page_setup.cc 7.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211
  1. // Copyright (c) 2011 The Chromium Authors. All rights reserved.
  2. // Use of this source code is governed by a BSD-style license that can be
  3. // found in the LICENSE file.
  4. #include "printing/page_setup.h"
  5. #include <algorithm>
  6. #include "base/check_op.h"
  7. namespace printing {
  8. namespace {
  9. // Checks whether `printable_area` can be used to form a valid symmetrical
  10. // printable area, so that margin_left equals margin_right, and margin_top
  11. // equals margin_bottom. For example if
  12. // printable_area.x() * 2 >= page_size.width(), then the
  13. // content_width = page_size.width() - 2 * printable_area.x() would be zero or
  14. // negative, which is invalid.
  15. // `page_size` is the physical page size that includes margins.
  16. bool IsValidPrintableArea(const gfx::Size& page_size,
  17. const gfx::Rect& printable_area) {
  18. return !printable_area.IsEmpty() && printable_area.x() >= 0 &&
  19. printable_area.y() >= 0 &&
  20. printable_area.right() <= page_size.width() &&
  21. printable_area.bottom() <= page_size.height() &&
  22. printable_area.x() * 2 < page_size.width() &&
  23. printable_area.y() * 2 < page_size.height() &&
  24. printable_area.right() * 2 > page_size.width() &&
  25. printable_area.bottom() * 2 > page_size.height();
  26. }
  27. } // namespace
  28. PageMargins::PageMargins()
  29. : header(0), footer(0), left(0), right(0), top(0), bottom(0) {}
  30. PageMargins::PageMargins(int header,
  31. int footer,
  32. int left,
  33. int right,
  34. int top,
  35. int bottom)
  36. : header(header),
  37. footer(footer),
  38. left(left),
  39. right(right),
  40. top(top),
  41. bottom(bottom) {}
  42. void PageMargins::Clear() {
  43. header = 0;
  44. footer = 0;
  45. left = 0;
  46. right = 0;
  47. top = 0;
  48. bottom = 0;
  49. }
  50. bool PageMargins::Equals(const PageMargins& rhs) const {
  51. return header == rhs.header && footer == rhs.footer && left == rhs.left &&
  52. top == rhs.top && right == rhs.right && bottom == rhs.bottom;
  53. }
  54. PageSetup::PageSetup() {
  55. Clear();
  56. }
  57. PageSetup::PageSetup(const gfx::Size& physical_size,
  58. const gfx::Rect& printable_area,
  59. const PageMargins& requested_margins,
  60. bool forced_margins,
  61. int text_height)
  62. : requested_margins_(requested_margins), forced_margins_(forced_margins) {
  63. Init(physical_size, printable_area, text_height);
  64. }
  65. PageSetup::PageSetup(const PageSetup& other) = default;
  66. PageSetup::~PageSetup() = default;
  67. // static
  68. gfx::Rect PageSetup::GetSymmetricalPrintableArea(
  69. const gfx::Size& page_size,
  70. const gfx::Rect& printable_area) {
  71. if (!IsValidPrintableArea(page_size, printable_area))
  72. return gfx::Rect();
  73. int left_right_margin =
  74. std::max(printable_area.x(), page_size.width() - printable_area.right());
  75. int top_bottom_margin = std::max(
  76. printable_area.y(), page_size.height() - printable_area.bottom());
  77. int width = page_size.width() - 2 * left_right_margin;
  78. int height = page_size.height() - 2 * top_bottom_margin;
  79. gfx::Rect symmetrical_printable_area = gfx::Rect(page_size);
  80. symmetrical_printable_area.ClampToCenteredSize(gfx::Size(width, height));
  81. return symmetrical_printable_area;
  82. }
  83. void PageSetup::Clear() {
  84. physical_size_.SetSize(0, 0);
  85. printable_area_.SetRect(0, 0, 0, 0);
  86. overlay_area_.SetRect(0, 0, 0, 0);
  87. content_area_.SetRect(0, 0, 0, 0);
  88. effective_margins_.Clear();
  89. text_height_ = 0;
  90. forced_margins_ = false;
  91. }
  92. bool PageSetup::Equals(const PageSetup& rhs) const {
  93. return physical_size_ == rhs.physical_size_ &&
  94. printable_area_ == rhs.printable_area_ &&
  95. overlay_area_ == rhs.overlay_area_ &&
  96. content_area_ == rhs.content_area_ &&
  97. effective_margins_.Equals(rhs.effective_margins_) &&
  98. requested_margins_.Equals(rhs.requested_margins_) &&
  99. text_height_ == rhs.text_height_;
  100. }
  101. void PageSetup::Init(const gfx::Size& physical_size,
  102. const gfx::Rect& printable_area,
  103. int text_height) {
  104. DCHECK_LE(printable_area.right(), physical_size.width());
  105. // I've seen this assert triggers on Canon GP160PF PCL 5e and HP LaserJet 5.
  106. // Since we don't know the dpi here, just disable the check.
  107. // DCHECK_LE(printable_area.bottom(), physical_size.height());
  108. DCHECK_GE(printable_area.x(), 0);
  109. DCHECK_GE(printable_area.y(), 0);
  110. DCHECK_GE(text_height, 0);
  111. physical_size_ = physical_size;
  112. printable_area_ = printable_area;
  113. text_height_ = text_height;
  114. SetRequestedMarginsAndCalculateSizes(requested_margins_);
  115. }
  116. void PageSetup::SetRequestedMargins(const PageMargins& requested_margins) {
  117. forced_margins_ = false;
  118. SetRequestedMarginsAndCalculateSizes(requested_margins);
  119. }
  120. void PageSetup::ForceRequestedMargins(const PageMargins& requested_margins) {
  121. forced_margins_ = true;
  122. SetRequestedMarginsAndCalculateSizes(requested_margins);
  123. }
  124. void PageSetup::FlipOrientation() {
  125. if (physical_size_.width() && physical_size_.height()) {
  126. gfx::Size new_size(physical_size_.height(), physical_size_.width());
  127. int new_y = physical_size_.width() -
  128. (printable_area_.width() + printable_area_.x());
  129. gfx::Rect new_printable_area(printable_area_.y(), new_y,
  130. printable_area_.height(),
  131. printable_area_.width());
  132. Init(new_size, new_printable_area, text_height_);
  133. }
  134. }
  135. void PageSetup::SetRequestedMarginsAndCalculateSizes(
  136. const PageMargins& requested_margins) {
  137. requested_margins_ = requested_margins;
  138. if (physical_size_.width() && physical_size_.height()) {
  139. if (forced_margins_)
  140. CalculateSizesWithinRect(gfx::Rect(physical_size_), 0);
  141. else
  142. CalculateSizesWithinRect(printable_area_, text_height_);
  143. }
  144. }
  145. void PageSetup::CalculateSizesWithinRect(const gfx::Rect& bounds,
  146. int text_height) {
  147. // Calculate the effective margins. The tricky part.
  148. effective_margins_.header = std::max(requested_margins_.header, bounds.y());
  149. effective_margins_.footer = std::max(
  150. requested_margins_.footer, physical_size_.height() - bounds.bottom());
  151. effective_margins_.left = std::max(requested_margins_.left, bounds.x());
  152. effective_margins_.top = std::max({requested_margins_.top, bounds.y(),
  153. effective_margins_.header + text_height});
  154. effective_margins_.right = std::max(requested_margins_.right,
  155. physical_size_.width() - bounds.right());
  156. effective_margins_.bottom = std::max(
  157. {requested_margins_.bottom, physical_size_.height() - bounds.bottom(),
  158. effective_margins_.footer + text_height});
  159. // Calculate the overlay area. If the margins are excessive, the overlay_area
  160. // size will be (0, 0).
  161. overlay_area_.set_x(effective_margins_.left);
  162. overlay_area_.set_y(effective_margins_.header);
  163. overlay_area_.set_width(std::max(
  164. 0,
  165. physical_size_.width() - effective_margins_.right - overlay_area_.x()));
  166. overlay_area_.set_height(std::max(
  167. 0,
  168. physical_size_.height() - effective_margins_.footer - overlay_area_.y()));
  169. // Calculate the content area. If the margins are excessive, the content_area
  170. // size will be (0, 0).
  171. content_area_.set_x(effective_margins_.left);
  172. content_area_.set_y(effective_margins_.top);
  173. content_area_.set_width(std::max(
  174. 0,
  175. physical_size_.width() - effective_margins_.right - content_area_.x()));
  176. content_area_.set_height(std::max(
  177. 0,
  178. physical_size_.height() - effective_margins_.bottom - content_area_.y()));
  179. }
  180. } // namespace printing