diff --git a/chrome/browser/ash/crosapi/local_printer_ash_unittest.cc b/chrome/browser/ash/crosapi/local_printer_ash_unittest.cc index 7807d0b59de9b..1e23fb279810b 100644 --- a/chrome/browser/ash/crosapi/local_printer_ash_unittest.cc +++ b/chrome/browser/ash/crosapi/local_printer_ash_unittest.cc @@ -56,6 +56,7 @@ #include "testing/gmock/include/gmock/gmock.h" #include "testing/gtest/include/gtest/gtest.h" #include "third_party/abseil-cpp/absl/types/optional.h" +#include "ui/gfx/geometry/rect.h" #include "ui/gfx/geometry/size.h" #include "url/gurl.h" @@ -228,7 +229,7 @@ class TestLocalPrinterAshWithPrinterConfigurer : public TestLocalPrinterAsh { class LocalPrinterAshTestBase : public testing::Test { public: const std::vector<PrinterSemanticCapsAndDefaults::Paper> kPapers = { - {"bar", "vendor", {600, 600}}}; + {"bar", "vendor", gfx::Size(600, 600), gfx::Rect(0, 0, 600, 600)}}; LocalPrinterAshTestBase() = default; LocalPrinterAshTestBase(const LocalPrinterAshTestBase&) = delete; @@ -1035,7 +1036,7 @@ TEST(LocalPrinterAsh, StatusToMojom) { class LocalPrinterAshWithOAuth2Test : public testing::Test { public: const std::vector<PrinterSemanticCapsAndDefaults::Paper> kPapers = { - {"bar", "vendor", {600, 600}}}; + {"bar", "vendor", gfx::Size(600, 600), gfx::Rect(0, 0, 600, 600)}}; LocalPrinterAshWithOAuth2Test() = default; LocalPrinterAshWithOAuth2Test(const LocalPrinterAshWithOAuth2Test&) = delete; diff --git a/chrome/browser/ui/webui/print_preview/local_printer_handler_default_unittest.cc b/chrome/browser/ui/webui/print_preview/local_printer_handler_default_unittest.cc index 425fc8fae49bc..a0fb70b3bda53 100644 --- a/chrome/browser/ui/webui/print_preview/local_printer_handler_default_unittest.cc +++ b/chrome/browser/ui/webui/print_preview/local_printer_handler_default_unittest.cc @@ -24,6 +24,8 @@ #include "printing/print_job_constants.h" #include "printing/printing_features.h" #include "testing/gtest/include/gtest/gtest.h" +#include "ui/gfx/geometry/rect.h" +#include "ui/gfx/geometry/size.h" #if BUILDFLAG(ENABLE_OOP_PRINTING) #include "chrome/browser/printing/print_backend_service_manager.h" @@ -294,8 +296,8 @@ class LocalPrinterHandlerDefaultTestBase : public testing::Test { bool is_default, bool requires_elevated_permissions) { auto caps = std::make_unique<PrinterSemanticCapsAndDefaults>(); - caps->papers.emplace_back( - PrinterSemanticCapsAndDefaults::Paper{"bar", "vendor", {600, 600}}); + caps->papers.emplace_back(PrinterSemanticCapsAndDefaults::Paper{ + "bar", "vendor", gfx::Size(600, 600), gfx::Rect(0, 0, 600, 600)}); auto basic_info = std::make_unique<PrinterBasicInfo>( id, display_name, description, /*printer_status=*/0, is_default, PrinterBasicInfoOptions{}); diff --git a/chrome/common/printing/print_media_l10n_unittest.cc b/chrome/common/printing/print_media_l10n_unittest.cc index c04bd92f81865..870264c2fcd49 100644 --- a/chrome/common/printing/print_media_l10n_unittest.cc +++ b/chrome/common/printing/print_media_l10n_unittest.cc @@ -9,7 +9,10 @@ #include <vector> #include "chrome/common/printing/print_media_l10n.h" +#include "printing/backend/print_backend.h" #include "testing/gtest/include/gtest/gtest.h" +#include "ui/gfx/geometry/rect.h" +#include "ui/gfx/geometry/size.h" namespace printing { @@ -137,14 +140,18 @@ TEST(PrintMediaL10N, SortGroupsOrdered) { // Verifies that inch paper sizes are sorted by width, height, name. TEST(PrintMediaL10N, SortInchSizes) { - PaperWithSizeInfo p1 = {MediaSizeInfo{u"1x3", MediaSizeGroup::kSizeIn}, - Paper{"1x3", "in", gfx::Size(1, 3)}}; - PaperWithSizeInfo p2 = {MediaSizeInfo{u"2x1", MediaSizeGroup::kSizeIn}, - Paper{"2x1", "in", gfx::Size(2, 1)}}; - PaperWithSizeInfo p3 = {MediaSizeInfo{u"2x2", MediaSizeGroup::kSizeIn}, - Paper{"2x2", "in", gfx::Size(2, 2)}}; - PaperWithSizeInfo p4 = {MediaSizeInfo{u"2x2 B", MediaSizeGroup::kSizeIn}, - Paper{"2x2 B", "in", gfx::Size(2, 2)}}; + PaperWithSizeInfo p1 = { + 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}, + Paper{"2x1", "in", gfx::Size(2, 1), gfx::Rect(0, 0, 2, 1)}}; + PaperWithSizeInfo p3 = { + 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}, + 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}; @@ -156,14 +163,18 @@ TEST(PrintMediaL10N, SortInchSizes) { // Verifies that mm paper sizes are sorted by width, height, name. TEST(PrintMediaL10N, SortMmSizes) { - PaperWithSizeInfo p1 = {MediaSizeInfo{u"1x3", MediaSizeGroup::kSizeMm}, - Paper{"1x3", "mm", gfx::Size(1, 3)}}; - PaperWithSizeInfo p2 = {MediaSizeInfo{u"2x1", MediaSizeGroup::kSizeMm}, - Paper{"2x1", "mm", gfx::Size(2, 1)}}; - PaperWithSizeInfo p3 = {MediaSizeInfo{u"2x2", MediaSizeGroup::kSizeMm}, - Paper{"2x2", "mm", gfx::Size(2, 2)}}; - PaperWithSizeInfo p4 = {MediaSizeInfo{u"2x2 B", MediaSizeGroup::kSizeMm}, - Paper{"2x2 B", "mm", gfx::Size(2, 2)}}; + PaperWithSizeInfo p1 = { + 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}, + Paper{"2x1", "mm", gfx::Size(2, 1), gfx::Rect(0, 0, 2, 1)}}; + PaperWithSizeInfo p3 = { + 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}, + 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}; @@ -175,14 +186,18 @@ TEST(PrintMediaL10N, SortMmSizes) { // Verifies that named paper sizes are sorted by name, width, height. TEST(PrintMediaL10N, SortNamedSizes) { - PaperWithSizeInfo p1 = {MediaSizeInfo{u"AAA", MediaSizeGroup::kSizeNamed}, - Paper{"AAA", "name", gfx::Size(50, 50)}}; - PaperWithSizeInfo p2 = {MediaSizeInfo{u"BBB", MediaSizeGroup::kSizeNamed}, - Paper{"BBB", "name1", gfx::Size(1, 3)}}; - PaperWithSizeInfo p3 = {MediaSizeInfo{u"BBB", MediaSizeGroup::kSizeNamed}, - Paper{"BBB", "name2", gfx::Size(2, 2)}}; - PaperWithSizeInfo p4 = {MediaSizeInfo{u"BBB", MediaSizeGroup::kSizeNamed}, - Paper{"BBB", "name3", gfx::Size(2, 3)}}; + PaperWithSizeInfo p1 = { + 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}, + Paper{"BBB", "name1", gfx::Size(1, 3), gfx::Rect(0, 0, 1, 3)}}; + PaperWithSizeInfo p3 = { + 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}, + Paper{"BBB", "name3", gfx::Size(2, 3), gfx::Rect(0, 0, 2, 3)}}; std::vector<PaperWithSizeInfo> papers = {p4, p1, p2, p3}; std::vector<PaperWithSizeInfo> expected = {p1, p2, p3, p4}; diff --git a/printing/backend/mojom/print_backend.mojom b/printing/backend/mojom/print_backend.mojom index f9c3d91d4e121..bed5f843e38bb 100644 --- a/printing/backend/mojom/print_backend.mojom +++ b/printing/backend/mojom/print_backend.mojom @@ -22,11 +22,13 @@ struct PrinterBasicInfo { // Paper used by printer semantic capabilities and defaults. // Corresponds to `printing::PrinterSemanticCapsAndDefaults::Paper` in // printing/backend/print_backend.h. +// For backwards compatibility, `printable_area_um` must be optional. [Stable] struct Paper { string display_name; string vendor_id; gfx.mojom.Size size_um; + [MinVersion=1] gfx.mojom.Rect? printable_area_um; }; // An advanced capability value for ChromeOS printing. diff --git a/printing/backend/mojom/print_backend_mojom_traits.cc b/printing/backend/mojom/print_backend_mojom_traits.cc index 6e054e03002df..cb24a5bba1af4 100644 --- a/printing/backend/mojom/print_backend_mojom_traits.cc +++ b/printing/backend/mojom/print_backend_mojom_traits.cc @@ -112,8 +112,30 @@ bool StructTraits<printing::mojom::PaperDataView, printing::PrinterSemanticCapsAndDefaults::Paper>:: Read(printing::mojom::PaperDataView data, printing::PrinterSemanticCapsAndDefaults::Paper* out) { - return data.ReadDisplayName(&out->display_name) && - data.ReadVendorId(&out->vendor_id) && data.ReadSizeUm(&out->size_um); + absl::optional<gfx::Rect> printable_area_um; + if (!data.ReadDisplayName(&out->display_name) || + !data.ReadVendorId(&out->vendor_id) || !data.ReadSizeUm(&out->size_um) || + !data.ReadPrintableAreaUm(&printable_area_um)) { + return false; + } + + // For backwards compatibility, allow printable area to be missing. Set the + // default printable area to be the page size. + out->printable_area_um = printable_area_um.value_or(gfx::Rect(out->size_um)); + + // Allow empty Papers, since PrinterSemanticCapsAndDefaults can have empty + // default Papers. + if (out->display_name.empty() && out->vendor_id.empty() && + out->size_um.IsEmpty() && out->printable_area_um.IsEmpty()) { + return true; + } + + // Invalid if the printable area is empty, has negative values or has a larger + // width or height than the size of the Paper. + return !out->printable_area_um.IsEmpty() && out->printable_area_um.x() >= 0 && + out->printable_area_um.y() >= 0 && + out->printable_area_um.width() <= out->size_um.width() && + out->printable_area_um.height() <= out->size_um.height(); } #if BUILDFLAG(IS_CHROMEOS) diff --git a/printing/backend/mojom/print_backend_mojom_traits.h b/printing/backend/mojom/print_backend_mojom_traits.h index 5e2aba638c59c..f562a64ebfc3b 100644 --- a/printing/backend/mojom/print_backend_mojom_traits.h +++ b/printing/backend/mojom/print_backend_mojom_traits.h @@ -12,6 +12,7 @@ #include "printing/backend/mojom/print_backend.mojom-shared.h" #include "printing/backend/print_backend.h" #include "printing/mojom/print.mojom.h" +#include "ui/gfx/geometry/rect.h" #include "ui/gfx/geometry/size.h" namespace mojo { @@ -59,6 +60,10 @@ struct StructTraits<printing::mojom::PaperDataView, const printing::PrinterSemanticCapsAndDefaults::Paper& p) { return p.size_um; } + static const gfx::Rect& printable_area_um( + const printing::PrinterSemanticCapsAndDefaults::Paper& p) { + return p.printable_area_um; + } static bool Read(printing::mojom::PaperDataView data, printing::PrinterSemanticCapsAndDefaults::Paper* out); diff --git a/printing/backend/mojom/print_backend_mojom_traits_unittest.cc b/printing/backend/mojom/print_backend_mojom_traits_unittest.cc index a2ad736371ce5..7451fb09185bd 100644 --- a/printing/backend/mojom/print_backend_mojom_traits_unittest.cc +++ b/printing/backend/mojom/print_backend_mojom_traits_unittest.cc @@ -88,6 +88,52 @@ TEST(PrintBackendMojomTraitsTest, TestSerializeAndDeserializePaper) { } } +TEST(PrintBackendMojomTraitsTest, TestPaperEmpty) { + // Empty Papers should be valid. + PrinterSemanticCapsAndDefaults::Paper input; + PrinterSemanticCapsAndDefaults::Paper output; + + EXPECT_TRUE(mojo::test::SerializeAndDeserialize<mojom::Paper>(input, output)); + EXPECT_EQ(input, output); +} + +TEST(PrintBackendMojomTraitsTest, TestPaperEmptyPrintableArea) { + // The printable area is empty, but the other fields are not, so it should be + // invalid. + PrinterSemanticCapsAndDefaults::Paper input{ + /*display_name=*/"display_name", /*vendor_id=*/"vendor_id", + /*size_um=*/gfx::Size(4000, 7000), + /*printable_area_um=*/gfx::Rect(0, 100, 0, 0)}; + PrinterSemanticCapsAndDefaults::Paper output; + + EXPECT_FALSE( + mojo::test::SerializeAndDeserialize<mojom::Paper>(input, output)); +} + +TEST(PrintBackendMojomTraitsTest, TestPaperPrintableAreaLargerThanSize) { + // The printable area is larger than the size, so it should be invalid. + PrinterSemanticCapsAndDefaults::Paper input{ + /*display_name=*/"display_name", /*vendor_id=*/"vendor_id", + /*size_um=*/gfx::Size(4000, 7000), + /*printable_area_um=*/gfx::Rect(0, 100, 4100, 7200)}; + PrinterSemanticCapsAndDefaults::Paper output; + + EXPECT_FALSE( + mojo::test::SerializeAndDeserialize<mojom::Paper>(input, output)); +} + +TEST(PrintBackendMojomTraitsTest, TestPaperNegativePrintableArea) { + // The printable area has negative x and y values, so it should be invalid. + PrinterSemanticCapsAndDefaults::Paper input{ + /*display_name=*/"display_name", /*vendor_id=*/"vendor_id", + /*size_um=*/gfx::Size(4000, 7000), + /*printable_area_um=*/gfx::Rect(-10, -10, 2800, 6000)}; + PrinterSemanticCapsAndDefaults::Paper output; + + EXPECT_FALSE( + mojo::test::SerializeAndDeserialize<mojom::Paper>(input, output)); +} + #if BUILDFLAG(IS_CHROMEOS) TEST(PrintBackendMojomTraitsTest, TestSerializeAndDeserializeAdvancedCapability) { diff --git a/printing/backend/print_backend.cc b/printing/backend/print_backend.cc index f8ac14d71faa8..59b1849eaaffa 100644 --- a/printing/backend/print_backend.cc +++ b/printing/backend/print_backend.cc @@ -157,7 +157,8 @@ XpsCapabilities::~XpsCapabilities() = default; bool PrinterSemanticCapsAndDefaults::Paper::operator==( const PrinterSemanticCapsAndDefaults::Paper& other) const { return display_name == other.display_name && vendor_id == other.vendor_id && - size_um == other.size_um; + size_um == other.size_um && + printable_area_um == other.printable_area_um; } PrinterSemanticCapsAndDefaults::PrinterSemanticCapsAndDefaults() = default; diff --git a/printing/backend/print_backend.h b/printing/backend/print_backend.h index de71d366af21d..888771dd1e143 100644 --- a/printing/backend/print_backend.h +++ b/printing/backend/print_backend.h @@ -18,6 +18,7 @@ #include "build/build_config.h" #include "printing/mojom/print.mojom.h" #include "third_party/abseil-cpp/absl/types/optional.h" +#include "ui/gfx/geometry/rect.h" #include "ui/gfx/geometry/size.h" #if BUILDFLAG(IS_WIN) @@ -192,6 +193,9 @@ struct COMPONENT_EXPORT(PRINT_BACKEND) PrinterSemanticCapsAndDefaults { std::string vendor_id; gfx::Size size_um; + // Origin (x,y) is at the bottom-left. + gfx::Rect printable_area_um; + bool operator==(const Paper& other) const; }; using Papers = std::vector<Paper>; diff --git a/printing/backend/print_backend_test_constants.h b/printing/backend/print_backend_test_constants.h index 221558015082b..fd4fd608b6542 100644 --- a/printing/backend/print_backend_test_constants.h +++ b/printing/backend/print_backend_test_constants.h @@ -40,16 +40,20 @@ struct OptionalSampleCapabilities { inline const PrinterSemanticCapsAndDefaults::Paper kPaperA3{ /*display_name=*/"A3", /*vendor_id=*/"67", - /*size_um=*/gfx::Size(7016, 9921)}; + /*size_um=*/gfx::Size(7016, 9921), + /*printable_area_um=*/gfx::Rect(0, 0, 7016, 9921)}; inline const PrinterSemanticCapsAndDefaults::Paper kPaperA4{ /*display_name=*/"A4", /*vendor_id=*/"12", - /*size_um=*/gfx::Size(4961, 7016)}; + /*size_um=*/gfx::Size(4961, 7016), + /*printable_area_um=*/gfx::Rect(100, 200, 500, 800)}; inline const PrinterSemanticCapsAndDefaults::Paper kPaperLetter{ /*display_name=*/"Letter", /*vendor_id=*/"45", - /*size_um=*/gfx::Size(5100, 6600)}; + /*size_um=*/gfx::Size(5100, 6600), + /*printable_area_um=*/gfx::Rect(0, 0, 5100, 6600)}; inline const PrinterSemanticCapsAndDefaults::Paper kPaperLedger{ /*display_name=*/"Ledger", /*vendor_id=*/"89", - /*size_um=*/gfx::Size(6600, 10200)}; + /*size_um=*/gfx::Size(6600, 10200), + /*printable_area_um=*/gfx::Rect(0, 0, 6600, 10200)}; #if BUILDFLAG(IS_CHROMEOS) inline const AdvancedCapability kAdvancedCapability1( diff --git a/printing/backend/print_backend_utils.cc b/printing/backend/print_backend_utils.cc index 4032ea266cc01..e1590d2aa9f1e 100644 --- a/printing/backend/print_backend_utils.cc +++ b/printing/backend/print_backend_utils.cc @@ -11,6 +11,7 @@ #include "base/strings/string_piece.h" #include "base/strings/string_split.h" #include "printing/units.h" +#include "ui/gfx/geometry/rect.h" #include "ui/gfx/geometry/size.h" #include "ui/gfx/geometry/size_conversions.h" #include "ui/gfx/geometry/size_f.h" @@ -109,6 +110,7 @@ PrinterSemanticCapsAndDefaults::Paper ParsePaper(base::StringPiece value) { PrinterSemanticCapsAndDefaults::Paper paper; paper.vendor_id = std::string(value); paper.size_um = DimensionsToMicrons(dimensions); + paper.printable_area_um = gfx::Rect(paper.size_um); // Omits the final token describing the media dimensions. pieces.pop_back(); paper.display_name = base::JoinString(pieces, " ");