Skip to content

Commit

Permalink
Select default paper size based on locale if default isn't set in PPD
Browse files Browse the repository at this point in the history
Currently, when the default page size of a printer cannot be parsed from
the PPD, the default falls back to the first page size on the list of
capabilities. Because such a page size tends to be the first
alphanumerically, it tends to be one that is not commonly printed on,
such as A2, A3, or 11x17. Using the locale information allows the parser
to fall back on either A4 or N.A. Letter, respecting the locale.

In doing so, alter the signature of ParsePpdCapabilities() to read the
locale, which is then passed to GetDefaultPaperSizeFromLocaleMicrons().

Change some instances of const to constexpr along the way.

Bug: 890904
Change-Id: I4ecd824008a7045086919630e491699d05bd78b1
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1937705
Commit-Queue: Daniel Hosseinian <dhoss@chromium.org>
Reviewed-by: Lei Zhang <thestig@chromium.org>
Cr-Commit-Position: refs/heads/master@{#725235}
  • Loading branch information
Daniel Hosseinian authored and Commit Bot committed Dec 16, 2019
1 parent fa4db16 commit d8f4bc7
Show file tree
Hide file tree
Showing 8 changed files with 226 additions and 30 deletions.
29 changes: 27 additions & 2 deletions printing/backend/cups_helper.cc
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
#include "base/values.h"
#include "printing/backend/print_backend.h"
#include "printing/backend/print_backend_consts.h"
#include "printing/printing_utils.h"
#include "printing/units.h"
#include "url/gurl.h"

Expand Down Expand Up @@ -426,6 +427,7 @@ http_t* HttpConnectionCUPS::http() {
}

bool ParsePpdCapabilities(base::StringPiece printer_name,
base::StringPiece locale,
base::StringPiece printer_capabilities,
PrinterSemanticCapsAndDefaults* printer_info) {
base::FilePath ppd_file_path;
Expand Down Expand Up @@ -474,11 +476,12 @@ bool ParsePpdCapabilities(base::StringPiece printer_name,
if (ppd->num_sizes > 0 && ppd->sizes) {
VLOG(1) << "Paper list size - " << ppd->num_sizes;
ppd_option_t* paper_option = ppdFindOption(ppd, kPageSize);
bool is_default_found = false;
for (int i = 0; i < ppd->num_sizes; ++i) {
gfx::Size paper_size_microns(
ConvertUnit(ppd->sizes[i].width, kPointsPerInch, kMicronsPerInch),
ConvertUnit(ppd->sizes[i].length, kPointsPerInch, kMicronsPerInch));
if (paper_size_microns.width() > 0 && paper_size_microns.height() > 0) {
if (!paper_size_microns.IsEmpty()) {
PrinterSemanticCapsAndDefaults::Paper paper;
paper.size_um = paper_size_microns;
paper.vendor_id = ppd->sizes[i].name;
Expand All @@ -492,11 +495,33 @@ bool ParsePpdCapabilities(base::StringPiece printer_name,
}
}
caps.papers.push_back(paper);
if (i == 0 || ppd->sizes[i].marked) {
if (ppd->sizes[i].marked) {
caps.default_paper = paper;
is_default_found = true;
}
}
}
if (!is_default_found) {
gfx::Size locale_paper_microns =
GetDefaultPaperSizeFromLocaleMicrons(locale);
for (const PrinterSemanticCapsAndDefaults::Paper& paper : caps.papers) {
// Set epsilon to 500 microns to allow tolerance of rounded paper sizes.
// While the above utility function returns paper sizes in microns, they
// are still rounded to the nearest millimeter (1000 microns).
constexpr int kSizeEpsilon = 500;
if (SizesEqualWithinEpsilon(paper.size_um, locale_paper_microns,
kSizeEpsilon)) {
caps.default_paper = paper;
is_default_found = true;
break;
}
}

// If no default was set in the PPD or if the locale default is not within
// the printer's capabilities, select the first on the list.
if (!is_default_found)
caps.default_paper = caps.papers[0];
}
}

ppdClose(ppd);
Expand Down
1 change: 1 addition & 0 deletions printing/backend/cups_helper.h
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ class PRINTING_EXPORT HttpConnectionCUPS {
// semantic options.
PRINTING_EXPORT bool ParsePpdCapabilities(
base::StringPiece printer_name,
base::StringPiece locale,
base::StringPiece printer_capabilities,
PrinterSemanticCapsAndDefaults* printer_info);

Expand Down
92 changes: 80 additions & 12 deletions printing/backend/cups_helper_unittest.cc
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,23 @@
// found in the LICENSE file.

#include "printing/backend/cups_helper.h"

#include "printing/backend/print_backend.h"
#include "printing/printing_utils.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"

namespace {

// Returns true if the papers have the same name, vendor ID, and size.
bool PapersEqual(const printing::PrinterSemanticCapsAndDefaults::Paper& lhs,
const printing::PrinterSemanticCapsAndDefaults::Paper& rhs) {
return lhs.display_name == rhs.display_name &&
lhs.vendor_id == rhs.vendor_id && lhs.size_um == rhs.size_um;
}

} // namespace

TEST(PrintBackendCupsHelperTest, TestPpdParsingNoColorDuplexShortEdge) {
const char kTestPpdData[] =
"*PPD-Adobe: \"4.3\"\n\n"
Expand All @@ -32,7 +45,7 @@ TEST(PrintBackendCupsHelperTest, TestPpdParsingNoColorDuplexShortEdge) {
"*CloseGroup: General\n";

printing::PrinterSemanticCapsAndDefaults caps;
EXPECT_TRUE(printing::ParsePpdCapabilities("test", kTestPpdData, &caps));
EXPECT_TRUE(printing::ParsePpdCapabilities("test", "", kTestPpdData, &caps));
EXPECT_TRUE(caps.collate_capable);
EXPECT_TRUE(caps.collate_default);
EXPECT_TRUE(caps.copies_capable);
Expand Down Expand Up @@ -61,7 +74,7 @@ TEST(PrintBackendCupsHelperTest, TestPpdParsingNoColorDuplexSimples) {
"*CloseGroup: General\n";

printing::PrinterSemanticCapsAndDefaults caps;
EXPECT_TRUE(printing::ParsePpdCapabilities("test", kTestPpdData, &caps));
EXPECT_TRUE(printing::ParsePpdCapabilities("test", "", kTestPpdData, &caps));
EXPECT_TRUE(caps.collate_capable);
EXPECT_TRUE(caps.collate_default);
EXPECT_TRUE(caps.copies_capable);
Expand Down Expand Up @@ -89,7 +102,7 @@ TEST(PrintBackendCupsHelperTest, TestPpdParsingNoColorNoDuplex) {
"*CloseGroup: General\n";

printing::PrinterSemanticCapsAndDefaults caps;
EXPECT_TRUE(printing::ParsePpdCapabilities("test", kTestPpdData, &caps));
EXPECT_TRUE(printing::ParsePpdCapabilities("test", "", kTestPpdData, &caps));
EXPECT_TRUE(caps.collate_capable);
EXPECT_TRUE(caps.collate_default);
EXPECT_TRUE(caps.copies_capable);
Expand Down Expand Up @@ -124,7 +137,7 @@ TEST(PrintBackendCupsHelperTest, TestPpdParsingColorTrueDuplexShortEdge) {
"*CloseGroup: General\n";

printing::PrinterSemanticCapsAndDefaults caps;
EXPECT_TRUE(printing::ParsePpdCapabilities("test", kTestPpdData, &caps));
EXPECT_TRUE(printing::ParsePpdCapabilities("test", "", kTestPpdData, &caps));
EXPECT_TRUE(caps.collate_capable);
EXPECT_TRUE(caps.collate_default);
EXPECT_TRUE(caps.copies_capable);
Expand Down Expand Up @@ -165,7 +178,7 @@ TEST(PrintBackendCupsHelperTest, TestPpdParsingColorFalseDuplexLongEdge) {
"*CloseGroup: General\n";

printing::PrinterSemanticCapsAndDefaults caps;
EXPECT_TRUE(printing::ParsePpdCapabilities("test", kTestPpdData, &caps));
EXPECT_TRUE(printing::ParsePpdCapabilities("test", "", kTestPpdData, &caps));
EXPECT_TRUE(caps.collate_capable);
EXPECT_TRUE(caps.collate_default);
EXPECT_TRUE(caps.copies_capable);
Expand All @@ -181,7 +194,7 @@ TEST(PrintBackendCupsHelperTest, TestPpdParsingPageSize) {
const char kTestPpdData[] =
"*PPD-Adobe: \"4.3\"\n\n"
"*OpenUI *PageSize: PickOne\n"
"*DefaultPageSize: Letter\n"
"*DefaultPageSize: Legal\n"
"*PageSize Letter/US Letter: \""
" <</DeferredMediaSelection true /PageSize [612 792] "
" /ImagingBBox null /MediaClass null >> setpagedevice\"\n"
Expand All @@ -190,13 +203,13 @@ TEST(PrintBackendCupsHelperTest, TestPpdParsingPageSize) {
" <</DeferredMediaSelection true /PageSize [612 1008] "
" /ImagingBBox null /MediaClass null >> setpagedevice\"\n"
"*End\n"
"*DefaultPaperDimension: Letter\n"
"*DefaultPaperDimension: Legal\n"
"*PaperDimension Letter/US Letter: \"612 792\"\n"
"*PaperDimension Legal/US Legal: \"612 1008\"\n\n"
"*CloseUI: *PageSize\n\n";

printing::PrinterSemanticCapsAndDefaults caps;
EXPECT_TRUE(printing::ParsePpdCapabilities("test", kTestPpdData, &caps));
EXPECT_TRUE(printing::ParsePpdCapabilities("test", "", kTestPpdData, &caps));
ASSERT_EQ(2UL, caps.papers.size());
EXPECT_EQ("Letter", caps.papers[0].vendor_id);
EXPECT_EQ("US Letter", caps.papers[0].display_name);
Expand All @@ -206,6 +219,57 @@ TEST(PrintBackendCupsHelperTest, TestPpdParsingPageSize) {
EXPECT_EQ("US Legal", caps.papers[1].display_name);
EXPECT_EQ(215900, caps.papers[1].size_um.width());
EXPECT_EQ(355600, caps.papers[1].size_um.height());
EXPECT_TRUE(PapersEqual(caps.papers[1], caps.default_paper));
}

TEST(PrintBackendCupsHelperTest, TestPpdParsingPageSizeNoDefaultSpecified) {
const char kTestPpdData[] =
R"(*PPD-Adobe: "4.3"
*OpenUI *PageSize: PickOne
*PageSize A3/ISO A3: "
<< /DeferredMediaSelection true /PageSize [842 1191]
/ImagingBBox null >> setpagedevice"
*End
*PageSize A4/ISO A4: "
<< /DeferredMediaSelection true /PageSize [595 842]
/ImagingBBox null >> setpagedevice"
*End
*PageSize Legal/US Legal: "
<< /DeferredMediaSelection true /PageSize [612 1008]
/ImagingBBox null >> setpagedevice"
*End
*PageSize Letter/US Letter: "
<< /DeferredMediaSelection true /PageSize [612 792]
/ImagingBBox null >> setpagedevice"
*End
*PaperDimension A3/ISO A3: "842 1191"
*PaperDimension A4/ISO A4: "595 842"
*PaperDimension Legal/US Legal: "612 1008"
*PaperDimension Letter/US Letter: "612 792"
*CloseUI: *PageSize)";

{
printing::PrinterSemanticCapsAndDefaults caps;
EXPECT_TRUE(
printing::ParsePpdCapabilities("test", "en-US", kTestPpdData, &caps));
ASSERT_EQ(4UL, caps.papers.size());
EXPECT_EQ("Letter", caps.papers[3].vendor_id);
EXPECT_EQ("US Letter", caps.papers[3].display_name);
EXPECT_EQ(215900, caps.papers[3].size_um.width());
EXPECT_EQ(279400, caps.papers[3].size_um.height());
EXPECT_TRUE(PapersEqual(caps.papers[3], caps.default_paper));
}
{
printing::PrinterSemanticCapsAndDefaults caps;
EXPECT_TRUE(
printing::ParsePpdCapabilities("test", "en-UK", kTestPpdData, &caps));
ASSERT_EQ(4UL, caps.papers.size());
EXPECT_EQ("A4", caps.papers[1].vendor_id);
EXPECT_EQ("ISO A4", caps.papers[1].display_name);
EXPECT_EQ(209903, caps.papers[1].size_um.width());
EXPECT_EQ(297039, caps.papers[1].size_um.height());
EXPECT_TRUE(PapersEqual(caps.papers[1], caps.default_paper));
}
}

TEST(PrintBackendCupsHelperTest, TestPpdParsingBrotherPrinters) {
Expand All @@ -221,7 +285,8 @@ TEST(PrintBackendCupsHelperTest, TestPpdParsingBrotherPrinters) {
"*CloseUI: *BRPrintQuality\n\n";

printing::PrinterSemanticCapsAndDefaults caps;
EXPECT_TRUE(printing::ParsePpdCapabilities("test", kTestPpdData, &caps));
EXPECT_TRUE(
printing::ParsePpdCapabilities("test", "", kTestPpdData, &caps));
EXPECT_TRUE(caps.color_changeable);
EXPECT_TRUE(caps.color_default);
EXPECT_EQ(printing::BROTHER_BRSCRIPT3_COLOR, caps.color_model);
Expand All @@ -239,7 +304,8 @@ TEST(PrintBackendCupsHelperTest, TestPpdParsingBrotherPrinters) {
"*CloseUI: *BRMonoColor\n\n";

printing::PrinterSemanticCapsAndDefaults caps;
EXPECT_TRUE(printing::ParsePpdCapabilities("test", kTestPpdData, &caps));
EXPECT_TRUE(
printing::ParsePpdCapabilities("test", "", kTestPpdData, &caps));
EXPECT_TRUE(caps.color_changeable);
EXPECT_TRUE(caps.color_default);
EXPECT_EQ(printing::BROTHER_CUPS_COLOR, caps.color_model);
Expand All @@ -257,7 +323,8 @@ TEST(PrintBackendCupsHelperTest, TestPpdParsingBrotherPrinters) {
"*CloseUI: *BRDuplex\n\n";

printing::PrinterSemanticCapsAndDefaults caps;
EXPECT_TRUE(printing::ParsePpdCapabilities("test", kTestPpdData, &caps));
EXPECT_TRUE(
printing::ParsePpdCapabilities("test", "", kTestPpdData, &caps));
EXPECT_THAT(caps.duplex_modes, testing::UnorderedElementsAre(
printing::SIMPLEX, printing::LONG_EDGE,
printing::SHORT_EDGE));
Expand All @@ -277,7 +344,8 @@ TEST(PrintBackendCupsHelperTest, TestPpdParsingSamsungPrinters) {
"*CloseUI: *ColorMode\n\n";

printing::PrinterSemanticCapsAndDefaults caps;
EXPECT_TRUE(printing::ParsePpdCapabilities("test", kTestPpdData, &caps));
EXPECT_TRUE(
printing::ParsePpdCapabilities("test", "", kTestPpdData, &caps));
EXPECT_TRUE(caps.color_changeable);
EXPECT_TRUE(caps.color_default);
EXPECT_EQ(printing::COLORMODE_COLOR, caps.color_model);
Expand Down
2 changes: 1 addition & 1 deletion printing/backend/print_backend_cups.cc
Original file line number Diff line number Diff line change
Expand Up @@ -158,7 +158,7 @@ bool PrintBackendCUPS::GetPrinterSemanticCapsAndDefaults(
if (!GetPrinterCapsAndDefaults(printer_name, &info))
return false;

return ParsePpdCapabilities(printer_name, info.printer_capabilities,
return ParsePpdCapabilities(printer_name, locale(), info.printer_capabilities,
printer_info);
}

Expand Down
40 changes: 38 additions & 2 deletions printing/printing_utils.cc
Original file line number Diff line number Diff line change
Expand Up @@ -4,21 +4,26 @@

#include "printing/printing_utils.h"

#include <stddef.h>
#include <unicode/ulocdata.h>

#include <algorithm>
#include <cmath>
#include <string>

#include "base/logging.h"
#include "base/strings/string_util.h"
#include "base/strings/utf_string_conversions.h"
#include "printing/units.h"
#include "third_party/icu/source/common/unicode/uchar.h"
#include "ui/gfx/geometry/size.h"
#include "ui/gfx/text_elider.h"

namespace printing {

namespace {

const size_t kMaxDocumentTitleLength = 80;
constexpr size_t kMaxDocumentTitleLength = 80;
constexpr gfx::Size kIsoA4Microns = gfx::Size(210000, 297000);

} // namespace

Expand Down Expand Up @@ -63,4 +68,35 @@ base::string16 FormatDocumentTitleWithOwner(const base::string16& owner,
kMaxDocumentTitleLength);
}

gfx::Size GetDefaultPaperSizeFromLocaleMicrons(base::StringPiece locale) {
if (locale.empty())
return kIsoA4Microns;

int32_t width = 0;
int32_t height = 0;
UErrorCode error = U_ZERO_ERROR;
ulocdata_getPaperSize(locale.as_string().c_str(), &height, &width, &error);
if (error > U_ZERO_ERROR) {
// If the call failed, assume Letter paper size.
LOG(WARNING) << "ulocdata_getPaperSize failed, using ISO A4 Paper, error: "
<< error;

return kIsoA4Microns;
}
// Convert millis to microns
return gfx::Size(width * 1000, height * 1000);
}

bool SizesEqualWithinEpsilon(const gfx::Size& lhs,
const gfx::Size& rhs,
int epsilon) {
DCHECK_GE(epsilon, 0);

if (lhs.IsEmpty() && rhs.IsEmpty())
return true;

return std::abs(lhs.width() - rhs.width()) <= epsilon &&
std::abs(lhs.height() - rhs.height()) <= epsilon;
}

} // namespace printing
16 changes: 16 additions & 0 deletions printing/printing_utils.h
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,13 @@
#include <stddef.h>

#include "base/strings/string16.h"
#include "base/strings/string_piece.h"
#include "printing/printing_export.h"

namespace gfx {
class Size;
}

namespace printing {

// Simplify title to resolve issue with some drivers.
Expand All @@ -29,6 +34,17 @@ PRINTING_EXPORT base::string16 FormatDocumentTitleWithOwnerAndLength(
const base::string16& title,
size_t length);

// Returns the paper size (microns) most common in the locale to the nearest
// millimeter. Defaults to ISO A4 for an empty or invalid locale.
PRINTING_EXPORT gfx::Size GetDefaultPaperSizeFromLocaleMicrons(
base::StringPiece locale);

// Returns true if both dimensions of the sizes have a delta less than or equal
// to the epsilon value.
PRINTING_EXPORT bool SizesEqualWithinEpsilon(const gfx::Size& lhs,
const gfx::Size& rhs,
int epsilon);

} // namespace printing

#endif // PRINTING_PRINTING_UTILS_H_
Loading

0 comments on commit d8f4bc7

Please sign in to comment.