document_layout.h 5.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179
  1. // Copyright 2019 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. #ifndef PDF_DOCUMENT_LAYOUT_H_
  5. #define PDF_DOCUMENT_LAYOUT_H_
  6. #include <cstddef>
  7. #include <vector>
  8. #include "base/check_op.h"
  9. #include "base/i18n/rtl.h"
  10. #include "base/values.h"
  11. #include "pdf/draw_utils/coordinates.h"
  12. #include "pdf/page_orientation.h"
  13. #include "ui/gfx/geometry/rect.h"
  14. #include "ui/gfx/geometry/size.h"
  15. namespace chrome_pdf {
  16. // Layout of pages within a PDF document. Pages are placed as rectangles
  17. // (possibly rotated) in a non-overlapping vertical sequence.
  18. //
  19. // All layout units are pixels.
  20. //
  21. // The `Options` class controls the behavior of the layout, such as the default
  22. // orientation of pages.
  23. class DocumentLayout final {
  24. public:
  25. // TODO(crbug.com/1144505): Add `kTwoUpEven` page spread support.
  26. enum class PageSpread {
  27. kOneUp = 0, // One page per spread.
  28. kTwoUpOdd = 1, // Two pages per spread, with odd pages first.
  29. };
  30. // Options controlling layout behavior.
  31. class Options final {
  32. public:
  33. Options();
  34. Options(const Options& other);
  35. Options& operator=(const Options& other);
  36. ~Options();
  37. friend bool operator==(const Options& lhs, const Options& rhs) {
  38. return lhs.direction() == rhs.direction() &&
  39. lhs.default_page_orientation() == rhs.default_page_orientation() &&
  40. lhs.page_spread() == rhs.page_spread();
  41. }
  42. friend bool operator!=(const Options& lhs, const Options& rhs) {
  43. return !(lhs == rhs);
  44. }
  45. // Serializes layout options to a base::Value::Dict.
  46. base::Value::Dict ToValue() const;
  47. // Deserializes layout options from a base::Value::Dict.
  48. void FromValue(const base::Value::Dict& value);
  49. // Page layout direction. This is tied to the direction of the user's UI,
  50. // rather than the direction of individual pages.
  51. base::i18n::TextDirection direction() const { return direction_; }
  52. void set_direction(base::i18n::TextDirection direction) {
  53. direction_ = direction;
  54. }
  55. PageOrientation default_page_orientation() const {
  56. return default_page_orientation_;
  57. }
  58. // Rotates default page orientation 90 degrees clockwise.
  59. void RotatePagesClockwise();
  60. // Rotates default page orientation 90 degrees counterclockwise.
  61. void RotatePagesCounterclockwise();
  62. PageSpread page_spread() const { return page_spread_; }
  63. // Changes two-up view status.
  64. void set_page_spread(PageSpread spread) { page_spread_ = spread; }
  65. private:
  66. base::i18n::TextDirection direction_ = base::i18n::UNKNOWN_DIRECTION;
  67. PageOrientation default_page_orientation_ = PageOrientation::kOriginal;
  68. PageSpread page_spread_ = PageSpread::kOneUp;
  69. };
  70. static const draw_utils::PageInsetSizes kSingleViewInsets;
  71. static constexpr int32_t kBottomSeparator = 4;
  72. static constexpr int32_t kHorizontalSeparator = 1;
  73. DocumentLayout();
  74. DocumentLayout(const DocumentLayout& other) = delete;
  75. DocumentLayout& operator=(const DocumentLayout& other) = delete;
  76. ~DocumentLayout();
  77. // Returns the layout options.
  78. const Options& options() const { return options_; }
  79. // Sets the layout options. If certain options with immediate effect change
  80. // (such as the default page orientation), the layout will be marked dirty.
  81. //
  82. // TODO(kmoon): We shouldn't have layout options that take effect immediately.
  83. void SetOptions(const Options& options);
  84. // Returns true if the layout has been modified since the last call to
  85. // clear_dirty(). The initial state is false (clean), which assumes
  86. // appropriate default behavior for an initially empty layout.
  87. bool dirty() const { return dirty_; }
  88. // Clears the dirty() state of the layout. This should be called after any
  89. // layout changes have been applied.
  90. void clear_dirty() { dirty_ = false; }
  91. // Returns the layout's total size.
  92. const gfx::Size& size() const { return size_; }
  93. size_t page_count() const { return page_layouts_.size(); }
  94. // Gets the layout rectangle for a page. Only valid after computing a layout.
  95. const gfx::Rect& page_rect(size_t page_index) const {
  96. DCHECK_LT(page_index, page_count());
  97. return page_layouts_[page_index].outer_rect;
  98. }
  99. // Gets the layout rectangle for a page's bounds (which excludes additional
  100. // regions like page shadows). Only valid after computing a layout.
  101. const gfx::Rect& page_bounds_rect(size_t page_index) const {
  102. DCHECK_LT(page_index, page_count());
  103. return page_layouts_[page_index].inner_rect;
  104. }
  105. // Computes the layout for a given list of `page_sizes` based on `options_`.
  106. void ComputeLayout(const std::vector<gfx::Size>& page_sizes);
  107. private:
  108. // Layout of a single page.
  109. struct PageLayout {
  110. // Bounding rectangle for the page with decorations.
  111. gfx::Rect outer_rect;
  112. // Bounding rectangle for the page without decorations.
  113. gfx::Rect inner_rect;
  114. };
  115. // Helpers for ComputeLayout() handling different page spreads.
  116. void ComputeOneUpLayout(const std::vector<gfx::Size>& page_sizes);
  117. void ComputeTwoUpOddLayout(const std::vector<gfx::Size>& page_sizes);
  118. // Copies `source_rect` to `destination_rect`, setting `dirty_` to true if
  119. // `destination_rect` is modified as a result.
  120. void CopyRectIfModified(const gfx::Rect& source_rect,
  121. gfx::Rect& destination_rect);
  122. Options options_;
  123. // Indicates if the layout has changed in an externally-observable way,
  124. // usually as a result of calling `ComputeLayout()` with different inputs.
  125. //
  126. // Some operations that may trigger layout changes:
  127. // * Changing page sizes
  128. // * Adding or removing pages
  129. // * Changing page orientations
  130. bool dirty_ = false;
  131. // Layout's total size.
  132. gfx::Size size_;
  133. std::vector<PageLayout> page_layouts_;
  134. };
  135. } // namespace chrome_pdf
  136. #endif // PDF_DOCUMENT_LAYOUT_H_