1 // Copyright 2011 The Chromium Authors
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "printing/page_setup.h"
9 #include "base/check_op.h"
15 // Checks whether `printable_area` can be used to form a valid symmetrical
16 // printable area, so that margin_left equals margin_right, and margin_top
17 // equals margin_bottom. For example if
18 // printable_area.x() * 2 >= page_size.width(), then the
19 // content_width = page_size.width() - 2 * printable_area.x() would be zero or
20 // negative, which is invalid.
21 // `page_size` is the physical page size that includes margins.
22 bool IsValidPrintableArea(const gfx::Size& page_size,
23 const gfx::Rect& printable_area) {
24 return !printable_area.IsEmpty() && printable_area.x() >= 0 &&
25 printable_area.y() >= 0 &&
26 printable_area.right() <= page_size.width() &&
27 printable_area.bottom() <= page_size.height() &&
28 printable_area.x() * 2 < page_size.width() &&
29 printable_area.y() * 2 < page_size.height() &&
30 printable_area.right() * 2 > page_size.width() &&
31 printable_area.bottom() * 2 > page_size.height();
36 PageMargins::PageMargins()
37 : header(0), footer(0), left(0), right(0), top(0), bottom(0) {}
39 PageMargins::PageMargins(int header,
52 void PageMargins::Clear() {
61 bool PageMargins::Equals(const PageMargins& rhs) const {
62 return header == rhs.header && footer == rhs.footer && left == rhs.left &&
63 top == rhs.top && right == rhs.right && bottom == rhs.bottom;
66 PageSetup::PageSetup() {
70 PageSetup::PageSetup(const gfx::Size& physical_size,
71 const gfx::Rect& printable_area,
72 const PageMargins& requested_margins,
75 : requested_margins_(requested_margins), forced_margins_(forced_margins) {
76 Init(physical_size, printable_area, text_height);
79 PageSetup::PageSetup(const PageSetup& other) = default;
81 PageSetup::~PageSetup() = default;
84 gfx::Rect PageSetup::GetSymmetricalPrintableArea(
85 const gfx::Size& page_size,
86 const gfx::Rect& printable_area) {
87 if (!IsValidPrintableArea(page_size, printable_area))
90 int left_right_margin =
91 std::max(printable_area.x(), page_size.width() - printable_area.right());
92 int top_bottom_margin = std::max(
93 printable_area.y(), page_size.height() - printable_area.bottom());
94 int width = page_size.width() - 2 * left_right_margin;
95 int height = page_size.height() - 2 * top_bottom_margin;
97 gfx::Rect symmetrical_printable_area = gfx::Rect(page_size);
98 symmetrical_printable_area.ClampToCenteredSize(gfx::Size(width, height));
100 return symmetrical_printable_area;
103 void PageSetup::Clear() {
104 physical_size_.SetSize(0, 0);
105 printable_area_.SetRect(0, 0, 0, 0);
106 overlay_area_.SetRect(0, 0, 0, 0);
107 content_area_.SetRect(0, 0, 0, 0);
108 effective_margins_.Clear();
110 forced_margins_ = false;
113 bool PageSetup::Equals(const PageSetup& rhs) const {
114 return physical_size_ == rhs.physical_size_ &&
115 printable_area_ == rhs.printable_area_ &&
116 overlay_area_ == rhs.overlay_area_ &&
117 content_area_ == rhs.content_area_ &&
118 effective_margins_.Equals(rhs.effective_margins_) &&
119 requested_margins_.Equals(rhs.requested_margins_) &&
120 text_height_ == rhs.text_height_;
123 void PageSetup::Init(const gfx::Size& physical_size,
124 const gfx::Rect& printable_area,
126 DCHECK_LE(printable_area.right(), physical_size.width());
127 // I've seen this assert triggers on Canon GP160PF PCL 5e and HP LaserJet 5.
128 // Since we don't know the dpi here, just disable the check.
129 // DCHECK_LE(printable_area.bottom(), physical_size.height());
130 DCHECK_GE(printable_area.x(), 0);
131 DCHECK_GE(printable_area.y(), 0);
132 DCHECK_GE(text_height, 0);
133 physical_size_ = physical_size;
134 printable_area_ = printable_area;
135 text_height_ = text_height;
137 SetRequestedMarginsAndCalculateSizes(requested_margins_);
140 void PageSetup::SetRequestedMargins(const PageMargins& requested_margins) {
141 forced_margins_ = false;
142 SetRequestedMarginsAndCalculateSizes(requested_margins);
145 void PageSetup::ForceRequestedMargins(const PageMargins& requested_margins) {
146 forced_margins_ = true;
147 SetRequestedMarginsAndCalculateSizes(requested_margins);
150 void PageSetup::FlipOrientation() {
151 if (physical_size_.width() && physical_size_.height()) {
152 gfx::Size new_size(physical_size_.height(), physical_size_.width());
153 int new_y = physical_size_.width() -
154 (printable_area_.width() + printable_area_.x());
155 gfx::Rect new_printable_area(printable_area_.y(), new_y,
156 printable_area_.height(),
157 printable_area_.width());
158 Init(new_size, new_printable_area, text_height_);
162 void PageSetup::SetRequestedMarginsAndCalculateSizes(
163 const PageMargins& requested_margins) {
164 requested_margins_ = requested_margins;
165 if (physical_size_.width() && physical_size_.height()) {
167 CalculateSizesWithinRect(gfx::Rect(physical_size_), 0);
169 CalculateSizesWithinRect(printable_area_, text_height_);
173 void PageSetup::CalculateSizesWithinRect(const gfx::Rect& bounds,
175 // Calculate the effective margins. The tricky part.
176 effective_margins_.header = std::max(requested_margins_.header, bounds.y());
177 effective_margins_.footer = std::max(
178 requested_margins_.footer, physical_size_.height() - bounds.bottom());
179 effective_margins_.left = std::max(requested_margins_.left, bounds.x());
180 effective_margins_.top = std::max({requested_margins_.top, bounds.y(),
181 effective_margins_.header + text_height});
182 effective_margins_.right = std::max(requested_margins_.right,
183 physical_size_.width() - bounds.right());
184 effective_margins_.bottom = std::max(
185 {requested_margins_.bottom, physical_size_.height() - bounds.bottom(),
186 effective_margins_.footer + text_height});
188 // Calculate the overlay area. If the margins are excessive, the overlay_area
189 // size will be (0, 0).
190 overlay_area_.set_x(effective_margins_.left);
191 overlay_area_.set_y(effective_margins_.header);
192 overlay_area_.set_width(std::max(
194 physical_size_.width() - effective_margins_.right - overlay_area_.x()));
195 overlay_area_.set_height(std::max(
197 physical_size_.height() - effective_margins_.footer - overlay_area_.y()));
199 // Calculate the content area. If the margins are excessive, the content_area
200 // size will be (0, 0).
201 content_area_.set_x(effective_margins_.left);
202 content_area_.set_y(effective_margins_.top);
203 content_area_.set_width(std::max(
205 physical_size_.width() - effective_margins_.right - content_area_.x()));
206 content_area_.set_height(std::max(
208 physical_size_.height() - effective_margins_.bottom - content_area_.y()));
211 } // namespace printing