blob: 2c93d70fcbc6bb7cd3ca8676ad4debca7508f9e2 [file] [log] [blame]
Avi Drissmandb497b32022-09-15 19:47:281// Copyright 2019 The Chromium Authors
K Moonbd80ce72019-07-26 19:27:502// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#ifndef PDF_DOCUMENT_LAYOUT_H_
6#define PDF_DOCUMENT_LAYOUT_H_
7
K Moonff7ec672019-08-14 19:19:568#include <cstddef>
Jeremy Chinsend6fd27ce2019-08-06 00:40:179#include <vector>
10
Hans Wennborg29adea92020-06-22 16:13:5311#include "base/check_op.h"
K. Moone2dda8f22021-10-05 00:37:2912#include "base/i18n/rtl.h"
Lei Zhang277b156c2022-04-11 22:58:5113#include "base/values.h"
K Moon9a62bf42019-08-07 20:05:3614#include "pdf/page_orientation.h"
Lei Zhangd3ef3f32024-06-11 16:14:5615#include "ui/gfx/geometry/insets.h"
Ankit Kumar 🌪️00798692020-08-26 22:57:1416#include "ui/gfx/geometry/rect.h"
Ankit Kumar 🌪️e35101152020-07-30 09:57:5917#include "ui/gfx/geometry/size.h"
K Moonbd80ce72019-07-26 19:27:5018
19namespace chrome_pdf {
20
21// Layout of pages within a PDF document. Pages are placed as rectangles
22// (possibly rotated) in a non-overlapping vertical sequence.
23//
24// All layout units are pixels.
K Mooneb9e0002019-08-06 19:25:3225//
Daniel Hosseiniane257d962021-04-23 21:18:3526// The `Options` class controls the behavior of the layout, such as the default
K Mooneb9e0002019-08-06 19:25:3227// orientation of pages.
K Moonbd80ce72019-07-26 19:27:5028class DocumentLayout final {
29 public:
Alison Gale47d1537d2024-04-19 21:31:4630 // TODO(crbug.com/40155509): Add `kTwoUpEven` page spread support.
Daniel Hosseinianbe882062021-04-22 01:22:3931 enum class PageSpread {
32 kOneUp = 0, // One page per spread.
33 kTwoUpOdd = 1, // Two pages per spread, with odd pages first.
34 };
35
K Mooneb9e0002019-08-06 19:25:3236 // Options controlling layout behavior.
37 class Options final {
38 public:
39 Options();
40
41 Options(const Options& other);
42 Options& operator=(const Options& other);
43
44 ~Options();
45
Hui Yingst28f9f5c2020-01-16 19:52:5646 friend bool operator==(const Options& lhs, const Options& rhs) {
K. Moone2dda8f22021-10-05 00:37:2947 return lhs.direction() == rhs.direction() &&
48 lhs.default_page_orientation() == rhs.default_page_orientation() &&
49 lhs.page_spread() == rhs.page_spread();
Hui Yingst28f9f5c2020-01-16 19:52:5650 }
51
52 friend bool operator!=(const Options& lhs, const Options& rhs) {
53 return !(lhs == rhs);
54 }
55
Lei Zhang277b156c2022-04-11 22:58:5156 // Serializes layout options to a base::Value::Dict.
57 base::Value::Dict ToValue() const;
K Moon23d56442019-10-03 05:06:2358
Lei Zhang277b156c2022-04-11 22:58:5159 // Deserializes layout options from a base::Value::Dict.
60 void FromValue(const base::Value::Dict& value);
K Moon23d56442019-10-03 05:06:2361
K. Moone2dda8f22021-10-05 00:37:2962 // Page layout direction. This is tied to the direction of the user's UI,
63 // rather than the direction of individual pages.
64 base::i18n::TextDirection direction() const { return direction_; }
65
66 void set_direction(base::i18n::TextDirection direction) {
67 direction_ = direction;
68 }
69
K Moon9a62bf42019-08-07 20:05:3670 PageOrientation default_page_orientation() const {
71 return default_page_orientation_;
72 }
K Mooneb9e0002019-08-06 19:25:3273
74 // Rotates default page orientation 90 degrees clockwise.
75 void RotatePagesClockwise();
76
77 // Rotates default page orientation 90 degrees counterclockwise.
78 void RotatePagesCounterclockwise();
79
Daniel Hosseinianbe882062021-04-22 01:22:3980 PageSpread page_spread() const { return page_spread_; }
Hui Yingst28f9f5c2020-01-16 19:52:5681
82 // Changes two-up view status.
Daniel Hosseinianbe882062021-04-22 01:22:3983 void set_page_spread(PageSpread spread) { page_spread_ = spread; }
Hui Yingst28f9f5c2020-01-16 19:52:5684
K Mooneb9e0002019-08-06 19:25:3285 private:
K. Moone2dda8f22021-10-05 00:37:2986 base::i18n::TextDirection direction_ = base::i18n::UNKNOWN_DIRECTION;
K Moon9a62bf42019-08-07 20:05:3687 PageOrientation default_page_orientation_ = PageOrientation::kOriginal;
Daniel Hosseinianbe882062021-04-22 01:22:3988 PageSpread page_spread_ = PageSpread::kOneUp;
K Mooneb9e0002019-08-06 19:25:3289 };
90
Lei Zhangd3ef3f32024-06-11 16:14:5691 static constexpr gfx::Insets kSingleViewInsets =
92 gfx::Insets::TLBR(/*top=*/3, /*left=*/5, /*bottom=*/7, /*right=*/5);
Lei Zhang4906c102019-08-06 00:28:0393 static constexpr int32_t kBottomSeparator = 4;
94 static constexpr int32_t kHorizontalSeparator = 1;
95
K Moonbd80ce72019-07-26 19:27:5096 DocumentLayout();
97
K Mooneb9e0002019-08-06 19:25:3298 DocumentLayout(const DocumentLayout& other) = delete;
99 DocumentLayout& operator=(const DocumentLayout& other) = delete;
K Moonbd80ce72019-07-26 19:27:50100
101 ~DocumentLayout();
102
K Mooneb9e0002019-08-06 19:25:32103 // Returns the layout options.
104 const Options& options() const { return options_; }
K Moonbd80ce72019-07-26 19:27:50105
K Moon6d326b92019-09-19 22:42:07106 // Sets the layout options. If certain options with immediate effect change
107 // (such as the default page orientation), the layout will be marked dirty.
108 //
109 // TODO(kmoon): We shouldn't have layout options that take effect immediately.
110 void SetOptions(const Options& options);
111
112 // Returns true if the layout has been modified since the last call to
113 // clear_dirty(). The initial state is false (clean), which assumes
114 // appropriate default behavior for an initially empty layout.
115 bool dirty() const { return dirty_; }
116
117 // Clears the dirty() state of the layout. This should be called after any
118 // layout changes have been applied.
119 void clear_dirty() { dirty_ = false; }
K Moonbd80ce72019-07-26 19:27:50120
121 // Returns the layout's total size.
Ankit Kumar 🌪️e35101152020-07-30 09:57:59122 const gfx::Size& size() const { return size_; }
K Moonbd80ce72019-07-26 19:27:50123
K Moone4bd7522019-08-23 00:12:56124 size_t page_count() const { return page_layouts_.size(); }
Jeremy Chinsen08beb482019-08-07 01:58:54125
K Moonff7ec672019-08-14 19:19:56126 // Gets the layout rectangle for a page. Only valid after computing a layout.
Ankit Kumar 🌪️00798692020-08-26 22:57:14127 const gfx::Rect& page_rect(size_t page_index) const {
K Moonff7ec672019-08-14 19:19:56128 DCHECK_LT(page_index, page_count());
K Moone4bd7522019-08-23 00:12:56129 return page_layouts_[page_index].outer_rect;
130 }
131
132 // Gets the layout rectangle for a page's bounds (which excludes additional
133 // regions like page shadows). Only valid after computing a layout.
Ankit Kumar 🌪️00798692020-08-26 22:57:14134 const gfx::Rect& page_bounds_rect(size_t page_index) const {
K Moone4bd7522019-08-23 00:12:56135 DCHECK_LT(page_index, page_count());
136 return page_layouts_[page_index].inner_rect;
K Moonff7ec672019-08-14 19:19:56137 }
138
Daniel Hosseiniane257d962021-04-23 21:18:35139 // Computes the layout for a given list of `page_sizes` based on `options_`.
Daniel Hosseinianbcbedda2021-04-23 19:09:51140 void ComputeLayout(const std::vector<gfx::Size>& page_sizes);
Jeremy Chinsend6fd27ce2019-08-06 00:40:17141
K Moonbd80ce72019-07-26 19:27:50142 private:
K Moone4bd7522019-08-23 00:12:56143 // Layout of a single page.
144 struct PageLayout {
145 // Bounding rectangle for the page with decorations.
Ankit Kumar 🌪️00798692020-08-26 22:57:14146 gfx::Rect outer_rect;
K Moone4bd7522019-08-23 00:12:56147
148 // Bounding rectangle for the page without decorations.
Ankit Kumar 🌪️00798692020-08-26 22:57:14149 gfx::Rect inner_rect;
K Moone4bd7522019-08-23 00:12:56150 };
151
Daniel Hosseinianbcbedda2021-04-23 19:09:51152 // Helpers for ComputeLayout() handling different page spreads.
153 void ComputeOneUpLayout(const std::vector<gfx::Size>& page_sizes);
154 void ComputeTwoUpOddLayout(const std::vector<gfx::Size>& page_sizes);
155
Daniel Hosseiniane257d962021-04-23 21:18:35156 // Copies `source_rect` to `destination_rect`, setting `dirty_` to true if
157 // `destination_rect` is modified as a result.
Ankit Kumar 🌪️00798692020-08-26 22:57:14158 void CopyRectIfModified(const gfx::Rect& source_rect,
159 gfx::Rect& destination_rect);
K Moon6d326b92019-09-19 22:42:07160
K Mooneb9e0002019-08-06 19:25:32161 Options options_;
K Moonbd80ce72019-07-26 19:27:50162
K Moon6d326b92019-09-19 22:42:07163 // Indicates if the layout has changed in an externally-observable way,
Daniel Hosseiniane257d962021-04-23 21:18:35164 // usually as a result of calling `ComputeLayout()` with different inputs.
K Moon6d326b92019-09-19 22:42:07165 //
166 // Some operations that may trigger layout changes:
167 // * Changing page sizes
168 // * Adding or removing pages
169 // * Changing page orientations
170 bool dirty_ = false;
171
K Moonbd80ce72019-07-26 19:27:50172 // Layout's total size.
Ankit Kumar 🌪️e35101152020-07-30 09:57:59173 gfx::Size size_;
K Moonff7ec672019-08-14 19:19:56174
K Moone4bd7522019-08-23 00:12:56175 std::vector<PageLayout> page_layouts_;
K Moonbd80ce72019-07-26 19:27:50176};
177
178} // namespace chrome_pdf
179
180#endif // PDF_DOCUMENT_LAYOUT_H_