blob: 9f5b12c460c782f271da1f9a121e5eff87519467 [file] [log] [blame]
K Moonbd80ce72019-07-26 19:27:501// 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
5#include "pdf/document_layout.h"
6
Jeremy Apthorp17c873c2019-12-02 20:27:397#include <algorithm>
8
Hans Wennborg5078d102020-04-29 18:26:469#include "base/check_op.h"
Gouarb Kunduc4338a62020-07-30 21:30:4810#include "base/values.h"
Ankit Kumar 🌪️aecc9f92020-08-18 19:11:2211#include "ui/gfx/geometry/point.h"
Ankit Kumar 🌪️b8ba092f2020-08-21 20:07:4512#include "ui/gfx/geometry/rect.h"
Ankit Kumar 🌪️e35101152020-07-30 09:57:5913#include "ui/gfx/geometry/size.h"
K Moonbd80ce72019-07-26 19:27:5014
15namespace chrome_pdf {
16
Jeremy Chinsene819dea2019-08-07 21:58:5917namespace {
18
K Moon23d56442019-10-03 05:06:2319constexpr char kDefaultPageOrientation[] = "defaultPageOrientation";
Hui Yingst28f9f5c2020-01-16 19:52:5620constexpr char kTwoUpViewEnabled[] = "twoUpViewEnabled";
K Moon23d56442019-10-03 05:06:2321
Ankit Kumar 🌪️e35101152020-07-30 09:57:5922int GetWidestPageWidth(const std::vector<gfx::Size>& page_sizes) {
Jeremy Chinsene819dea2019-08-07 21:58:5923 int widest_page_width = 0;
24 for (const auto& page_size : page_sizes) {
25 widest_page_width = std::max(widest_page_width, page_size.width());
26 }
27
28 return widest_page_width;
29}
30
Ankit Kumar 🌪️00798692020-08-26 22:57:1431gfx::Rect InsetRect(const gfx::Rect& rect,
32 const draw_utils::PageInsetSizes& inset_sizes) {
33 gfx::Rect inset_rect(rect);
34 inset_rect.Inset(inset_sizes.left, inset_sizes.top, inset_sizes.right,
35 inset_sizes.bottom);
36 return inset_rect;
K Moone4bd7522019-08-23 00:12:5637}
38
Jeremy Chinsene819dea2019-08-07 21:58:5939} // namespace
40
Lei Zhang4906c102019-08-06 00:28:0341const draw_utils::PageInsetSizes DocumentLayout::kSingleViewInsets{
42 /*left=*/5, /*top=*/3, /*right=*/5, /*bottom=*/7};
43
K Mooneb9e0002019-08-06 19:25:3244DocumentLayout::Options::Options() = default;
K Moonbd80ce72019-07-26 19:27:5045
K Mooneb9e0002019-08-06 19:25:3246DocumentLayout::Options::Options(const Options& other) = default;
47DocumentLayout::Options& DocumentLayout::Options::operator=(
48 const Options& other) = default;
K Moonbd80ce72019-07-26 19:27:5049
K Mooneb9e0002019-08-06 19:25:3250DocumentLayout::Options::~Options() = default;
K Moonbd80ce72019-07-26 19:27:5051
Gouarb Kunduc4338a62020-07-30 21:30:4852base::Value DocumentLayout::Options::ToValue() const {
53 base::Value dictionary(base::Value::Type::DICTIONARY);
54 dictionary.SetIntKey(kDefaultPageOrientation,
55 static_cast<int32_t>(default_page_orientation_));
56 dictionary.SetBoolKey(kTwoUpViewEnabled, two_up_view_enabled_);
K Moon23d56442019-10-03 05:06:2357 return dictionary;
58}
59
Gouarb Kundu18d80932020-09-23 04:29:1660void DocumentLayout::Options::FromValue(const base::Value& value) {
61 DCHECK(value.is_dict());
K Moon23d56442019-10-03 05:06:2362
63 int32_t default_page_orientation =
Gouarb Kundu18d80932020-09-23 04:29:1664 value.FindKey(kDefaultPageOrientation)->GetInt();
K Moon23d56442019-10-03 05:06:2365 DCHECK_GE(default_page_orientation,
66 static_cast<int32_t>(PageOrientation::kOriginal));
67 DCHECK_LE(default_page_orientation,
68 static_cast<int32_t>(PageOrientation::kLast));
69 default_page_orientation_ =
70 static_cast<PageOrientation>(default_page_orientation);
Hui Yingst28f9f5c2020-01-16 19:52:5671
Gouarb Kundu18d80932020-09-23 04:29:1672 two_up_view_enabled_ = value.FindKey(kTwoUpViewEnabled)->GetBool();
K Moon23d56442019-10-03 05:06:2373}
74
K Mooneb9e0002019-08-06 19:25:3275void DocumentLayout::Options::RotatePagesClockwise() {
K Moon9a62bf42019-08-07 20:05:3676 default_page_orientation_ = RotateClockwise(default_page_orientation_);
K Moonbd80ce72019-07-26 19:27:5077}
78
K Mooneb9e0002019-08-06 19:25:3279void DocumentLayout::Options::RotatePagesCounterclockwise() {
K Moon9a62bf42019-08-07 20:05:3680 default_page_orientation_ = RotateCounterclockwise(default_page_orientation_);
K Moonbd80ce72019-07-26 19:27:5081}
82
K Mooneb9e0002019-08-06 19:25:3283DocumentLayout::DocumentLayout() = default;
84
85DocumentLayout::~DocumentLayout() = default;
86
K Moon6d326b92019-09-19 22:42:0787void DocumentLayout::SetOptions(const Options& options) {
Hui Yingst28f9f5c2020-01-16 19:52:5688 // To be conservative, we want to consider the layout dirty for any layout
89 // option changes, even if the page rects don't necessarily change when
90 // layout options change.
K Moon6d326b92019-09-19 22:42:0791 //
Hui Yingst28f9f5c2020-01-16 19:52:5692 // We also probably don't want layout changes to actually kick in until
K Moon6d326b92019-09-19 22:42:0793 // the next call to ComputeLayout(). (In practice, we'll call ComputeLayout()
94 // shortly after calling SetOptions().)
Hui Yingst28f9f5c2020-01-16 19:52:5695 if (options_ != options) {
K Moon6d326b92019-09-19 22:42:0796 dirty_ = true;
97 }
98 options_ = options;
99}
100
K Moonff7ec672019-08-14 19:19:56101void DocumentLayout::ComputeSingleViewLayout(
Ankit Kumar 🌪️e35101152020-07-30 09:57:59102 const std::vector<gfx::Size>& page_sizes) {
103 gfx::Size document_size(GetWidestPageWidth(page_sizes), 0);
Jeremy Chinsen08beb482019-08-07 01:58:54104
K Moon6d326b92019-09-19 22:42:07105 if (page_layouts_.size() != page_sizes.size()) {
106 // TODO(kmoon): May want to do less work when shrinking a layout.
107 page_layouts_.resize(page_sizes.size());
108 dirty_ = true;
109 }
110
Jeremy Chinsen08beb482019-08-07 01:58:54111 for (size_t i = 0; i < page_sizes.size(); ++i) {
112 if (i != 0) {
113 // Add space for bottom separator.
K Moon6d326b92019-09-19 22:42:07114 document_size.Enlarge(0, kBottomSeparator);
Jeremy Chinsen08beb482019-08-07 01:58:54115 }
116
Ankit Kumar 🌪️e35101152020-07-30 09:57:59117 const gfx::Size& page_size = page_sizes[i];
Ankit Kumar 🌪️00798692020-08-26 22:57:14118 gfx::Rect page_rect =
119 draw_utils::GetRectForSingleView(page_size, document_size);
120 CopyRectIfModified(page_rect, page_layouts_[i].outer_rect);
K Moon6d326b92019-09-19 22:42:07121 CopyRectIfModified(InsetRect(page_rect, kSingleViewInsets),
Ankit Kumar 🌪️00798692020-08-26 22:57:14122 page_layouts_[i].inner_rect);
K Moone4bd7522019-08-23 00:12:56123
K Moon6d326b92019-09-19 22:42:07124 draw_utils::ExpandDocumentSize(page_size, &document_size);
125 }
126
127 if (size_ != document_size) {
128 size_ = document_size;
129 dirty_ = true;
Jeremy Chinsen08beb482019-08-07 01:58:54130 }
Jeremy Chinsen08beb482019-08-07 01:58:54131}
132
K Moonff7ec672019-08-14 19:19:56133void DocumentLayout::ComputeTwoUpViewLayout(
Ankit Kumar 🌪️e35101152020-07-30 09:57:59134 const std::vector<gfx::Size>& page_sizes) {
135 gfx::Size document_size(GetWidestPageWidth(page_sizes), 0);
Jeremy Chinsend6fd27ce2019-08-06 00:40:17136
K Moon6d326b92019-09-19 22:42:07137 if (page_layouts_.size() != page_sizes.size()) {
138 // TODO(kmoon): May want to do less work when shrinking a layout.
139 page_layouts_.resize(page_sizes.size());
140 dirty_ = true;
141 }
142
Jeremy Chinsen4a65aad2019-08-07 00:14:33143 for (size_t i = 0; i < page_sizes.size(); ++i) {
Jeremy Chinsend6fd27ce2019-08-06 00:40:17144 draw_utils::PageInsetSizes page_insets =
145 draw_utils::GetPageInsetsForTwoUpView(
Jeremy Chinsen4a65aad2019-08-07 00:14:33146 i, page_sizes.size(), kSingleViewInsets, kHorizontalSeparator);
Ankit Kumar 🌪️e35101152020-07-30 09:57:59147 const gfx::Size& page_size = page_sizes[i];
Jeremy Chinsend6fd27ce2019-08-06 00:40:17148
Ankit Kumar 🌪️00798692020-08-26 22:57:14149 gfx::Rect page_rect;
Jeremy Chinsend6fd27ce2019-08-06 00:40:17150 if (i % 2 == 0) {
Ankit Kumar 🌪️00798692020-08-26 22:57:14151 page_rect = draw_utils::GetLeftRectForTwoUpView(
152 page_size, {document_size.width(), document_size.height()});
Jeremy Chinsend6fd27ce2019-08-06 00:40:17153 } else {
Ankit Kumar 🌪️00798692020-08-26 22:57:14154 page_rect = draw_utils::GetRightRectForTwoUpView(
155 page_size, {document_size.width(), document_size.height()});
K Moon6d326b92019-09-19 22:42:07156 document_size.Enlarge(
157 0, std::max(page_size.height(), page_sizes[i - 1].height()));
Jeremy Chinsend6fd27ce2019-08-06 00:40:17158 }
Ankit Kumar 🌪️00798692020-08-26 22:57:14159 CopyRectIfModified(page_rect, page_layouts_[i].outer_rect);
K Moon6d326b92019-09-19 22:42:07160 CopyRectIfModified(InsetRect(page_rect, page_insets),
Ankit Kumar 🌪️00798692020-08-26 22:57:14161 page_layouts_[i].inner_rect);
Jeremy Chinsend6fd27ce2019-08-06 00:40:17162 }
163
Jeremy Chinsen4a65aad2019-08-07 00:14:33164 if (page_sizes.size() % 2 == 1) {
K Moon6d326b92019-09-19 22:42:07165 document_size.Enlarge(0, page_sizes.back().height());
Jeremy Chinsend6fd27ce2019-08-06 00:40:17166 }
167
K Moon6d326b92019-09-19 22:42:07168 document_size.set_width(2 * document_size.width());
169
170 if (size_ != document_size) {
171 size_ = document_size;
172 dirty_ = true;
173 }
174}
175
Ankit Kumar 🌪️00798692020-08-26 22:57:14176void DocumentLayout::CopyRectIfModified(const gfx::Rect& source_rect,
177 gfx::Rect& destination_rect) {
178 if (destination_rect != source_rect) {
179 destination_rect = source_rect;
K Moon6d326b92019-09-19 22:42:07180 dirty_ = true;
181 }
Jeremy Chinsend6fd27ce2019-08-06 00:40:17182}
183
K Moonbd80ce72019-07-26 19:27:50184} // namespace chrome_pdf