0
Files
src/pdf/document_layout.h
K. Moon e2dda8f27c Send UI direction to internal PDF plugin
Extends chrome_pdf::DocumentLayout::Options with a field for the UI
direction (left-to-right or right-to-left). This allows the viewer UI to
communicate the UI direction to the plugin. (This information is
available from base::i18n::IsRTL() in unseasoned mode, but is not
available to the Pepper plugin. In any case, it could be useful to make
it togglable in the PDF viewer.)

The UI direction field could have been added to the viewport message
directly, but it likely will be useful to support RTL page layouts in
the future.

Also adds some serialization and deserialization tests, now that Options
serializes to and from base::Value. Also had to fix a bug with dirty
layout options triggering layout before document loading finished.

Bug: 1158670
Change-Id: Iaa7cfccacfe54858a53d6e28b07f786332d7e9e8
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/3202535
Reviewed-by: Daniel Hosseinian <dhoss@chromium.org>
Commit-Queue: K. Moon <kmoon@chromium.org>
Cr-Commit-Position: refs/heads/main@{#927933}
2021-10-05 00:37:29 +00:00

183 lines
5.8 KiB
C++

// Copyright 2019 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef PDF_DOCUMENT_LAYOUT_H_
#define PDF_DOCUMENT_LAYOUT_H_
#include <cstddef>
#include <vector>
#include "base/check_op.h"
#include "base/i18n/rtl.h"
#include "pdf/draw_utils/coordinates.h"
#include "pdf/page_orientation.h"
#include "ui/gfx/geometry/rect.h"
#include "ui/gfx/geometry/size.h"
namespace base {
class Value;
}
namespace chrome_pdf {
// Layout of pages within a PDF document. Pages are placed as rectangles
// (possibly rotated) in a non-overlapping vertical sequence.
//
// All layout units are pixels.
//
// The `Options` class controls the behavior of the layout, such as the default
// orientation of pages.
class DocumentLayout final {
public:
// TODO(crbug.com/1144505): Add `kTwoUpEven` page spread support.
enum class PageSpread {
kOneUp = 0, // One page per spread.
kTwoUpOdd = 1, // Two pages per spread, with odd pages first.
};
// Options controlling layout behavior.
class Options final {
public:
Options();
Options(const Options& other);
Options& operator=(const Options& other);
~Options();
friend bool operator==(const Options& lhs, const Options& rhs) {
return lhs.direction() == rhs.direction() &&
lhs.default_page_orientation() == rhs.default_page_orientation() &&
lhs.page_spread() == rhs.page_spread();
}
friend bool operator!=(const Options& lhs, const Options& rhs) {
return !(lhs == rhs);
}
// Serializes layout options to a base::Value.
base::Value ToValue() const;
// Deserializes layout options from a base::Value.
void FromValue(const base::Value& value);
// Page layout direction. This is tied to the direction of the user's UI,
// rather than the direction of individual pages.
base::i18n::TextDirection direction() const { return direction_; }
void set_direction(base::i18n::TextDirection direction) {
direction_ = direction;
}
PageOrientation default_page_orientation() const {
return default_page_orientation_;
}
// Rotates default page orientation 90 degrees clockwise.
void RotatePagesClockwise();
// Rotates default page orientation 90 degrees counterclockwise.
void RotatePagesCounterclockwise();
PageSpread page_spread() const { return page_spread_; }
// Changes two-up view status.
void set_page_spread(PageSpread spread) { page_spread_ = spread; }
private:
base::i18n::TextDirection direction_ = base::i18n::UNKNOWN_DIRECTION;
PageOrientation default_page_orientation_ = PageOrientation::kOriginal;
PageSpread page_spread_ = PageSpread::kOneUp;
};
static const draw_utils::PageInsetSizes kSingleViewInsets;
static constexpr int32_t kBottomSeparator = 4;
static constexpr int32_t kHorizontalSeparator = 1;
DocumentLayout();
DocumentLayout(const DocumentLayout& other) = delete;
DocumentLayout& operator=(const DocumentLayout& other) = delete;
~DocumentLayout();
// Returns the layout options.
const Options& options() const { return options_; }
// Sets the layout options. If certain options with immediate effect change
// (such as the default page orientation), the layout will be marked dirty.
//
// TODO(kmoon): We shouldn't have layout options that take effect immediately.
void SetOptions(const Options& options);
// Returns true if the layout has been modified since the last call to
// clear_dirty(). The initial state is false (clean), which assumes
// appropriate default behavior for an initially empty layout.
bool dirty() const { return dirty_; }
// Clears the dirty() state of the layout. This should be called after any
// layout changes have been applied.
void clear_dirty() { dirty_ = false; }
// Returns the layout's total size.
const gfx::Size& size() const { return size_; }
size_t page_count() const { return page_layouts_.size(); }
// Gets the layout rectangle for a page. Only valid after computing a layout.
const gfx::Rect& page_rect(size_t page_index) const {
DCHECK_LT(page_index, page_count());
return page_layouts_[page_index].outer_rect;
}
// Gets the layout rectangle for a page's bounds (which excludes additional
// regions like page shadows). Only valid after computing a layout.
const gfx::Rect& page_bounds_rect(size_t page_index) const {
DCHECK_LT(page_index, page_count());
return page_layouts_[page_index].inner_rect;
}
// Computes the layout for a given list of `page_sizes` based on `options_`.
void ComputeLayout(const std::vector<gfx::Size>& page_sizes);
private:
// Layout of a single page.
struct PageLayout {
// Bounding rectangle for the page with decorations.
gfx::Rect outer_rect;
// Bounding rectangle for the page without decorations.
gfx::Rect inner_rect;
};
// Helpers for ComputeLayout() handling different page spreads.
void ComputeOneUpLayout(const std::vector<gfx::Size>& page_sizes);
void ComputeTwoUpOddLayout(const std::vector<gfx::Size>& page_sizes);
// Copies `source_rect` to `destination_rect`, setting `dirty_` to true if
// `destination_rect` is modified as a result.
void CopyRectIfModified(const gfx::Rect& source_rect,
gfx::Rect& destination_rect);
Options options_;
// Indicates if the layout has changed in an externally-observable way,
// usually as a result of calling `ComputeLayout()` with different inputs.
//
// Some operations that may trigger layout changes:
// * Changing page sizes
// * Adding or removing pages
// * Changing page orientations
bool dirty_ = false;
// Layout's total size.
gfx::Size size_;
std::vector<PageLayout> page_layouts_;
};
} // namespace chrome_pdf
#endif // PDF_DOCUMENT_LAYOUT_H_