Move page layout rectangles into DocumentLayout
This change moves primary ownership of a page's "layout rectangle" from individual PDFiumPage objects to the DocumentLayout as a whole. Conceptually, a page's rectangle in the layout really is a property of the layout, and not of the PDFium-specific page data structure: A PDFiumPage should be a client of the layout, not vice versa. This change also allows multiple layouts to exist simultaneously: The shared, per engine PDFiumPage-based layout rectangles currently prevent calculating different layouts independently. To minimize the size of this refactoring, for now the PDFiumPage retains a secondary copy of the layout rectangle for use during painting and coordinate transformations. This copy should only be updated when PDFiumEngine::ApplyCurrentLayoutToPages() is called, after a layout change. Bug: 885110 Change-Id: I8aac622e80f0779c556b8873ab085c6106f92c6e Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1746084 Commit-Queue: K Moon <kmoon@chromium.org> Reviewed-by: Lei Zhang <thestig@chromium.org> Cr-Commit-Position: refs/heads/master@{#686933}
This commit is contained in:
@ -44,11 +44,11 @@ DocumentLayout::DocumentLayout() = default;
|
||||
|
||||
DocumentLayout::~DocumentLayout() = default;
|
||||
|
||||
std::vector<pp::Rect> DocumentLayout::GetSingleViewLayout(
|
||||
void DocumentLayout::ComputeSingleViewLayout(
|
||||
const std::vector<pp::Size>& page_sizes) {
|
||||
set_size({GetWidestPageWidth(page_sizes), 0});
|
||||
|
||||
std::vector<pp::Rect> formatted_rects(page_sizes.size());
|
||||
page_rects_.resize(page_sizes.size());
|
||||
for (size_t i = 0; i < page_sizes.size(); ++i) {
|
||||
if (i != 0) {
|
||||
// Add space for bottom separator.
|
||||
@ -56,19 +56,17 @@ std::vector<pp::Rect> DocumentLayout::GetSingleViewLayout(
|
||||
}
|
||||
|
||||
const pp::Size& page_size = page_sizes[i];
|
||||
formatted_rects[i] =
|
||||
page_rects_[i] =
|
||||
draw_utils::GetRectForSingleView(page_size, size_, kSingleViewInsets);
|
||||
AppendPageRect(page_size);
|
||||
draw_utils::ExpandDocumentSize(page_size, &size_);
|
||||
}
|
||||
|
||||
return formatted_rects;
|
||||
}
|
||||
|
||||
std::vector<pp::Rect> DocumentLayout::GetTwoUpViewLayout(
|
||||
void DocumentLayout::ComputeTwoUpViewLayout(
|
||||
const std::vector<pp::Size>& page_sizes) {
|
||||
set_size({GetWidestPageWidth(page_sizes), 0});
|
||||
|
||||
std::vector<pp::Rect> formatted_rects(page_sizes.size());
|
||||
page_rects_.resize(page_sizes.size());
|
||||
for (size_t i = 0; i < page_sizes.size(); ++i) {
|
||||
draw_utils::PageInsetSizes page_insets =
|
||||
draw_utils::GetPageInsetsForTwoUpView(
|
||||
@ -76,10 +74,10 @@ std::vector<pp::Rect> DocumentLayout::GetTwoUpViewLayout(
|
||||
const pp::Size& page_size = page_sizes[i];
|
||||
|
||||
if (i % 2 == 0) {
|
||||
formatted_rects[i] = draw_utils::GetLeftRectForTwoUpView(
|
||||
page_rects_[i] = draw_utils::GetLeftRectForTwoUpView(
|
||||
page_size, {size_.width(), size_.height()}, page_insets);
|
||||
} else {
|
||||
formatted_rects[i] = draw_utils::GetRightRectForTwoUpView(
|
||||
page_rects_[i] = draw_utils::GetRightRectForTwoUpView(
|
||||
page_size, {size_.width(), size_.height()}, page_insets);
|
||||
EnlargeHeight(std::max(page_size.height(), page_sizes[i - 1].height()));
|
||||
}
|
||||
@ -90,8 +88,6 @@ std::vector<pp::Rect> DocumentLayout::GetTwoUpViewLayout(
|
||||
}
|
||||
|
||||
size_.set_width(2 * size_.width());
|
||||
|
||||
return formatted_rects;
|
||||
}
|
||||
|
||||
void DocumentLayout::EnlargeHeight(int height) {
|
||||
@ -99,9 +95,4 @@ void DocumentLayout::EnlargeHeight(int height) {
|
||||
size_.Enlarge(0, height);
|
||||
}
|
||||
|
||||
void DocumentLayout::AppendPageRect(const pp::Size& page_rect) {
|
||||
// TODO(kmoon): Inline draw_utils::ExpandDocumentSize().
|
||||
draw_utils::ExpandDocumentSize(page_rect, &size_);
|
||||
}
|
||||
|
||||
} // namespace chrome_pdf
|
||||
|
@ -5,8 +5,10 @@
|
||||
#ifndef PDF_DOCUMENT_LAYOUT_H_
|
||||
#define PDF_DOCUMENT_LAYOUT_H_
|
||||
|
||||
#include <cstddef>
|
||||
#include <vector>
|
||||
|
||||
#include "base/logging.h"
|
||||
#include "pdf/draw_utils/coordinates.h"
|
||||
#include "pdf/page_orientation.h"
|
||||
#include "ppapi/cpp/rect.h"
|
||||
@ -68,33 +70,41 @@ class DocumentLayout final {
|
||||
const pp::Size& size() const { return size_; }
|
||||
|
||||
// Sets the layout's total size.
|
||||
//
|
||||
// TODO(kmoon): Get rid of this method.
|
||||
void set_size(const pp::Size& size) { size_ = size; }
|
||||
|
||||
// Given |page_sizes|, return pp::Rects that represent |page_sizes|
|
||||
// formatted for single view and update the layout's size to the size of
|
||||
// the new single view layout.
|
||||
std::vector<pp::Rect> GetSingleViewLayout(
|
||||
const std::vector<pp::Size>& page_sizes);
|
||||
size_t page_count() const { return page_rects_.size(); }
|
||||
|
||||
// Given |page_sizes|, return pp::Rects that represent |page_sizes|
|
||||
// formatted for two-up view and update the layout's size to the size of
|
||||
// the new two-up view layout.
|
||||
std::vector<pp::Rect> GetTwoUpViewLayout(
|
||||
const std::vector<pp::Size>& page_sizes);
|
||||
// Gets the layout rectangle for a page. Only valid after computing a layout.
|
||||
const pp::Rect& page_rect(size_t page_index) const {
|
||||
DCHECK_LT(page_index, page_count());
|
||||
return page_rects_[page_index];
|
||||
}
|
||||
|
||||
// Computes layout that represent |page_sizes| formatted for single view.
|
||||
//
|
||||
// TODO(kmoon): Control layout type using an option.
|
||||
void ComputeSingleViewLayout(const std::vector<pp::Size>& page_sizes);
|
||||
|
||||
// Computes layout that represent |page_sizes| formatted for two-up view.
|
||||
//
|
||||
// TODO(kmoon): Control layout type using an option.
|
||||
void ComputeTwoUpViewLayout(const std::vector<pp::Size>& page_sizes);
|
||||
|
||||
// Increases the layout's total height by |height|.
|
||||
//
|
||||
// TODO(kmoon): Delete or make this private.
|
||||
void EnlargeHeight(int height);
|
||||
|
||||
// Appends a rectangle of size |page_rect| to the layout. This will increase
|
||||
// the layout's height by the page's height, and increase the layout's width
|
||||
// to at least the page's width.
|
||||
void AppendPageRect(const pp::Size& page_rect);
|
||||
|
||||
private:
|
||||
Options options_;
|
||||
|
||||
// Layout's total size.
|
||||
pp::Size size_;
|
||||
|
||||
// Page layout rectangles.
|
||||
std::vector<pp::Rect> page_rects_;
|
||||
};
|
||||
|
||||
} // namespace chrome_pdf
|
||||
|
@ -96,6 +96,7 @@ TEST_F(DocumentLayoutTest, DefaultConstructor) {
|
||||
EXPECT_EQ(layout_.options().default_page_orientation(),
|
||||
PageOrientation::kOriginal);
|
||||
EXPECT_PRED2(PpSizeEq, layout_.size(), pp::Size(0, 0));
|
||||
EXPECT_EQ(layout_.page_count(), 0u);
|
||||
}
|
||||
|
||||
TEST_F(DocumentLayoutTest, SetOptionsDoesNotRecomputeLayout) {
|
||||
@ -117,64 +118,59 @@ TEST_F(DocumentLayoutTest, EnlargeHeight) {
|
||||
EXPECT_PRED2(PpSizeEq, layout_.size(), pp::Size(0, 16));
|
||||
}
|
||||
|
||||
TEST_F(DocumentLayoutTest, GetSingleViewLayout) {
|
||||
std::vector<pp::Rect> single_view_layout;
|
||||
|
||||
TEST_F(DocumentLayoutTest, ComputeSingleViewLayout) {
|
||||
std::vector<pp::Size> page_sizes{
|
||||
{300, 400}, {400, 500}, {300, 400}, {200, 300}};
|
||||
single_view_layout = layout_.GetSingleViewLayout(page_sizes);
|
||||
ASSERT_EQ(4u, single_view_layout.size());
|
||||
EXPECT_PRED2(PpRectEq, pp::Rect(55, 3, 290, 390), single_view_layout[0]);
|
||||
EXPECT_PRED2(PpRectEq, pp::Rect(5, 407, 390, 490), single_view_layout[1]);
|
||||
EXPECT_PRED2(PpRectEq, pp::Rect(55, 911, 290, 390), single_view_layout[2]);
|
||||
EXPECT_PRED2(PpRectEq, pp::Rect(105, 1315, 190, 290), single_view_layout[3]);
|
||||
layout_.ComputeSingleViewLayout(page_sizes);
|
||||
ASSERT_EQ(4u, layout_.page_count());
|
||||
EXPECT_PRED2(PpRectEq, pp::Rect(55, 3, 290, 390), layout_.page_rect(0));
|
||||
EXPECT_PRED2(PpRectEq, pp::Rect(5, 407, 390, 490), layout_.page_rect(1));
|
||||
EXPECT_PRED2(PpRectEq, pp::Rect(55, 911, 290, 390), layout_.page_rect(2));
|
||||
EXPECT_PRED2(PpRectEq, pp::Rect(105, 1315, 190, 290), layout_.page_rect(3));
|
||||
EXPECT_PRED2(PpSizeEq, pp::Size(400, 1612), layout_.size());
|
||||
|
||||
page_sizes = {{240, 300}, {320, 400}, {250, 360}, {300, 600}, {270, 555}};
|
||||
single_view_layout = layout_.GetSingleViewLayout(page_sizes);
|
||||
ASSERT_EQ(5u, single_view_layout.size());
|
||||
EXPECT_PRED2(PpRectEq, pp::Rect(45, 3, 230, 290), single_view_layout[0]);
|
||||
EXPECT_PRED2(PpRectEq, pp::Rect(5, 307, 310, 390), single_view_layout[1]);
|
||||
EXPECT_PRED2(PpRectEq, pp::Rect(40, 711, 240, 350), single_view_layout[2]);
|
||||
EXPECT_PRED2(PpRectEq, pp::Rect(15, 1075, 290, 590), single_view_layout[3]);
|
||||
EXPECT_PRED2(PpRectEq, pp::Rect(30, 1679, 260, 545), single_view_layout[4]);
|
||||
layout_.ComputeSingleViewLayout(page_sizes);
|
||||
ASSERT_EQ(5u, layout_.page_count());
|
||||
EXPECT_PRED2(PpRectEq, pp::Rect(45, 3, 230, 290), layout_.page_rect(0));
|
||||
EXPECT_PRED2(PpRectEq, pp::Rect(5, 307, 310, 390), layout_.page_rect(1));
|
||||
EXPECT_PRED2(PpRectEq, pp::Rect(40, 711, 240, 350), layout_.page_rect(2));
|
||||
EXPECT_PRED2(PpRectEq, pp::Rect(15, 1075, 290, 590), layout_.page_rect(3));
|
||||
EXPECT_PRED2(PpRectEq, pp::Rect(30, 1679, 260, 545), layout_.page_rect(4));
|
||||
EXPECT_PRED2(PpSizeEq, pp::Size(320, 2231), layout_.size());
|
||||
}
|
||||
|
||||
TEST_F(DocumentLayoutTest, GetTwoUpViewLayout) {
|
||||
std::vector<pp::Rect> two_up_view_layout;
|
||||
|
||||
TEST_F(DocumentLayoutTest, ComputeTwoUpViewLayout) {
|
||||
// Test case where the widest page is on the right.
|
||||
std::vector<pp::Size> page_sizes{
|
||||
{826, 1066}, {1066, 826}, {826, 1066}, {826, 900}};
|
||||
two_up_view_layout = layout_.GetTwoUpViewLayout(page_sizes);
|
||||
ASSERT_EQ(4u, two_up_view_layout.size());
|
||||
EXPECT_PRED2(PpRectEq, pp::Rect(245, 3, 820, 1056), two_up_view_layout[0]);
|
||||
EXPECT_PRED2(PpRectEq, pp::Rect(1067, 3, 1060, 816), two_up_view_layout[1]);
|
||||
EXPECT_PRED2(PpRectEq, pp::Rect(245, 1069, 820, 1056), two_up_view_layout[2]);
|
||||
EXPECT_PRED2(PpRectEq, pp::Rect(1067, 1069, 820, 890), two_up_view_layout[3]);
|
||||
layout_.ComputeTwoUpViewLayout(page_sizes);
|
||||
ASSERT_EQ(4u, layout_.page_count());
|
||||
EXPECT_PRED2(PpRectEq, pp::Rect(245, 3, 820, 1056), layout_.page_rect(0));
|
||||
EXPECT_PRED2(PpRectEq, pp::Rect(1067, 3, 1060, 816), layout_.page_rect(1));
|
||||
EXPECT_PRED2(PpRectEq, pp::Rect(245, 1069, 820, 1056), layout_.page_rect(2));
|
||||
EXPECT_PRED2(PpRectEq, pp::Rect(1067, 1069, 820, 890), layout_.page_rect(3));
|
||||
EXPECT_PRED2(PpSizeEq, pp::Size(2132, 2132), layout_.size());
|
||||
|
||||
// Test case where the widest page is on the left.
|
||||
page_sizes = {{1066, 826}, {820, 1056}, {820, 890}, {826, 1066}};
|
||||
two_up_view_layout = layout_.GetTwoUpViewLayout(page_sizes);
|
||||
ASSERT_EQ(4u, two_up_view_layout.size());
|
||||
EXPECT_PRED2(PpRectEq, pp::Rect(5, 3, 1060, 816), two_up_view_layout[0]);
|
||||
EXPECT_PRED2(PpRectEq, pp::Rect(1067, 3, 814, 1046), two_up_view_layout[1]);
|
||||
EXPECT_PRED2(PpRectEq, pp::Rect(251, 1059, 814, 880), two_up_view_layout[2]);
|
||||
EXPECT_PRED2(PpRectEq, pp::Rect(1067, 1059, 820, 1056),
|
||||
two_up_view_layout[3]);
|
||||
layout_.ComputeTwoUpViewLayout(page_sizes);
|
||||
ASSERT_EQ(4u, layout_.page_count());
|
||||
EXPECT_PRED2(PpRectEq, pp::Rect(5, 3, 1060, 816), layout_.page_rect(0));
|
||||
EXPECT_PRED2(PpRectEq, pp::Rect(1067, 3, 814, 1046), layout_.page_rect(1));
|
||||
EXPECT_PRED2(PpRectEq, pp::Rect(251, 1059, 814, 880), layout_.page_rect(2));
|
||||
EXPECT_PRED2(PpRectEq, pp::Rect(1067, 1059, 820, 1056), layout_.page_rect(3));
|
||||
EXPECT_PRED2(PpSizeEq, pp::Size(2132, 2122), layout_.size());
|
||||
|
||||
// Test case where there's an odd # of pages.
|
||||
page_sizes = {{200, 300}, {400, 200}, {300, 600}, {250, 500}, {300, 400}};
|
||||
two_up_view_layout = layout_.GetTwoUpViewLayout(page_sizes);
|
||||
ASSERT_EQ(5u, two_up_view_layout.size());
|
||||
EXPECT_PRED2(PpRectEq, pp::Rect(205, 3, 194, 290), two_up_view_layout[0]);
|
||||
EXPECT_PRED2(PpRectEq, pp::Rect(401, 3, 394, 190), two_up_view_layout[1]);
|
||||
EXPECT_PRED2(PpRectEq, pp::Rect(105, 303, 294, 590), two_up_view_layout[2]);
|
||||
EXPECT_PRED2(PpRectEq, pp::Rect(401, 303, 244, 490), two_up_view_layout[3]);
|
||||
EXPECT_PRED2(PpRectEq, pp::Rect(105, 903, 290, 390), two_up_view_layout[4]);
|
||||
layout_.ComputeTwoUpViewLayout(page_sizes);
|
||||
ASSERT_EQ(5u, layout_.page_count());
|
||||
EXPECT_PRED2(PpRectEq, pp::Rect(205, 3, 194, 290), layout_.page_rect(0));
|
||||
EXPECT_PRED2(PpRectEq, pp::Rect(401, 3, 394, 190), layout_.page_rect(1));
|
||||
EXPECT_PRED2(PpRectEq, pp::Rect(105, 303, 294, 590), layout_.page_rect(2));
|
||||
EXPECT_PRED2(PpRectEq, pp::Rect(401, 303, 244, 490), layout_.page_rect(3));
|
||||
EXPECT_PRED2(PpRectEq, pp::Rect(105, 903, 290, 390), layout_.page_rect(4));
|
||||
EXPECT_PRED2(PpSizeEq, pp::Size(800, 1300), layout_.size());
|
||||
}
|
||||
|
||||
@ -182,17 +178,6 @@ TEST_F(DocumentLayoutDeathTest, EnlargeHeightNegativeIncrement) {
|
||||
EXPECT_DCHECK_DEATH(layout_.EnlargeHeight(-5));
|
||||
}
|
||||
|
||||
TEST_F(DocumentLayoutTest, AppendPageRect) {
|
||||
layout_.AppendPageRect(pp::Size(3, 5));
|
||||
EXPECT_PRED2(PpSizeEq, layout_.size(), pp::Size(3, 5));
|
||||
|
||||
layout_.AppendPageRect(pp::Size(7, 11));
|
||||
EXPECT_PRED2(PpSizeEq, layout_.size(), pp::Size(7, 16));
|
||||
|
||||
layout_.AppendPageRect(pp::Size(5, 11));
|
||||
EXPECT_PRED2(PpSizeEq, layout_.size(), pp::Size(7, 27));
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
} // namespace chrome_pdf
|
||||
|
@ -2229,6 +2229,7 @@ bool PDFiumEngine::GetPageSizeAndUniformity(pp::Size* size) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// TODO(kmoon): Rewrite this to use DocumentLayout properly.
|
||||
void PDFiumEngine::AppendBlankPages(int num_pages) {
|
||||
DCHECK_NE(num_pages, 0);
|
||||
|
||||
@ -2388,36 +2389,33 @@ void PDFiumEngine::ContinueLoadingDocument(const std::string& password) {
|
||||
FinishLoadingDocument();
|
||||
}
|
||||
|
||||
void PDFiumEngine::AppendPageRectToPages(const pp::Rect& page_rect,
|
||||
size_t page_index,
|
||||
bool reload) {
|
||||
if (!reload) {
|
||||
// The page is marked as not being available even if |doc_complete| is
|
||||
// true because FPDFAvail_IsPageAvail() still has to be called for this
|
||||
// page, which will be done in FinishLoadingDocument().
|
||||
pages_.push_back(
|
||||
std::make_unique<PDFiumPage>(this, page_index, page_rect, false));
|
||||
} else if (page_index < pages_.size()) {
|
||||
pages_[page_index]->set_rect(page_rect);
|
||||
} else {
|
||||
bool available =
|
||||
FPDFAvail_IsPageAvail(fpdf_availability(), page_index, nullptr);
|
||||
pages_.push_back(
|
||||
std::make_unique<PDFiumPage>(this, page_index, page_rect, available));
|
||||
}
|
||||
}
|
||||
|
||||
void PDFiumEngine::LoadPagesInCurrentLayout(std::vector<pp::Size> page_sizes,
|
||||
bool reload) {
|
||||
std::vector<pp::Rect> formatted_pages;
|
||||
if (two_up_view_) {
|
||||
formatted_pages = layout_.GetTwoUpViewLayout(page_sizes);
|
||||
layout_.ComputeTwoUpViewLayout(page_sizes);
|
||||
} else {
|
||||
formatted_pages = layout_.GetSingleViewLayout(page_sizes);
|
||||
layout_.ComputeSingleViewLayout(page_sizes);
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < formatted_pages.size(); ++i) {
|
||||
AppendPageRectToPages(formatted_pages[i], i, reload);
|
||||
ApplyCurrentLayoutToPages(reload);
|
||||
}
|
||||
|
||||
// TODO(kmoon): This should be the only method that sets |PDFiumPage::rect_|.
|
||||
void PDFiumEngine::ApplyCurrentLayoutToPages(bool reload) {
|
||||
for (size_t i = 0; i < layout_.page_count(); ++i) {
|
||||
const pp::Rect& page_rect = layout_.page_rect(i);
|
||||
if (!reload) {
|
||||
// The page is marked as not being available even if |doc_complete| is
|
||||
// true because FPDFAvail_IsPageAvail() still has to be called for this
|
||||
// page, which will be done in FinishLoadingDocument().
|
||||
pages_.push_back(std::make_unique<PDFiumPage>(this, i, page_rect, false));
|
||||
} else if (i < pages_.size()) {
|
||||
pages_[i]->set_rect(page_rect);
|
||||
} else {
|
||||
bool available = FPDFAvail_IsPageAvail(fpdf_availability(), i, nullptr);
|
||||
pages_.push_back(
|
||||
std::make_unique<PDFiumPage>(this, i, page_rect, available));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -235,16 +235,19 @@ class PDFiumEngine : public PDFEngine,
|
||||
// If this has been run once, it will not notify the client again.
|
||||
void FinishLoadingDocument();
|
||||
|
||||
// Appends a PDFiumPage with |page_rect| to |pages_| or sets existing
|
||||
// PDFiumPage for |page_index| to |page_rect|. |page_index| is 0-based.
|
||||
void AppendPageRectToPages(const pp::Rect& page_rect,
|
||||
size_t page_index,
|
||||
bool reload);
|
||||
|
||||
// Formats the pages of |page_sizes| and appends them to |pages_|. Formats to
|
||||
// two-up view if |two_up_view_| is true, else formats to single-view.
|
||||
void LoadPagesInCurrentLayout(std::vector<pp::Size> page_sizes, bool reload);
|
||||
|
||||
// Applies the current layout to the PDFiumPage objects. This primarily
|
||||
// involves updating the PDFiumPage rectangles from the corresponding layout
|
||||
// page rectangles.
|
||||
//
|
||||
// TODO(kmoon): Conceivably, the PDFiumPages wouldn't need to store page
|
||||
// rectangles at all, and we could get rid of this step. This is a pretty
|
||||
// involved change, however.
|
||||
void ApplyCurrentLayoutToPages(bool reload);
|
||||
|
||||
// Loads information about the pages in the document and calculate the
|
||||
// document size.
|
||||
void LoadPageInfo(bool reload);
|
||||
|
Reference in New Issue
Block a user