0

extensions: printing: verify margins values 3/*

chrome.printing must verify that margin values are among supported
values stored in capabilities.

Design doc:
https://docs.google.com/document/d/1EgbaHpFDl8sEMYDaeL0oAta3lSa_x4Nv9KmSfScyKRk

Bug: 316999874, 308709702
Change-Id: Ia1f567fbe2be0777ee6340009e504a04626b4d68
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/6383043
Commit-Queue: Maksim Sisov <msisov@igalia.com>
Reviewed-by: Nathan Muggli <nmuggli@google.com>
Reviewed-by: Lei Zhang <thestig@chromium.org>
Cr-Commit-Position: refs/heads/main@{#1442599}
This commit is contained in:
Maksim Sisov
2025-04-04 00:09:15 -07:00
committed by Chromium LUCI CQ
parent d2ea0e1d80
commit 9d4503e7a4
4 changed files with 148 additions and 0 deletions

@ -388,6 +388,40 @@ bool CheckSettingsAndCapabilitiesCompatibility(
<< "' is not compatible with printer capabilities";
return false;
}
if (settings.margin_type() !=
printing::mojom::MarginType::kDefaultMargins) {
const auto& requested_margins_um =
settings.requested_custom_margins_in_microns();
bool result = std::ranges::any_of(
capabilities.papers,
[requested_margins_um,
needs_borderless_variant = settings.borderless()](
const printing::PrinterSemanticCapsAndDefaults::Paper& paper) {
// Borderless variant doesn't have margins stored separately. Thus,
// check if there is a paper with borderless variant.
if (needs_borderless_variant) {
return paper.has_borderless_variant() &&
requested_margins_um.IsEmpty();
}
if (!paper.supported_margins_um().has_value()) {
return false;
}
const auto& supported_margins =
paper.supported_margins_um().value();
return requested_margins_um ==
printing::PageMargins(/*header=*/0, /*footer=*/0,
supported_margins.left_margin_um,
supported_margins.right_margin_um,
supported_margins.top_margin_um,
supported_margins.bottom_margin_um);
});
if (!result) {
LOG(ERROR) << "Margin values " << requested_margins_um.ToString()
<< " are not supported by the printer";
return false;
}
}
}
const printing::PrintSettings::RequestedMedia& requested_media =

@ -752,4 +752,102 @@ TEST(PrintingApiUtilsTest,
}
}
TEST(PrintingApiUtilsTest, CheckSettingsAndCapabilitiesCompatibility_Margins) {
std::unique_ptr<printing::PrintSettings> settings = ConstructPrintSettings();
printing::PrinterSemanticCapsAndDefaults capabilities =
ConstructPrinterCapabilities();
const printing::PageMargins kMargins = {
/*header=*/0, /*footer=*/0,
/*left=*/1500, /*right=*/500,
/*top=*/3530, /*bottom=*/5525};
settings->SetCustomMargins(kMargins);
settings->set_margin_type(printing::mojom::MarginType::kCustomMargins);
// There must be no supported margins for the check to pass.
for (const auto& paper : capabilities.papers) {
ASSERT_FALSE(paper.supported_margins_um().has_value());
}
{
// Test with feature disabled - despite margins not being supported and
// provided, the check should pass as the feature is disabled.
base::test::ScopedFeatureList feature_list;
feature_list.InitAndDisableFeature(
printing::features::kApiPrintingMarginsAndScale);
EXPECT_TRUE(
CheckSettingsAndCapabilitiesCompatibility(*settings, capabilities));
}
// Re-enable feature for further tests.
base::test::ScopedFeatureList feature_list(
printing::features::kApiPrintingMarginsAndScale);
// Add a paper with supported margins.
const printing::PaperMargins kSupportedMargins(1500, 500, 3241, 3451);
capabilities.papers.emplace_back(
/*display_name=*/"", /*vendor_id=*/"",
/*size_um=*/gfx::Size(kMediaSizeWidth, kMediaSizeHeight),
/*printable_area_um=*/gfx::Rect(kMediaSizeWidth, kMediaSizeHeight),
/*max_height_um=*/0, /*has_borderless_variant=*/false,
/*supported_margins_um=*/kSupportedMargins);
// Default margins should be supported.
{
settings->SetCustomMargins(printing::PageMargins());
settings->set_margin_type(printing::mojom::MarginType::kDefaultMargins);
EXPECT_TRUE(
CheckSettingsAndCapabilitiesCompatibility(*settings, capabilities));
}
// Set supported margins and settings to different values. The check should
// fail.
{
settings->SetCustomMargins(kMargins);
settings->set_margin_type(printing::mojom::MarginType::kCustomMargins);
EXPECT_FALSE(
CheckSettingsAndCapabilitiesCompatibility(*settings, capabilities));
}
// Now, update the settings to have supported margins. The check should pass.
{
settings->SetCustomMargins(printing::PageMargins(
/*header=*/0, /*footer=*/0,
/*left=*/kSupportedMargins.left_margin_um,
/*right=*/kSupportedMargins.right_margin_um,
/*top=*/kSupportedMargins.top_margin_um,
/*bottom=*/kSupportedMargins.bottom_margin_um));
EXPECT_TRUE(
CheckSettingsAndCapabilitiesCompatibility(*settings, capabilities));
}
// Test borderless variant.
{
settings->SetCustomMargins(printing::PageMargins());
settings->set_margin_type(printing::mojom::MarginType::kNoMargins);
settings->set_borderless(true);
EXPECT_FALSE(
CheckSettingsAndCapabilitiesCompatibility(*settings, capabilities));
capabilities.papers.emplace_back(
printing::PrinterSemanticCapsAndDefaults::Paper(
/*display_name=*/"", /*vendor_id=*/"",
/*size_um=*/gfx::Size(kMediaSizeWidth, kMediaSizeHeight),
/*printable_area_um=*/gfx::Rect(kMediaSizeWidth, kMediaSizeHeight),
/*max_height_um=*/0, /*has_borderless_variant=*/true,
/*supported_margins_um=*/kSupportedMargins));
EXPECT_TRUE(
CheckSettingsAndCapabilitiesCompatibility(*settings, capabilities));
}
// Invalid case: try to set borderless in settings, but still provide margin
// values. This must be invalid.
{
settings->set_borderless(true);
settings->SetCustomMargins(kMargins);
settings->set_margin_type(printing::mojom::MarginType::kCustomMargins);
EXPECT_FALSE(
CheckSettingsAndCapabilitiesCompatibility(*settings, capabilities));
}
}
} // namespace extensions

@ -8,6 +8,7 @@
#include <tuple>
#include "base/check_op.h"
#include "base/strings/stringprintf.h"
namespace printing {
@ -65,6 +66,17 @@ void PageMargins::Clear() {
bottom = 0;
}
std::string PageMargins::ToString() const {
return base::StringPrintf(
"header=%d, footer=%d, left=%d, right=%d, top=%d, bottom=%d)", header,
footer, left, right, top, bottom);
}
bool PageMargins::IsEmpty() const {
return header == 0 && footer == 0 && left == 0 && right == 0 && top == 0 &&
bottom == 0;
}
PageSetup::PageSetup() {
Clear();
}

@ -20,6 +20,10 @@ class COMPONENT_EXPORT(PRINTING_SETTINGS) PageMargins {
void Clear();
std::string ToString() const;
bool IsEmpty() const;
// Vertical space for the overlay from the top of the sheet.
int header;
// Vertical space for the overlay from the bottom of the sheet.