[go: nahoru, domu]

blob: bb357c23e4bcb13a51719b8c77b923b67625188b [file] [log] [blame]
// Copyright 2021 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "printing/backend/print_backend_utils.h"
#include <string_view>
#include <vector>
#include "base/logging.h"
#include "base/strings/string_number_conversions.h"
#include "base/strings/string_split.h"
#include "base/strings/string_util.h"
#include "printing/buildflags/buildflags.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"
#if BUILDFLAG(USE_CUPS)
#include "printing/backend/cups_printer.h"
#endif // BUILDFLAG(USE_CUPS)
namespace printing {
namespace {
constexpr float kMmPerInch = 25.4f;
constexpr float kMicronsPerInch = kMmPerInch * kMicronsPerMm;
// Defines two prefixes of a special breed of media sizes not meant for
// users' eyes. CUPS incidentally returns these IPP values to us, but
// we have no use for them.
constexpr std::string_view kMediaCustomMinPrefix = "custom_min";
constexpr std::string_view kMediaCustomMaxPrefix = "custom_max";
bool IsValidMediaName(std::string_view& value,
std::vector<std::string_view>& pieces) {
// We expect at least a display string and a dimension string.
// Additionally, we drop the "custom_min*" and "custom_max*" special
// "sizes" (not for users' eyes).
return pieces.size() >= 2 &&
!base::StartsWith(value, kMediaCustomMinPrefix) &&
!base::StartsWith(value, kMediaCustomMaxPrefix);
}
std::vector<std::string_view> GetStringPiecesIfValid(std::string_view value) {
// <name>_<width>x<height>{in,mm}
// e.g. na_letter_8.5x11in, iso_a4_210x297mm
std::vector<std::string_view> pieces = base::SplitStringPiece(
value, "_", base::TRIM_WHITESPACE, base::SPLIT_WANT_NONEMPTY);
if (!IsValidMediaName(value, pieces)) {
return std::vector<std::string_view>();
}
return pieces;
}
gfx::Size DimensionsToMicrons(std::string_view value) {
Unit unit;
std::string_view dims;
size_t unit_position;
if ((unit_position = value.find("mm")) != base::StringPiece::npos) {
unit = Unit::kMillimeters;
dims = value.substr(0, unit_position);
} else if ((unit_position = value.find("in")) != base::StringPiece::npos) {
unit = Unit::kInches;
dims = value.substr(0, unit_position);
} else {
LOG(WARNING) << "Could not parse paper dimensions";
return {0, 0};
}
double width;
double height;
std::vector<std::string> pieces = base::SplitString(
dims, "x", base::TRIM_WHITESPACE, base::SPLIT_WANT_NONEMPTY);
if (pieces.size() != 2 || !base::StringToDouble(pieces[0], &width) ||
!base::StringToDouble(pieces[1], &height)) {
return {0, 0};
}
float scale;
switch (unit) {
case Unit::kMillimeters:
scale = kMicronsPerMm;
break;
case Unit::kInches:
scale = kMicronsPerInch;
break;
}
return gfx::ToFlooredSize(gfx::ScaleSize(gfx::SizeF(width, height), scale));
}
} // namespace
gfx::Size ParsePaperSize(std::string_view value) {
std::vector<std::string_view> pieces = GetStringPiecesIfValid(value);
if (pieces.empty()) {
return gfx::Size();
}
std::string_view dimensions = pieces.back();
return DimensionsToMicrons(dimensions);
}
#if BUILDFLAG(USE_CUPS)
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) 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 =
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);
}
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);
// 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);
*bottom_pwg = bottom_um / kMicronsPerPwgUnit;
*left_pwg = left_um / kMicronsPerPwgUnit;
*right_pwg = right_um / kMicronsPerPwgUnit;
*top_pwg = top_um / kMicronsPerPwgUnit;
}
#endif // BUILDFLAG(USE_CUPS)
} // namespace printing