[M108 Migration][HBBTV] Implement ewk_context_register_jsplugin_mime_types API
[platform/framework/web/chromium-efl.git] / pdf / document_layout.cc
1 // Copyright 2019 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.
4
5 #include "pdf/document_layout.h"
6
7 #include <algorithm>
8
9 #include "base/check_op.h"
10 #include "base/values.h"
11 #include "ui/gfx/geometry/point.h"
12 #include "ui/gfx/geometry/rect.h"
13 #include "ui/gfx/geometry/size.h"
14
15 namespace chrome_pdf {
16
17 namespace {
18
19 constexpr char kDirection[] = "direction";
20 constexpr char kDefaultPageOrientation[] = "defaultPageOrientation";
21 constexpr char kTwoUpViewEnabled[] = "twoUpViewEnabled";
22
23 int GetWidestPageWidth(const std::vector<gfx::Size>& page_sizes) {
24   int widest_page_width = 0;
25   for (const auto& page_size : page_sizes) {
26     widest_page_width = std::max(widest_page_width, page_size.width());
27   }
28
29   return widest_page_width;
30 }
31
32 gfx::Rect InsetRect(const gfx::Rect& rect,
33                     const draw_utils::PageInsetSizes& inset_sizes) {
34   gfx::Rect inset_rect(rect);
35   inset_rect.Inset(gfx::Insets::TLBR(inset_sizes.top, inset_sizes.left,
36                                      inset_sizes.bottom, inset_sizes.right));
37   return inset_rect;
38 }
39
40 }  // namespace
41
42 const draw_utils::PageInsetSizes DocumentLayout::kSingleViewInsets{
43     /*left=*/5, /*top=*/3, /*right=*/5, /*bottom=*/7};
44
45 DocumentLayout::Options::Options() = default;
46
47 DocumentLayout::Options::Options(const Options& other) = default;
48 DocumentLayout::Options& DocumentLayout::Options::operator=(
49     const Options& other) = default;
50
51 DocumentLayout::Options::~Options() = default;
52
53 base::Value::Dict DocumentLayout::Options::ToValue() const {
54   base::Value::Dict dictionary;
55   dictionary.Set(kDirection, direction_);
56   dictionary.Set(kDefaultPageOrientation,
57                  static_cast<int>(default_page_orientation_));
58   dictionary.Set(kTwoUpViewEnabled, page_spread_ == PageSpread::kTwoUpOdd);
59   return dictionary;
60 }
61
62 void DocumentLayout::Options::FromValue(const base::Value::Dict& value) {
63   int32_t direction = value.FindInt(kDirection).value();
64   DCHECK_GE(direction, base::i18n::UNKNOWN_DIRECTION);
65   DCHECK_LE(direction, base::i18n::TEXT_DIRECTION_MAX);
66   direction_ = static_cast<base::i18n::TextDirection>(direction);
67
68   int32_t default_page_orientation =
69       value.FindInt(kDefaultPageOrientation).value();
70   DCHECK_GE(default_page_orientation,
71             static_cast<int32_t>(PageOrientation::kOriginal));
72   DCHECK_LE(default_page_orientation,
73             static_cast<int32_t>(PageOrientation::kLast));
74   default_page_orientation_ =
75       static_cast<PageOrientation>(default_page_orientation);
76
77   page_spread_ = value.FindBool(kTwoUpViewEnabled).value()
78                      ? PageSpread::kTwoUpOdd
79                      : PageSpread::kOneUp;
80 }
81
82 void DocumentLayout::Options::RotatePagesClockwise() {
83   default_page_orientation_ = RotateClockwise(default_page_orientation_);
84 }
85
86 void DocumentLayout::Options::RotatePagesCounterclockwise() {
87   default_page_orientation_ = RotateCounterclockwise(default_page_orientation_);
88 }
89
90 DocumentLayout::DocumentLayout() = default;
91
92 DocumentLayout::~DocumentLayout() = default;
93
94 void DocumentLayout::SetOptions(const Options& options) {
95   // To be conservative, we want to consider the layout dirty for any layout
96   // option changes, even if the page rects don't necessarily change when
97   // layout options change.
98   //
99   // We also probably don't want layout changes to actually kick in until
100   // the next call to ComputeLayout(). (In practice, we'll call ComputeLayout()
101   // shortly after calling SetOptions().)
102   if (options_ != options) {
103     dirty_ = true;
104   }
105   options_ = options;
106 }
107
108 void DocumentLayout::ComputeLayout(const std::vector<gfx::Size>& page_sizes) {
109   switch (options_.page_spread()) {
110     case PageSpread::kOneUp:
111       return ComputeOneUpLayout(page_sizes);
112     case PageSpread::kTwoUpOdd:
113       return ComputeTwoUpOddLayout(page_sizes);
114   }
115 }
116
117 void DocumentLayout::ComputeOneUpLayout(
118     const std::vector<gfx::Size>& page_sizes) {
119   gfx::Size document_size(GetWidestPageWidth(page_sizes), 0);
120
121   if (page_layouts_.size() != page_sizes.size()) {
122     // TODO(kmoon): May want to do less work when shrinking a layout.
123     page_layouts_.resize(page_sizes.size());
124     dirty_ = true;
125   }
126
127   for (size_t i = 0; i < page_sizes.size(); ++i) {
128     if (i != 0) {
129       // Add space for bottom separator.
130       document_size.Enlarge(0, kBottomSeparator);
131     }
132
133     const gfx::Size& page_size = page_sizes[i];
134     gfx::Rect page_rect =
135         draw_utils::GetRectForSingleView(page_size, document_size);
136     CopyRectIfModified(page_rect, page_layouts_[i].outer_rect);
137     CopyRectIfModified(InsetRect(page_rect, kSingleViewInsets),
138                        page_layouts_[i].inner_rect);
139
140     draw_utils::ExpandDocumentSize(page_size, &document_size);
141   }
142
143   if (size_ != document_size) {
144     size_ = document_size;
145     dirty_ = true;
146   }
147 }
148
149 void DocumentLayout::ComputeTwoUpOddLayout(
150     const std::vector<gfx::Size>& page_sizes) {
151   gfx::Size document_size(GetWidestPageWidth(page_sizes), 0);
152
153   if (page_layouts_.size() != page_sizes.size()) {
154     // TODO(kmoon): May want to do less work when shrinking a layout.
155     page_layouts_.resize(page_sizes.size());
156     dirty_ = true;
157   }
158
159   for (size_t i = 0; i < page_sizes.size(); ++i) {
160     draw_utils::PageInsetSizes page_insets =
161         draw_utils::GetPageInsetsForTwoUpView(
162             i, page_sizes.size(), kSingleViewInsets, kHorizontalSeparator);
163     const gfx::Size& page_size = page_sizes[i];
164
165     gfx::Rect page_rect;
166     if (i % 2 == 0) {
167       page_rect = draw_utils::GetLeftRectForTwoUpView(
168           page_size, {document_size.width(), document_size.height()});
169     } else {
170       page_rect = draw_utils::GetRightRectForTwoUpView(
171           page_size, {document_size.width(), document_size.height()});
172       document_size.Enlarge(
173           0, std::max(page_size.height(), page_sizes[i - 1].height()));
174     }
175     CopyRectIfModified(page_rect, page_layouts_[i].outer_rect);
176     CopyRectIfModified(InsetRect(page_rect, page_insets),
177                        page_layouts_[i].inner_rect);
178   }
179
180   if (page_sizes.size() % 2 == 1) {
181     document_size.Enlarge(0, page_sizes.back().height());
182   }
183
184   document_size.set_width(2 * document_size.width());
185
186   if (size_ != document_size) {
187     size_ = document_size;
188     dirty_ = true;
189   }
190 }
191
192 void DocumentLayout::CopyRectIfModified(const gfx::Rect& source_rect,
193                                         gfx::Rect& destination_rect) {
194   if (destination_rect != source_rect) {
195     destination_rect = source_rect;
196     dirty_ = true;
197   }
198 }
199
200 }  // namespace chrome_pdf