
The methodology used to generate this CL is documented in https://crbug.com/1098010#c95. No-Try: true Bug: 1098010 Change-Id: I6ae92e5d7ccbf73b176588124b2f8b4067f805b3 Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/3900575 Reviewed-by: Mark Mentovai <mark@chromium.org> Owners-Override: Avi Drissman <avi@chromium.org> Commit-Queue: Avi Drissman <avi@chromium.org> Auto-Submit: Avi Drissman <avi@chromium.org> Cr-Commit-Position: refs/heads/main@{#1047628}
201 lines
6.4 KiB
C++
201 lines
6.4 KiB
C++
// Copyright 2019 The Chromium Authors
|
|
// Use of this source code is governed by a BSD-style license that can be
|
|
// found in the LICENSE file.
|
|
|
|
#include "pdf/document_layout.h"
|
|
|
|
#include <algorithm>
|
|
|
|
#include "base/check_op.h"
|
|
#include "base/values.h"
|
|
#include "ui/gfx/geometry/point.h"
|
|
#include "ui/gfx/geometry/rect.h"
|
|
#include "ui/gfx/geometry/size.h"
|
|
|
|
namespace chrome_pdf {
|
|
|
|
namespace {
|
|
|
|
constexpr char kDirection[] = "direction";
|
|
constexpr char kDefaultPageOrientation[] = "defaultPageOrientation";
|
|
constexpr char kTwoUpViewEnabled[] = "twoUpViewEnabled";
|
|
|
|
int GetWidestPageWidth(const std::vector<gfx::Size>& page_sizes) {
|
|
int widest_page_width = 0;
|
|
for (const auto& page_size : page_sizes) {
|
|
widest_page_width = std::max(widest_page_width, page_size.width());
|
|
}
|
|
|
|
return widest_page_width;
|
|
}
|
|
|
|
gfx::Rect InsetRect(const gfx::Rect& rect,
|
|
const draw_utils::PageInsetSizes& inset_sizes) {
|
|
gfx::Rect inset_rect(rect);
|
|
inset_rect.Inset(gfx::Insets::TLBR(inset_sizes.top, inset_sizes.left,
|
|
inset_sizes.bottom, inset_sizes.right));
|
|
return inset_rect;
|
|
}
|
|
|
|
} // namespace
|
|
|
|
const draw_utils::PageInsetSizes DocumentLayout::kSingleViewInsets{
|
|
/*left=*/5, /*top=*/3, /*right=*/5, /*bottom=*/7};
|
|
|
|
DocumentLayout::Options::Options() = default;
|
|
|
|
DocumentLayout::Options::Options(const Options& other) = default;
|
|
DocumentLayout::Options& DocumentLayout::Options::operator=(
|
|
const Options& other) = default;
|
|
|
|
DocumentLayout::Options::~Options() = default;
|
|
|
|
base::Value::Dict DocumentLayout::Options::ToValue() const {
|
|
base::Value::Dict dictionary;
|
|
dictionary.Set(kDirection, direction_);
|
|
dictionary.Set(kDefaultPageOrientation,
|
|
static_cast<int>(default_page_orientation_));
|
|
dictionary.Set(kTwoUpViewEnabled, page_spread_ == PageSpread::kTwoUpOdd);
|
|
return dictionary;
|
|
}
|
|
|
|
void DocumentLayout::Options::FromValue(const base::Value::Dict& value) {
|
|
int32_t direction = value.FindInt(kDirection).value();
|
|
DCHECK_GE(direction, base::i18n::UNKNOWN_DIRECTION);
|
|
DCHECK_LE(direction, base::i18n::TEXT_DIRECTION_MAX);
|
|
direction_ = static_cast<base::i18n::TextDirection>(direction);
|
|
|
|
int32_t default_page_orientation =
|
|
value.FindInt(kDefaultPageOrientation).value();
|
|
DCHECK_GE(default_page_orientation,
|
|
static_cast<int32_t>(PageOrientation::kOriginal));
|
|
DCHECK_LE(default_page_orientation,
|
|
static_cast<int32_t>(PageOrientation::kLast));
|
|
default_page_orientation_ =
|
|
static_cast<PageOrientation>(default_page_orientation);
|
|
|
|
page_spread_ = value.FindBool(kTwoUpViewEnabled).value()
|
|
? PageSpread::kTwoUpOdd
|
|
: PageSpread::kOneUp;
|
|
}
|
|
|
|
void DocumentLayout::Options::RotatePagesClockwise() {
|
|
default_page_orientation_ = RotateClockwise(default_page_orientation_);
|
|
}
|
|
|
|
void DocumentLayout::Options::RotatePagesCounterclockwise() {
|
|
default_page_orientation_ = RotateCounterclockwise(default_page_orientation_);
|
|
}
|
|
|
|
DocumentLayout::DocumentLayout() = default;
|
|
|
|
DocumentLayout::~DocumentLayout() = default;
|
|
|
|
void DocumentLayout::SetOptions(const Options& options) {
|
|
// To be conservative, we want to consider the layout dirty for any layout
|
|
// option changes, even if the page rects don't necessarily change when
|
|
// layout options change.
|
|
//
|
|
// We also probably don't want layout changes to actually kick in until
|
|
// the next call to ComputeLayout(). (In practice, we'll call ComputeLayout()
|
|
// shortly after calling SetOptions().)
|
|
if (options_ != options) {
|
|
dirty_ = true;
|
|
}
|
|
options_ = options;
|
|
}
|
|
|
|
void DocumentLayout::ComputeLayout(const std::vector<gfx::Size>& page_sizes) {
|
|
switch (options_.page_spread()) {
|
|
case PageSpread::kOneUp:
|
|
return ComputeOneUpLayout(page_sizes);
|
|
case PageSpread::kTwoUpOdd:
|
|
return ComputeTwoUpOddLayout(page_sizes);
|
|
}
|
|
}
|
|
|
|
void DocumentLayout::ComputeOneUpLayout(
|
|
const std::vector<gfx::Size>& page_sizes) {
|
|
gfx::Size document_size(GetWidestPageWidth(page_sizes), 0);
|
|
|
|
if (page_layouts_.size() != page_sizes.size()) {
|
|
// TODO(kmoon): May want to do less work when shrinking a layout.
|
|
page_layouts_.resize(page_sizes.size());
|
|
dirty_ = true;
|
|
}
|
|
|
|
for (size_t i = 0; i < page_sizes.size(); ++i) {
|
|
if (i != 0) {
|
|
// Add space for bottom separator.
|
|
document_size.Enlarge(0, kBottomSeparator);
|
|
}
|
|
|
|
const gfx::Size& page_size = page_sizes[i];
|
|
gfx::Rect page_rect =
|
|
draw_utils::GetRectForSingleView(page_size, document_size);
|
|
CopyRectIfModified(page_rect, page_layouts_[i].outer_rect);
|
|
CopyRectIfModified(InsetRect(page_rect, kSingleViewInsets),
|
|
page_layouts_[i].inner_rect);
|
|
|
|
draw_utils::ExpandDocumentSize(page_size, &document_size);
|
|
}
|
|
|
|
if (size_ != document_size) {
|
|
size_ = document_size;
|
|
dirty_ = true;
|
|
}
|
|
}
|
|
|
|
void DocumentLayout::ComputeTwoUpOddLayout(
|
|
const std::vector<gfx::Size>& page_sizes) {
|
|
gfx::Size document_size(GetWidestPageWidth(page_sizes), 0);
|
|
|
|
if (page_layouts_.size() != page_sizes.size()) {
|
|
// TODO(kmoon): May want to do less work when shrinking a layout.
|
|
page_layouts_.resize(page_sizes.size());
|
|
dirty_ = true;
|
|
}
|
|
|
|
for (size_t i = 0; i < page_sizes.size(); ++i) {
|
|
draw_utils::PageInsetSizes page_insets =
|
|
draw_utils::GetPageInsetsForTwoUpView(
|
|
i, page_sizes.size(), kSingleViewInsets, kHorizontalSeparator);
|
|
const gfx::Size& page_size = page_sizes[i];
|
|
|
|
gfx::Rect page_rect;
|
|
if (i % 2 == 0) {
|
|
page_rect = draw_utils::GetLeftRectForTwoUpView(
|
|
page_size, {document_size.width(), document_size.height()});
|
|
} else {
|
|
page_rect = draw_utils::GetRightRectForTwoUpView(
|
|
page_size, {document_size.width(), document_size.height()});
|
|
document_size.Enlarge(
|
|
0, std::max(page_size.height(), page_sizes[i - 1].height()));
|
|
}
|
|
CopyRectIfModified(page_rect, page_layouts_[i].outer_rect);
|
|
CopyRectIfModified(InsetRect(page_rect, page_insets),
|
|
page_layouts_[i].inner_rect);
|
|
}
|
|
|
|
if (page_sizes.size() % 2 == 1) {
|
|
document_size.Enlarge(0, page_sizes.back().height());
|
|
}
|
|
|
|
document_size.set_width(2 * document_size.width());
|
|
|
|
if (size_ != document_size) {
|
|
size_ = document_size;
|
|
dirty_ = true;
|
|
}
|
|
}
|
|
|
|
void DocumentLayout::CopyRectIfModified(const gfx::Rect& source_rect,
|
|
gfx::Rect& destination_rect) {
|
|
if (destination_rect != source_rect) {
|
|
destination_rect = source_rect;
|
|
dirty_ = true;
|
|
}
|
|
}
|
|
|
|
} // namespace chrome_pdf
|