Commit eb9e000c authored by K Moon's avatar K Moon Committed by Commit Bot

Split options from chrome_pdf::DocumentLayout

Due to the loose, asynchronous coupling between the C++ and JavaScript
portions of the layout code, we need to pass certain layout "options"
(such as the default page orientation) back and forth by value.

As a result, it makes sense to have a separate Options class to hold
these settings, which then can be used to recalculate the layout.

The expected layout lifecycle eventually should look like this:
1. Update desired layout options one or more times.
2. Estimate layout size with new layout options.
3. Send options and estimated size to JavaScript.
4. Receive updated options from JavaScript.
5. Apply final options to current layout.
6. Repaint using updated layout.

As a side effect of this change, I added the desired_layout_options_
field to PDFiumEngine. This new field holds the mutable state about
page orientation that was split off into DocumentLayout::Options.

Miscellaneous changes:
* Revised some of the API comments for DocumentLayout
* Eliminated need for unsigned math by replacing -1 with +3 (mod 4)
* DocumentLayout no longer needs to be copyable, so it isn't

Bug: 885110
Change-Id: I89714c4c2cba6c0ab354c0696ec3943327c979d0
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1733795
Commit-Queue: K Moon <kmoon@chromium.org>
Reviewed-by: default avatarLei Zhang <thestig@chromium.org>
Cr-Commit-Position: refs/heads/master@{#684441}
parent f2ea3ba5
...@@ -11,22 +11,27 @@ namespace chrome_pdf { ...@@ -11,22 +11,27 @@ namespace chrome_pdf {
const draw_utils::PageInsetSizes DocumentLayout::kSingleViewInsets{ const draw_utils::PageInsetSizes DocumentLayout::kSingleViewInsets{
/*left=*/5, /*top=*/3, /*right=*/5, /*bottom=*/7}; /*left=*/5, /*top=*/3, /*right=*/5, /*bottom=*/7};
DocumentLayout::DocumentLayout() = default; DocumentLayout::Options::Options() = default;
DocumentLayout::DocumentLayout(const DocumentLayout& other) = default; DocumentLayout::Options::Options(const Options& other) = default;
DocumentLayout& DocumentLayout::operator=(const DocumentLayout& other) = DocumentLayout::Options& DocumentLayout::Options::operator=(
default; const Options& other) = default;
DocumentLayout::~DocumentLayout() = default; DocumentLayout::Options::~Options() = default;
void DocumentLayout::RotatePagesClockwise() { void DocumentLayout::Options::RotatePagesClockwise() {
default_page_orientation_ = (default_page_orientation_ + 1) % 4; default_page_orientation_ = (default_page_orientation_ + 1) % 4;
} }
void DocumentLayout::RotatePagesCounterclockwise() { void DocumentLayout::Options::RotatePagesCounterclockwise() {
default_page_orientation_ = (default_page_orientation_ - 1) % 4; // Use the modular additive inverse of -1 to avoid negative values.
default_page_orientation_ = (default_page_orientation_ + 3) % 4;
} }
DocumentLayout::DocumentLayout() = default;
DocumentLayout::~DocumentLayout() = default;
std::vector<pp::Rect> DocumentLayout::GetTwoUpViewLayout( std::vector<pp::Rect> DocumentLayout::GetTwoUpViewLayout(
const std::vector<pp::Rect>& page_rects) { const std::vector<pp::Rect>& page_rects) {
std::vector<pp::Rect> formatted_rects(page_rects.size()); std::vector<pp::Rect> formatted_rects(page_rects.size());
......
...@@ -17,33 +17,57 @@ namespace chrome_pdf { ...@@ -17,33 +17,57 @@ namespace chrome_pdf {
// (possibly rotated) in a non-overlapping vertical sequence. // (possibly rotated) in a non-overlapping vertical sequence.
// //
// All layout units are pixels. // All layout units are pixels.
//
// The |Options| class controls the behavior of the layout, such as the default
// orientation of pages.
class DocumentLayout final { class DocumentLayout final {
public: public:
// Options controlling layout behavior.
class Options final {
public:
Options();
Options(const Options& other);
Options& operator=(const Options& other);
~Options();
// Returns the default page orientation, encoded as an integer from 0 to 3
// (inclusive).
//
// A return value of 0 indicates the original page orientation, with each
// increment indicating clockwise rotation by an additional 90 degrees.
//
// TODO(kmoon): Return an enum (class) instead of an integer.
int 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();
private:
// Orientations are non-negative integers modulo 4.
int default_page_orientation_ = 0;
};
static const draw_utils::PageInsetSizes kSingleViewInsets; static const draw_utils::PageInsetSizes kSingleViewInsets;
static constexpr int32_t kBottomSeparator = 4; static constexpr int32_t kBottomSeparator = 4;
static constexpr int32_t kHorizontalSeparator = 1; static constexpr int32_t kHorizontalSeparator = 1;
DocumentLayout(); DocumentLayout();
DocumentLayout(const DocumentLayout& other); DocumentLayout(const DocumentLayout& other) = delete;
DocumentLayout& operator=(const DocumentLayout& other); DocumentLayout& operator=(const DocumentLayout& other) = delete;
~DocumentLayout(); ~DocumentLayout();
// Returns an integer from 0 to 3 (inclusive), encoding the default // Returns the layout options.
// orientation of the document's pages. const Options& options() const { return options_; }
//
// A return value of 0 indicates the original page orientation, with each
// increment indicating clockwise rotation by an additional 90 degrees.
//
// TODO(kmoon): Return an enum (class) instead of an integer.
int default_page_orientation() const { return default_page_orientation_; }
// Rotates all pages 90 degrees clockwise. Does not recompute layout.
void RotatePagesClockwise();
// Rotates all pages 90 degrees counterclockwise. Does not recompute layout. // Sets the layout options.
void RotatePagesCounterclockwise(); void set_options(const Options& options) { options_ = options; }
// Returns the layout's total size. // Returns the layout's total size.
const pp::Size& size() const { return size_; } const pp::Size& size() const { return size_; }
...@@ -66,12 +90,7 @@ class DocumentLayout final { ...@@ -66,12 +90,7 @@ class DocumentLayout final {
void AppendPageRect(const pp::Size& page_rect); void AppendPageRect(const pp::Size& page_rect);
private: private:
// Orientations are non-negative integers modulo 4. Options options_;
//
// TODO(kmoon): Doesn't match return type of default_page_orientation().
// Callers expect int, but internally, we want unsigned semantics. This will
// be cleaned up when we switch to an enum.
unsigned int default_page_orientation_ = 0;
// Layout's total size. // Layout's total size.
pp::Size size_; pp::Size size_;
......
...@@ -11,6 +11,11 @@ namespace chrome_pdf { ...@@ -11,6 +11,11 @@ namespace chrome_pdf {
namespace { namespace {
class DocumentLayoutOptionsTest : public testing::Test {
protected:
DocumentLayout::Options options_;
};
class DocumentLayoutTest : public testing::Test { class DocumentLayoutTest : public testing::Test {
protected: protected:
DocumentLayout layout_; DocumentLayout layout_;
...@@ -29,79 +34,73 @@ inline bool PpRectEq(const pp::Rect& lhs, const pp::Rect& rhs) { ...@@ -29,79 +34,73 @@ inline bool PpRectEq(const pp::Rect& lhs, const pp::Rect& rhs) {
return lhs == rhs; return lhs == rhs;
} }
TEST_F(DocumentLayoutTest, DefaultConstructor) { TEST_F(DocumentLayoutOptionsTest, DefaultConstructor) {
EXPECT_EQ(layout_.default_page_orientation(), 0); EXPECT_EQ(options_.default_page_orientation(), 0);
EXPECT_PRED2(PpSizeEq, layout_.size(), pp::Size(0, 0));
} }
TEST_F(DocumentLayoutTest, CopyConstructor) { TEST_F(DocumentLayoutOptionsTest, CopyConstructor) {
layout_.RotatePagesClockwise(); options_.RotatePagesClockwise();
layout_.EnlargeHeight(2);
DocumentLayout copy(layout_); DocumentLayout::Options copy(options_);
EXPECT_EQ(copy.default_page_orientation(), 1); EXPECT_EQ(copy.default_page_orientation(), 1);
EXPECT_PRED2(PpSizeEq, copy.size(), pp::Size(0, 2));
layout_.RotatePagesClockwise(); options_.RotatePagesClockwise();
layout_.EnlargeHeight(5);
EXPECT_EQ(copy.default_page_orientation(), 1); EXPECT_EQ(copy.default_page_orientation(), 1);
EXPECT_PRED2(PpSizeEq, copy.size(), pp::Size(0, 2));
} }
TEST_F(DocumentLayoutTest, CopyAssignment) { TEST_F(DocumentLayoutOptionsTest, CopyAssignment) {
layout_.RotatePagesClockwise(); options_.RotatePagesClockwise();
layout_.EnlargeHeight(2);
DocumentLayout copy; DocumentLayout::Options copy;
EXPECT_EQ(copy.default_page_orientation(), 0); EXPECT_EQ(copy.default_page_orientation(), 0);
EXPECT_PRED2(PpSizeEq, copy.size(), pp::Size(0, 0)); copy = options_;
copy = layout_;
EXPECT_EQ(copy.default_page_orientation(), 1); EXPECT_EQ(copy.default_page_orientation(), 1);
EXPECT_PRED2(PpSizeEq, copy.size(), pp::Size(0, 2));
layout_.RotatePagesClockwise(); options_.RotatePagesClockwise();
layout_.EnlargeHeight(5);
EXPECT_EQ(copy.default_page_orientation(), 1); EXPECT_EQ(copy.default_page_orientation(), 1);
EXPECT_PRED2(PpSizeEq, copy.size(), pp::Size(0, 2));
} }
TEST_F(DocumentLayoutTest, RotatePagesClockwise) { TEST_F(DocumentLayoutOptionsTest, RotatePagesClockwise) {
layout_.RotatePagesClockwise(); options_.RotatePagesClockwise();
EXPECT_EQ(layout_.default_page_orientation(), 1); EXPECT_EQ(options_.default_page_orientation(), 1);
layout_.RotatePagesClockwise(); options_.RotatePagesClockwise();
EXPECT_EQ(layout_.default_page_orientation(), 2); EXPECT_EQ(options_.default_page_orientation(), 2);
layout_.RotatePagesClockwise(); options_.RotatePagesClockwise();
EXPECT_EQ(layout_.default_page_orientation(), 3); EXPECT_EQ(options_.default_page_orientation(), 3);
layout_.RotatePagesClockwise(); options_.RotatePagesClockwise();
EXPECT_EQ(layout_.default_page_orientation(), 0); EXPECT_EQ(options_.default_page_orientation(), 0);
} }
TEST_F(DocumentLayoutTest, RotatePagesCounterclockwise) { TEST_F(DocumentLayoutOptionsTest, RotatePagesCounterclockwise) {
layout_.RotatePagesCounterclockwise(); options_.RotatePagesCounterclockwise();
EXPECT_EQ(layout_.default_page_orientation(), 3); EXPECT_EQ(options_.default_page_orientation(), 3);
layout_.RotatePagesCounterclockwise(); options_.RotatePagesCounterclockwise();
EXPECT_EQ(layout_.default_page_orientation(), 2); EXPECT_EQ(options_.default_page_orientation(), 2);
layout_.RotatePagesCounterclockwise(); options_.RotatePagesCounterclockwise();
EXPECT_EQ(layout_.default_page_orientation(), 1); EXPECT_EQ(options_.default_page_orientation(), 1);
layout_.RotatePagesCounterclockwise(); options_.RotatePagesCounterclockwise();
EXPECT_EQ(layout_.default_page_orientation(), 0); EXPECT_EQ(options_.default_page_orientation(), 0);
} }
TEST_F(DocumentLayoutTest, RotatePagesDoesNotRecomputeLayout) { TEST_F(DocumentLayoutTest, DefaultConstructor) {
layout_.EnlargeHeight(2); EXPECT_EQ(layout_.options().default_page_orientation(), 0);
EXPECT_PRED2(PpSizeEq, layout_.size(), pp::Size(0, 0));
}
layout_.RotatePagesClockwise(); TEST_F(DocumentLayoutTest, SetOptionsDoesNotRecomputeLayout) {
EXPECT_PRED2(PpSizeEq, layout_.size(), pp::Size(0, 2)); layout_.set_size(pp::Size(1, 2));
layout_.RotatePagesCounterclockwise(); DocumentLayout::Options options;
EXPECT_PRED2(PpSizeEq, layout_.size(), pp::Size(0, 2)); options.RotatePagesClockwise();
layout_.set_options(options);
EXPECT_EQ(layout_.options().default_page_orientation(), 1);
EXPECT_PRED2(PpSizeEq, layout_.size(), pp::Size(1, 2));
} }
TEST_F(DocumentLayoutTest, EnlargeHeight) { TEST_F(DocumentLayoutTest, EnlargeHeight) {
......
...@@ -973,8 +973,8 @@ PDFiumPage::Area PDFiumEngine::GetCharIndex(const pp::Point& point, ...@@ -973,8 +973,8 @@ PDFiumPage::Area PDFiumEngine::GetCharIndex(const pp::Point& point,
*page_index = page; *page_index = page;
PDFiumPage::Area result = pages_[page]->GetCharIndex( PDFiumPage::Area result = pages_[page]->GetCharIndex(
point_in_page, layout_.default_page_orientation(), char_index, form_type, point_in_page, layout_.options().default_page_orientation(), char_index,
target); form_type, target);
return (client_->IsPrintPreview() && result == PDFiumPage::WEBLINK_AREA) return (client_->IsPrintPreview() && result == PDFiumPage::WEBLINK_AREA)
? PDFiumPage::NONSELECTABLE_AREA ? PDFiumPage::NONSELECTABLE_AREA
: result; : result;
...@@ -1818,7 +1818,7 @@ bool PDFiumEngine::SelectFindResult(bool forward) { ...@@ -1818,7 +1818,7 @@ bool PDFiumEngine::SelectFindResult(bool forward) {
// Use zoom of 1.0 since |visible_rect| is without zoom. // Use zoom of 1.0 since |visible_rect| is without zoom.
const std::vector<pp::Rect>& rects = const std::vector<pp::Rect>& rects =
find_results_[current_find_index_.value()].GetScreenRects( find_results_[current_find_index_.value()].GetScreenRects(
pp::Point(), 1.0, layout_.default_page_orientation()); pp::Point(), 1.0, layout_.options().default_page_orientation());
for (const auto& rect : rects) for (const auto& rect : rects)
bounding_rect = bounding_rect.Union(rect); bounding_rect = bounding_rect.Union(rect);
if (!visible_rect.Contains(bounding_rect)) { if (!visible_rect.Contains(bounding_rect)) {
...@@ -1865,8 +1865,9 @@ void PDFiumEngine::GetAllScreenRectsUnion( ...@@ -1865,8 +1865,9 @@ void PDFiumEngine::GetAllScreenRectsUnion(
std::vector<pp::Rect>* rect_vector) const { std::vector<pp::Rect>* rect_vector) const {
for (const auto& range : rect_range) { for (const auto& range : rect_range) {
pp::Rect result_rect; pp::Rect result_rect;
const std::vector<pp::Rect>& rects = range.GetScreenRects( const std::vector<pp::Rect>& rects =
offset_point, current_zoom_, layout_.default_page_orientation()); range.GetScreenRects(offset_point, current_zoom_,
layout_.options().default_page_orientation());
for (const auto& rect : rects) for (const auto& rect : rects)
result_rect = result_rect.Union(rect); result_rect = result_rect.Union(rect);
rect_vector->push_back(result_rect); rect_vector->push_back(result_rect);
...@@ -1889,12 +1890,12 @@ void PDFiumEngine::ZoomUpdated(double new_zoom_level) { ...@@ -1889,12 +1890,12 @@ void PDFiumEngine::ZoomUpdated(double new_zoom_level) {
} }
void PDFiumEngine::RotateClockwise() { void PDFiumEngine::RotateClockwise() {
layout_.RotatePagesClockwise(); desired_layout_options_.RotatePagesClockwise();
RotateInternal(); RotateInternal();
} }
void PDFiumEngine::RotateCounterclockwise() { void PDFiumEngine::RotateCounterclockwise() {
layout_.RotatePagesCounterclockwise(); desired_layout_options_.RotatePagesCounterclockwise();
RotateInternal(); RotateInternal();
} }
...@@ -2635,7 +2636,7 @@ pp::Size PDFiumEngine::GetPageSize(int index) { ...@@ -2635,7 +2636,7 @@ pp::Size PDFiumEngine::GetPageSize(int index) {
ConvertUnitDouble(width_in_points, kPointsPerInch, kPixelsPerInch)); ConvertUnitDouble(width_in_points, kPointsPerInch, kPixelsPerInch));
int height_in_pixels = static_cast<int>( int height_in_pixels = static_cast<int>(
ConvertUnitDouble(height_in_points, kPointsPerInch, kPixelsPerInch)); ConvertUnitDouble(height_in_points, kPointsPerInch, kPixelsPerInch));
if (layout_.default_page_orientation() % 2 == 1) if (layout_.options().default_page_orientation() % 2 == 1)
std::swap(width_in_pixels, height_in_pixels); std::swap(width_in_pixels, height_in_pixels);
size = pp::Size(width_in_pixels, height_in_pixels); size = pp::Size(width_in_pixels, height_in_pixels);
} }
...@@ -2732,7 +2733,8 @@ bool PDFiumEngine::ContinuePaint(int progressive_index, ...@@ -2732,7 +2733,8 @@ bool PDFiumEngine::ContinuePaint(int progressive_index,
0xFFFFFFFF); 0xFFFFFFFF);
rv = FPDF_RenderPageBitmap_Start( rv = FPDF_RenderPageBitmap_Start(
new_bitmap.get(), page, start_x, start_y, size_x, size_y, new_bitmap.get(), page, start_x, start_y, size_x, size_y,
layout_.default_page_orientation(), GetRenderingFlags(), this); layout_.options().default_page_orientation(), GetRenderingFlags(),
this);
progressive_paints_[progressive_index].SetBitmapAndImageData( progressive_paints_[progressive_index].SetBitmapAndImageData(
std::move(new_bitmap), *image_data); std::move(new_bitmap), *image_data);
} }
...@@ -2759,7 +2761,7 @@ void PDFiumEngine::FinishPaint(int progressive_index, ...@@ -2759,7 +2761,7 @@ void PDFiumEngine::FinishPaint(int progressive_index,
// Draw the forms. // Draw the forms.
FPDF_FFLDraw(form(), bitmap, pages_[page_index]->GetPage(), start_x, start_y, FPDF_FFLDraw(form(), bitmap, pages_[page_index]->GetPage(), start_x, start_y,
size_x, size_y, layout_.default_page_orientation(), size_x, size_y, layout_.options().default_page_orientation(),
GetRenderingFlags()); GetRenderingFlags());
FillPageSides(progressive_index); FillPageSides(progressive_index);
...@@ -2890,7 +2892,7 @@ void PDFiumEngine::DrawSelections(int progressive_index, ...@@ -2890,7 +2892,7 @@ void PDFiumEngine::DrawSelections(int progressive_index,
const std::vector<pp::Rect>& rects = const std::vector<pp::Rect>& rects =
range.GetScreenRects(visible_rect.point(), current_zoom_, range.GetScreenRects(visible_rect.point(), current_zoom_,
layout_.default_page_orientation()); layout_.options().default_page_orientation());
for (const auto& rect : rects) { for (const auto& rect : rects) {
pp::Rect visible_selection = rect.Intersect(dirty_in_screen); pp::Rect visible_selection = rect.Intersect(dirty_in_screen);
if (visible_selection.IsEmpty()) if (visible_selection.IsEmpty())
...@@ -3111,9 +3113,9 @@ PDFiumEngine::SelectionChangeInvalidator::GetVisibleSelections() const { ...@@ -3111,9 +3113,9 @@ PDFiumEngine::SelectionChangeInvalidator::GetVisibleSelections() const {
if (!engine_->IsPageVisible(range.page_index())) if (!engine_->IsPageVisible(range.page_index()))
continue; continue;
const std::vector<pp::Rect>& selection_rects = const std::vector<pp::Rect>& selection_rects = range.GetScreenRects(
range.GetScreenRects(visible_point, engine_->current_zoom_, visible_point, engine_->current_zoom_,
engine_->layout_.default_page_orientation()); engine_->layout_.options().default_page_orientation());
rects.insert(rects.end(), selection_rects.begin(), selection_rects.end()); rects.insert(rects.end(), selection_rects.begin(), selection_rects.end());
} }
return rects; return rects;
...@@ -3172,8 +3174,9 @@ void PDFiumEngine::DeviceToPage(int page_index, ...@@ -3172,8 +3174,9 @@ void PDFiumEngine::DeviceToPage(int page_index,
pages_[page_index]->rect().y()); pages_[page_index]->rect().y());
FPDF_BOOL ret = FPDF_DeviceToPage( FPDF_BOOL ret = FPDF_DeviceToPage(
pages_[page_index]->GetPage(), 0, 0, pages_[page_index]->rect().width(), pages_[page_index]->GetPage(), 0, 0, pages_[page_index]->rect().width(),
pages_[page_index]->rect().height(), layout_.default_page_orientation(), pages_[page_index]->rect().height(),
temp_x, temp_y, page_x, page_y); layout_.options().default_page_orientation(), temp_x, temp_y, page_x,
page_y);
DCHECK(ret); DCHECK(ret);
} }
...@@ -3281,7 +3284,7 @@ void PDFiumEngine::OnSelectionPositionChanged() { ...@@ -3281,7 +3284,7 @@ void PDFiumEngine::OnSelectionPositionChanged() {
for (const auto& sel : selection_) { for (const auto& sel : selection_) {
const std::vector<pp::Rect>& screen_rects = const std::vector<pp::Rect>& screen_rects =
sel.GetScreenRects(GetVisibleRect().point(), current_zoom_, sel.GetScreenRects(GetVisibleRect().point(), current_zoom_,
layout_.default_page_orientation()); layout_.options().default_page_orientation());
for (const auto& rect : screen_rects) { for (const auto& rect : screen_rects) {
if (IsAboveOrDirectlyLeftOf(rect, left)) if (IsAboveOrDirectlyLeftOf(rect, left))
left = rect; left = rect;
...@@ -3306,6 +3309,7 @@ void PDFiumEngine::RotateInternal() { ...@@ -3306,6 +3309,7 @@ void PDFiumEngine::RotateInternal() {
// Save the current page. // Save the current page.
int most_visible_page = most_visible_page_; int most_visible_page = most_visible_page_;
layout_.set_options(desired_layout_options_);
InvalidateAllPages(); InvalidateAllPages();
// Restore find results. // Restore find results.
......
...@@ -529,6 +529,9 @@ class PDFiumEngine : public PDFEngine, ...@@ -529,6 +529,9 @@ class PDFiumEngine : public PDFEngine,
// The current document layout. // The current document layout.
DocumentLayout layout_; DocumentLayout layout_;
// The options for the desired document layout.
DocumentLayout::Options desired_layout_options_;
// The scroll position in screen coordinates. // The scroll position in screen coordinates.
pp::Point position_; pp::Point position_;
// The offset of the page into the viewport. // The offset of the page into the viewport.
......
...@@ -100,7 +100,7 @@ void PDFiumFormFiller::Form_Invalidate(FPDF_FORMFILLINFO* param, ...@@ -100,7 +100,7 @@ void PDFiumFormFiller::Form_Invalidate(FPDF_FORMFILLINFO* param,
pp::Rect rect = engine->pages_[page_index]->PageToScreen( pp::Rect rect = engine->pages_[page_index]->PageToScreen(
engine->GetVisibleRect().point(), engine->current_zoom_, left, top, right, engine->GetVisibleRect().point(), engine->current_zoom_, left, top, right,
bottom, engine->layout_.default_page_orientation()); bottom, engine->layout_.options().default_page_orientation());
engine->client_->Invalidate(rect); engine->client_->Invalidate(rect);
} }
...@@ -119,7 +119,7 @@ void PDFiumFormFiller::Form_OutputSelectedRect(FPDF_FORMFILLINFO* param, ...@@ -119,7 +119,7 @@ void PDFiumFormFiller::Form_OutputSelectedRect(FPDF_FORMFILLINFO* param,
} }
pp::Rect rect = engine->pages_[page_index]->PageToScreen( pp::Rect rect = engine->pages_[page_index]->PageToScreen(
engine->GetVisibleRect().point(), engine->current_zoom_, left, top, right, engine->GetVisibleRect().point(), engine->current_zoom_, left, top, right,
bottom, engine->layout_.default_page_orientation()); bottom, engine->layout_.options().default_page_orientation());
if (rect.IsEmpty()) if (rect.IsEmpty())
return; return;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment