Commit 145d499a authored by Lei Zhang's avatar Lei Zhang Committed by Commit Bot

Split printing code from PDFiumEngine into PDFiumPrint.

Change-Id: I431828148e9f93eadd290493e848331f996cbd69
Reviewed-on: https://chromium-review.googlesource.com/1043657Reviewed-by: default avatarHenrique Nakashima <hnakashima@chromium.org>
Commit-Queue: Lei Zhang <thestig@chromium.org>
Cr-Commit-Position: refs/heads/master@{#556147}
parent a680f208
...@@ -92,6 +92,8 @@ if (enable_pdf) { ...@@ -92,6 +92,8 @@ if (enable_pdf) {
"pdfium/pdfium_mem_buffer_file_write.h", "pdfium/pdfium_mem_buffer_file_write.h",
"pdfium/pdfium_page.cc", "pdfium/pdfium_page.cc",
"pdfium/pdfium_page.h", "pdfium/pdfium_page.h",
"pdfium/pdfium_print.cc",
"pdfium/pdfium_print.h",
"pdfium/pdfium_range.cc", "pdfium/pdfium_range.cc",
"pdfium/pdfium_range.h", "pdfium/pdfium_range.h",
] ]
......
...@@ -12,16 +12,13 @@ ...@@ -12,16 +12,13 @@
#include <limits> #include <limits>
#include <memory> #include <memory>
#include <set> #include <set>
#include <utility>
#include "base/auto_reset.h" #include "base/auto_reset.h"
#include "base/i18n/encoding_detection.h" #include "base/i18n/encoding_detection.h"
#include "base/i18n/icu_string_conversions.h" #include "base/i18n/icu_string_conversions.h"
#include "base/logging.h" #include "base/logging.h"
#include "base/macros.h"
#include "base/numerics/safe_conversions.h"
#include "base/stl_util.h" #include "base/stl_util.h"
#include "base/strings/string_number_conversions.h"
#include "base/strings/string_piece.h"
#include "base/strings/string_util.h" #include "base/strings/string_util.h"
#include "base/strings/utf_string_conversions.h" #include "base/strings/utf_string_conversions.h"
#include "base/threading/thread_task_runner_handle.h" #include "base/threading/thread_task_runner_handle.h"
...@@ -36,36 +33,20 @@ ...@@ -36,36 +33,20 @@
#include "pdf/pdfium/pdfium_mem_buffer_file_read.h" #include "pdf/pdfium/pdfium_mem_buffer_file_read.h"
#include "pdf/pdfium/pdfium_mem_buffer_file_write.h" #include "pdf/pdfium/pdfium_mem_buffer_file_write.h"
#include "pdf/url_loader_wrapper_impl.h" #include "pdf/url_loader_wrapper_impl.h"
#include "ppapi/c/pp_errors.h"
#include "ppapi/c/pp_input_event.h"
#include "ppapi/c/ppb_core.h"
#include "ppapi/c/private/ppb_pdf.h"
#include "ppapi/cpp/dev/memory_dev.h"
#include "ppapi/cpp/input_event.h"
#include "ppapi/cpp/instance.h" #include "ppapi/cpp/instance.h"
#include "ppapi/cpp/module.h"
#include "ppapi/cpp/private/pdf.h" #include "ppapi/cpp/private/pdf.h"
#include "ppapi/cpp/trusted/browser_font_trusted.h" #include "ppapi/cpp/trusted/browser_font_trusted.h"
#include "ppapi/cpp/url_response_info.h"
#include "ppapi/cpp/var.h"
#include "ppapi/cpp/var_dictionary.h" #include "ppapi/cpp/var_dictionary.h"
#include "printing/nup_parameters.h"
#include "printing/units.h" #include "printing/units.h"
#include "third_party/pdfium/public/cpp/fpdf_scopers.h" #include "third_party/pdfium/public/cpp/fpdf_scopers.h"
#include "third_party/pdfium/public/fpdf_annot.h" #include "third_party/pdfium/public/fpdf_annot.h"
#include "third_party/pdfium/public/fpdf_attachment.h" #include "third_party/pdfium/public/fpdf_attachment.h"
#include "third_party/pdfium/public/fpdf_catalog.h" #include "third_party/pdfium/public/fpdf_catalog.h"
#include "third_party/pdfium/public/fpdf_edit.h"
#include "third_party/pdfium/public/fpdf_ext.h" #include "third_party/pdfium/public/fpdf_ext.h"
#include "third_party/pdfium/public/fpdf_flatten.h"
#include "third_party/pdfium/public/fpdf_ppo.h" #include "third_party/pdfium/public/fpdf_ppo.h"
#include "third_party/pdfium/public/fpdf_save.h"
#include "third_party/pdfium/public/fpdf_searchex.h" #include "third_party/pdfium/public/fpdf_searchex.h"
#include "third_party/pdfium/public/fpdf_sysfontinfo.h" #include "third_party/pdfium/public/fpdf_sysfontinfo.h"
#include "third_party/pdfium/public/fpdf_transformpage.h"
#include "third_party/pdfium/public/fpdfview.h"
#include "ui/events/keycodes/keyboard_codes.h" #include "ui/events/keycodes/keyboard_codes.h"
#include "ui/gfx/codec/jpeg_codec.h"
#include "ui/gfx/geometry/rect.h" #include "ui/gfx/geometry/rect.h"
#include "v8/include/v8.h" #include "v8/include/v8.h"
...@@ -153,19 +134,6 @@ constexpr bool kIsEditModeTracked = false; ...@@ -153,19 +134,6 @@ constexpr bool kIsEditModeTracked = false;
PDFiumEngine* g_engine_for_fontmapper = nullptr; PDFiumEngine* g_engine_for_fontmapper = nullptr;
std::vector<uint32_t> GetPageNumbersFromPrintPageNumberRange(
const PP_PrintPageNumberRange_Dev* page_ranges,
uint32_t page_range_count) {
std::vector<uint32_t> page_numbers;
for (uint32_t index = 0; index < page_range_count; ++index) {
for (uint32_t page_number = page_ranges[index].first_page_number;
page_number <= page_ranges[index].last_page_number; ++page_number) {
page_numbers.push_back(page_number);
}
}
return page_numbers;
}
#if defined(OS_LINUX) #if defined(OS_LINUX)
PP_Instance g_last_instance_id; PP_Instance g_last_instance_id;
...@@ -464,29 +432,6 @@ void Unsupported_Handler(UNSUPPORT_INFO*, int type) { ...@@ -464,29 +432,6 @@ void Unsupported_Handler(UNSUPPORT_INFO*, int type) {
UNSUPPORT_INFO g_unsupported_info = {1, Unsupported_Handler}; UNSUPPORT_INFO g_unsupported_info = {1, Unsupported_Handler};
// Set the destination page size and content area in points based on source
// page rotation and orientation.
//
// |rotated| True if source page is rotated 90 degree or 270 degree.
// |is_src_page_landscape| is true if the source page orientation is landscape.
// |page_size| has the actual destination page size in points.
// |content_rect| has the actual destination page printable area values in
// points.
void SetPageSizeAndContentRect(bool rotated,
bool is_src_page_landscape,
pp::Size* page_size,
pp::Rect* content_rect) {
bool is_dst_page_landscape = page_size->width() > page_size->height();
bool page_orientation_mismatched =
is_src_page_landscape != is_dst_page_landscape;
bool rotate_dst_page = rotated ^ page_orientation_mismatched;
if (rotate_dst_page) {
page_size->SetSize(page_size->height(), page_size->width());
content_rect->SetRect(content_rect->y(), content_rect->x(),
content_rect->height(), content_rect->width());
}
}
template <class S> template <class S>
bool IsAboveOrDirectlyLeftOf(const S& lhs, const S& rhs) { bool IsAboveOrDirectlyLeftOf(const S& lhs, const S& rhs) {
return lhs.y() < rhs.y() || (lhs.y() == rhs.y() && lhs.x() < rhs.x()); return lhs.y() < rhs.y() || (lhs.y() == rhs.y() && lhs.x() < rhs.x());
...@@ -618,17 +563,6 @@ void TearDownV8() { ...@@ -618,17 +563,6 @@ void TearDownV8() {
g_isolate_holder = nullptr; g_isolate_holder = nullptr;
} }
int GetBlockForJpeg(void* param,
unsigned long pos,
unsigned char* buf,
unsigned long size) {
std::vector<uint8_t>* data_vector = static_cast<std::vector<uint8_t>*>(param);
if (pos + size < pos || pos + size > data_vector->size())
return 0;
memcpy(buf, data_vector->data() + pos, size);
return 1;
}
// Returns true if the given |area| and |form_type| combination from // Returns true if the given |area| and |form_type| combination from
// PDFiumEngine::GetCharIndex() indicates it is a form text area. // PDFiumEngine::GetCharIndex() indicates it is a form text area.
bool IsFormTextArea(PDFiumPage::Area area, int form_type) { bool IsFormTextArea(PDFiumPage::Area area, int form_type) {
...@@ -705,30 +639,6 @@ std::string ConvertViewIntToViewString(unsigned long view_int) { ...@@ -705,30 +639,6 @@ std::string ConvertViewIntToViewString(unsigned long view_int) {
} }
} }
// UI should have done parameter sanity check, when execution
// reaches here, |num_pages_per_sheet| should be a positive integer.
bool ShouldDoNup(int num_pages_per_sheet) {
return num_pages_per_sheet > 1;
}
// Check the source doc orientation. Returns true if the doc is landscape.
// For now the orientation of the doc is determined by its first page's
// orientation. Improvement can be added in the future to better determine the
// orientation of the source docs that have mixed orientation.
// TODO(xlou): rotate pages if the source doc has mixed orientation. So that
// the orientation of all pages of the doc are uniform. Pages of square size
// will not be rotated.
bool IsSourcePdfLandscape(FPDF_DOCUMENT doc) {
DCHECK(doc);
ScopedFPDFPage pdf_page(FPDF_LoadPage(doc, 0));
DCHECK(pdf_page);
bool is_source_landscape =
FPDF_GetPageWidth(pdf_page.get()) > FPDF_GetPageHeight(pdf_page.get());
return is_source_landscape;
}
} // namespace } // namespace
bool InitializeSDK() { bool InitializeSDK() {
...@@ -799,7 +709,8 @@ PDFiumEngine::PDFiumEngine(PDFEngine::Client* client) ...@@ -799,7 +709,8 @@ PDFiumEngine::PDFiumEngine(PDFEngine::Client* client)
render_grayscale_(false), render_grayscale_(false),
render_annots_(true), render_annots_(true),
edit_mode_(false), edit_mode_(false),
form_filler_(this) { form_filler_(this),
print_(this) {
find_factory_.Initialize(this); find_factory_.Initialize(this);
password_factory_.Initialize(this); password_factory_.Initialize(this);
...@@ -1305,6 +1216,9 @@ pp::Resource PDFiumEngine::PrintPages( ...@@ -1305,6 +1216,9 @@ pp::Resource PDFiumEngine::PrintPages(
uint32_t page_range_count, uint32_t page_range_count,
const PP_PrintSettings_Dev& print_settings) { const PP_PrintSettings_Dev& print_settings) {
ScopedSubstFont scoped_subst_font(this); ScopedSubstFont scoped_subst_font(this);
if (!page_range_count)
return pp::Resource();
if ((print_settings.format & PP_PRINTOUTPUTFORMAT_PDF) && if ((print_settings.format & PP_PRINTOUTPUTFORMAT_PDF) &&
HasPermission(PERMISSION_PRINT_HIGH_QUALITY)) { HasPermission(PERMISSION_PRINT_HIGH_QUALITY)) {
return PrintPagesAsPDF(page_ranges, page_range_count, print_settings); return PrintPagesAsPDF(page_ranges, page_range_count, print_settings);
...@@ -1314,306 +1228,45 @@ pp::Resource PDFiumEngine::PrintPages( ...@@ -1314,306 +1228,45 @@ pp::Resource PDFiumEngine::PrintPages(
return pp::Resource(); return pp::Resource();
} }
FPDF_DOCUMENT PDFiumEngine::CreateSinglePageRasterPdf(
double source_page_width,
double source_page_height,
const PP_PrintSettings_Dev& print_settings,
PDFiumPage* page_to_print) {
FPDF_DOCUMENT temp_doc = FPDF_CreateNewDocument();
if (!temp_doc)
return temp_doc;
const pp::Size& bitmap_size(page_to_print->rect().size());
pp::ImageData image =
pp::ImageData(client_->GetPluginInstance(),
PP_IMAGEDATAFORMAT_BGRA_PREMUL, bitmap_size, false);
ScopedFPDFBitmap bitmap(
FPDFBitmap_CreateEx(bitmap_size.width(), bitmap_size.height(),
FPDFBitmap_BGRx, image.data(), image.stride()));
// Clear the bitmap
FPDFBitmap_FillRect(bitmap.get(), 0, 0, bitmap_size.width(),
bitmap_size.height(), 0xFFFFFFFF);
pp::Rect page_rect = page_to_print->rect();
FPDF_RenderPageBitmap(bitmap.get(), page_to_print->GetPrintPage(),
page_rect.x(), page_rect.y(), page_rect.width(),
page_rect.height(), print_settings.orientation,
FPDF_PRINTING | FPDF_NO_CATCH);
// Draw the forms.
FPDF_FFLDraw(form_, bitmap.get(), page_to_print->GetPrintPage(),
page_rect.x(), page_rect.y(), page_rect.width(),
page_rect.height(), print_settings.orientation,
FPDF_ANNOT | FPDF_PRINTING | FPDF_NO_CATCH);
unsigned char* bitmap_data =
static_cast<unsigned char*>(FPDFBitmap_GetBuffer(bitmap.get()));
double ratio_x = ConvertUnitDouble(bitmap_size.width(), print_settings.dpi,
kPointsPerInch);
double ratio_y = ConvertUnitDouble(bitmap_size.height(), print_settings.dpi,
kPointsPerInch);
// Add the bitmap to an image object and add the image object to the output
// page.
FPDF_PAGEOBJECT temp_img = FPDFPageObj_NewImageObj(temp_doc);
bool encoded = false;
std::vector<uint8_t> compressed_bitmap_data;
if (!(print_settings.format & PP_PRINTOUTPUTFORMAT_PDF)) {
// Use quality = 40 as this does not significantly degrade the printed
// document relative to a normal bitmap and provides better compression than
// a higher quality setting.
const int kQuality = 40;
SkImageInfo info = SkImageInfo::Make(
FPDFBitmap_GetWidth(bitmap.get()), FPDFBitmap_GetHeight(bitmap.get()),
kBGRA_8888_SkColorType, kOpaque_SkAlphaType);
SkPixmap src(info, bitmap_data, FPDFBitmap_GetStride(bitmap.get()));
encoded = gfx::JPEGCodec::Encode(src, kQuality, &compressed_bitmap_data);
}
{
ScopedFPDFPage temp_page_holder(
FPDFPage_New(temp_doc, 0, source_page_width, source_page_height));
FPDF_PAGE temp_page = temp_page_holder.get();
if (encoded) {
FPDF_FILEACCESS file_access = {};
file_access.m_FileLen =
static_cast<unsigned long>(compressed_bitmap_data.size());
file_access.m_GetBlock = &GetBlockForJpeg;
file_access.m_Param = &compressed_bitmap_data;
FPDFImageObj_LoadJpegFileInline(&temp_page, 1, temp_img, &file_access);
} else {
FPDFImageObj_SetBitmap(&temp_page, 1, temp_img, bitmap.get());
}
FPDFImageObj_SetMatrix(temp_img, ratio_x, 0, 0, ratio_y, 0, 0);
FPDFPage_InsertObject(temp_page, temp_img);
FPDFPage_GenerateContent(temp_page);
}
page_to_print->ClosePrintPage();
return temp_doc;
}
pp::Buffer_Dev PDFiumEngine::PrintPagesAsRasterPDF( pp::Buffer_Dev PDFiumEngine::PrintPagesAsRasterPDF(
const PP_PrintPageNumberRange_Dev* page_ranges, const PP_PrintPageNumberRange_Dev* page_ranges,
uint32_t page_range_count, uint32_t page_range_count,
const PP_PrintSettings_Dev& print_settings) { const PP_PrintSettings_Dev& print_settings) {
if (!page_range_count) DCHECK(page_range_count);
return pp::Buffer_Dev();
// If document is not downloaded yet, disable printing. // If document is not downloaded yet, disable printing.
if (doc_ && !doc_loader_->IsDocumentComplete()) if (doc_ && !doc_loader_->IsDocumentComplete())
return pp::Buffer_Dev(); return pp::Buffer_Dev();
ScopedFPDFDocument output_doc(FPDF_CreateNewDocument());
if (!output_doc)
return pp::Buffer_Dev();
KillFormFocus(); KillFormFocus();
std::vector<PDFiumPage> pages_to_print;
// width and height of source PDF pages.
std::vector<std::pair<double, double>> source_page_sizes;
// Collect pages to print and sizes of source pages.
std::vector<uint32_t> page_numbers =
GetPageNumbersFromPrintPageNumberRange(page_ranges, page_range_count);
for (uint32_t page_number : page_numbers) {
ScopedFPDFPage pdf_page(FPDF_LoadPage(doc_, page_number));
double source_page_width = FPDF_GetPageWidth(pdf_page.get());
double source_page_height = FPDF_GetPageHeight(pdf_page.get());
source_page_sizes.push_back(
std::make_pair(source_page_width, source_page_height));
// For computing size in pixels, use a square dpi since the source PDF page
// has square DPI.
int width_in_pixels =
ConvertUnit(source_page_width, kPointsPerInch, print_settings.dpi);
int height_in_pixels =
ConvertUnit(source_page_height, kPointsPerInch, print_settings.dpi);
pp::Rect rect(width_in_pixels, height_in_pixels);
pages_to_print.push_back(PDFiumPage(this, page_number, rect, true));
}
#if defined(OS_LINUX) #if defined(OS_LINUX)
g_last_instance_id = client_->GetPluginInstance()->pp_instance(); g_last_instance_id = client_->GetPluginInstance()->pp_instance();
#endif #endif
size_t i = 0; return print_.PrintPagesAsRasterPDF(page_ranges, page_range_count,
for (; i < pages_to_print.size(); ++i) { print_settings);
double source_page_width = source_page_sizes[i].first;
double source_page_height = source_page_sizes[i].second;
// Use |temp_doc| to compress image by saving PDF to |buffer|.
pp::Buffer_Dev buffer;
{
ScopedFPDFDocument temp_doc(
CreateSinglePageRasterPdf(source_page_width, source_page_height,
print_settings, &pages_to_print[i]));
if (!temp_doc)
break;
buffer = GetFlattenedPrintData(temp_doc.get());
}
PDFiumMemBufferFileRead file_read(buffer.data(), buffer.size());
ScopedFPDFDocument temp_doc(FPDF_LoadCustomDocument(&file_read, nullptr));
if (!FPDF_ImportPages(output_doc.get(), temp_doc.get(), "1", i))
break;
}
pp::Buffer_Dev buffer;
if (i == pages_to_print.size()) {
FPDF_CopyViewerPreferences(output_doc.get(), doc_);
if (ShouldDoNup(print_settings.num_pages_per_sheet)) {
buffer = NupPdfToPdf(output_doc.get(), print_settings);
} else {
FitContentsToPrintableAreaIfRequired(output_doc.get(), print_settings);
buffer = GetPrintData(output_doc.get());
}
}
return buffer;
}
bool PDFiumEngine::FlattenPrintData(FPDF_DOCUMENT doc) {
DCHECK(doc);
ScopedSubstFont scoped_subst_font(this);
int page_count = FPDF_GetPageCount(doc);
for (int i = 0; i < page_count; ++i) {
ScopedFPDFPage page(FPDF_LoadPage(doc, i));
DCHECK(page);
if (FPDFPage_Flatten(page.get(), FLAT_PRINT) == FLATTEN_FAIL)
return false;
}
return true;
}
pp::Buffer_Dev PDFiumEngine::GetPrintData(FPDF_DOCUMENT doc) {
DCHECK(doc);
pp::Buffer_Dev buffer;
PDFiumMemBufferFileWrite output_file_write;
if (FPDF_SaveAsCopy(doc, &output_file_write, 0)) {
size_t size = output_file_write.size();
buffer = pp::Buffer_Dev(client_->GetPluginInstance(), size);
if (!buffer.is_null())
memcpy(buffer.data(), output_file_write.buffer().c_str(), size);
}
return buffer;
}
pp::Buffer_Dev PDFiumEngine::GetFlattenedPrintData(FPDF_DOCUMENT doc) {
DCHECK(doc);
pp::Buffer_Dev buffer;
if (FlattenPrintData(doc))
buffer = GetPrintData(doc);
return buffer;
}
pp::Buffer_Dev PDFiumEngine::NupPdfToPdf(
FPDF_DOCUMENT doc,
const PP_PrintSettings_Dev& print_settings) {
DCHECK(doc);
PP_Size page_size = print_settings.paper_size;
printing::NupParameters nup_params;
bool is_landscape = IsSourcePdfLandscape(doc);
nup_params.SetParameters(print_settings.num_pages_per_sheet, is_landscape);
// Import n pages to one.
bool paper_is_landscape = page_size.width > page_size.height;
if (nup_params.landscape() != paper_is_landscape)
std::swap(page_size.width, page_size.height);
ScopedFPDFDocument output_doc_nup(FPDF_ImportNPagesToOne(
doc, page_size.width, page_size.height, nup_params.num_pages_on_x_axis(),
nup_params.num_pages_on_y_axis()));
if (!output_doc_nup)
return pp::Buffer_Dev();
FitContentsToPrintableAreaIfRequired(output_doc_nup.get(), print_settings);
return GetPrintData(output_doc_nup.get());
} }
pp::Buffer_Dev PDFiumEngine::PrintPagesAsPDF( pp::Buffer_Dev PDFiumEngine::PrintPagesAsPDF(
const PP_PrintPageNumberRange_Dev* page_ranges, const PP_PrintPageNumberRange_Dev* page_ranges,
uint32_t page_range_count, uint32_t page_range_count,
const PP_PrintSettings_Dev& print_settings) { const PP_PrintSettings_Dev& print_settings) {
if (!page_range_count) DCHECK(page_range_count);
return pp::Buffer_Dev();
DCHECK(doc_); DCHECK(doc_);
ScopedFPDFDocument output_doc(FPDF_CreateNewDocument());
if (!output_doc)
return pp::Buffer_Dev();
KillFormFocus(); KillFormFocus();
std::string page_number_str;
for (uint32_t index = 0; index < page_range_count; ++index) {
if (!page_number_str.empty())
page_number_str.append(",");
const PP_PrintPageNumberRange_Dev& range = page_ranges[index];
page_number_str.append(base::UintToString(range.first_page_number + 1));
if (range.first_page_number != range.last_page_number) {
page_number_str.append("-");
page_number_str.append(base::UintToString(range.last_page_number + 1));
}
}
std::vector<uint32_t> page_numbers = std::vector<uint32_t> page_numbers =
GetPageNumbersFromPrintPageNumberRange(page_ranges, page_range_count); PDFiumPrint::GetPageNumbersFromPrintPageNumberRange(page_ranges,
page_range_count);
for (uint32_t page_number : page_numbers) { for (uint32_t page_number : page_numbers) {
pages_[page_number]->GetPage(); pages_[page_number]->GetPage();
if (!IsPageVisible(page_number)) if (!IsPageVisible(page_number))
pages_[page_number]->Unload(); pages_[page_number]->Unload();
} }
FPDF_CopyViewerPreferences(output_doc.get(), doc_); return print_.PrintPagesAsPDF(page_ranges, page_range_count, print_settings);
if (!FPDF_ImportPages(output_doc.get(), doc_, page_number_str.c_str(), 0)) {
return pp::Buffer_Dev();
}
// Now flatten all the output pages.
if (!FlattenPrintData(output_doc.get())) {
return pp::Buffer_Dev();
}
pp::Buffer_Dev buffer;
if (ShouldDoNup(print_settings.num_pages_per_sheet)) {
buffer = NupPdfToPdf(output_doc.get(), print_settings);
} else {
FitContentsToPrintableAreaIfRequired(output_doc.get(), print_settings);
buffer = GetPrintData(output_doc.get());
}
return buffer;
}
void PDFiumEngine::FitContentsToPrintableAreaIfRequired(
FPDF_DOCUMENT doc,
const PP_PrintSettings_Dev& print_settings) {
// Check to see if we need to fit pdf contents to printer paper size.
if (print_settings.print_scaling_option !=
PP_PRINTSCALINGOPTION_SOURCE_SIZE) {
int num_pages = FPDF_GetPageCount(doc);
// In-place transformation is more efficient than creating a new
// transformed document from the source document. Therefore, transform
// every page to fit the contents in the selected printer paper.
for (int i = 0; i < num_pages; ++i) {
ScopedFPDFPage page(FPDF_LoadPage(doc, i));
TransformPDFPageForPrinting(page.get(), print_settings);
}
}
} }
void PDFiumEngine::KillFormFocus() { void PDFiumEngine::KillFormFocus() {
...@@ -3764,92 +3417,6 @@ void PDFiumEngine::SetCurrentPage(int index) { ...@@ -3764,92 +3417,6 @@ void PDFiumEngine::SetCurrentPage(int index) {
} }
} }
void PDFiumEngine::TransformPDFPageForPrinting(
FPDF_PAGE page,
const PP_PrintSettings_Dev& print_settings) {
// Get the source page width and height in points.
const double src_page_width = FPDF_GetPageWidth(page);
const double src_page_height = FPDF_GetPageHeight(page);
const int src_page_rotation = FPDFPage_GetRotation(page);
const bool fit_to_page = print_settings.print_scaling_option ==
PP_PRINTSCALINGOPTION_FIT_TO_PRINTABLE_AREA;
pp::Size page_size(print_settings.paper_size);
pp::Rect content_rect(print_settings.printable_area);
const bool rotated = (src_page_rotation % 2 == 1);
SetPageSizeAndContentRect(rotated, src_page_width > src_page_height,
&page_size, &content_rect);
// Compute the screen page width and height in points.
const int actual_page_width =
rotated ? page_size.height() : page_size.width();
const int actual_page_height =
rotated ? page_size.width() : page_size.height();
const gfx::Rect gfx_content_rect(content_rect.x(), content_rect.y(),
content_rect.width(), content_rect.height());
const double scale_factor =
fit_to_page ? CalculateScaleFactor(gfx_content_rect, src_page_width,
src_page_height, rotated)
: 1.0;
// Calculate positions for the clip box.
PdfRectangle media_box;
PdfRectangle crop_box;
bool has_media_box =
!!FPDFPage_GetMediaBox(page, &media_box.left, &media_box.bottom,
&media_box.right, &media_box.top);
bool has_crop_box = !!FPDFPage_GetCropBox(
page, &crop_box.left, &crop_box.bottom, &crop_box.right, &crop_box.top);
CalculateMediaBoxAndCropBox(rotated, has_media_box, has_crop_box, &media_box,
&crop_box);
PdfRectangle source_clip_box = CalculateClipBoxBoundary(media_box, crop_box);
ScalePdfRectangle(scale_factor, &source_clip_box);
// Calculate the translation offset values.
double offset_x = 0;
double offset_y = 0;
if (fit_to_page) {
CalculateScaledClipBoxOffset(gfx_content_rect, source_clip_box, &offset_x,
&offset_y);
} else {
CalculateNonScaledClipBoxOffset(gfx_content_rect, src_page_rotation,
actual_page_width, actual_page_height,
source_clip_box, &offset_x, &offset_y);
}
// Reset the media box and crop box. When the page has crop box and media box,
// the plugin will display the crop box contents and not the entire media box.
// If the pages have different crop box values, the plugin will display a
// document of multiple page sizes. To give better user experience, we
// decided to have same crop box and media box values. Hence, the user will
// see a list of uniform pages.
FPDFPage_SetMediaBox(page, 0, 0, page_size.width(), page_size.height());
FPDFPage_SetCropBox(page, 0, 0, page_size.width(), page_size.height());
// Transformation is not required, return. Do this check only after updating
// the media box and crop box. For more detailed information, please refer to
// the comment block right before FPDF_SetMediaBox and FPDF_GetMediaBox calls.
if (scale_factor == 1.0 && offset_x == 0 && offset_y == 0)
return;
// All the positions have been calculated, now manipulate the PDF.
FS_MATRIX matrix = {static_cast<float>(scale_factor),
0,
0,
static_cast<float>(scale_factor),
static_cast<float>(offset_x),
static_cast<float>(offset_y)};
FS_RECTF cliprect = {static_cast<float>(source_clip_box.left + offset_x),
static_cast<float>(source_clip_box.top + offset_y),
static_cast<float>(source_clip_box.right + offset_x),
static_cast<float>(source_clip_box.bottom + offset_y)};
FPDFPage_TransFormWithClip(page, &matrix, &cliprect);
FPDFPage_TransformAnnots(page, scale_factor, 0, 0, scale_factor, offset_x,
offset_y);
}
void PDFiumEngine::DrawPageShadow(const pp::Rect& page_rc, void PDFiumEngine::DrawPageShadow(const pp::Rect& page_rc,
const pp::Rect& shadow_rc, const pp::Rect& shadow_rc,
const pp::Rect& clip_rc, const pp::Rect& clip_rc,
......
...@@ -11,7 +11,6 @@ ...@@ -11,7 +11,6 @@
#include <map> #include <map>
#include <memory> #include <memory>
#include <string> #include <string>
#include <utility>
#include <vector> #include <vector>
#include "base/macros.h" #include "base/macros.h"
...@@ -21,6 +20,7 @@ ...@@ -21,6 +20,7 @@
#include "pdf/pdf_engine.h" #include "pdf/pdf_engine.h"
#include "pdf/pdfium/pdfium_form_filler.h" #include "pdf/pdfium/pdfium_form_filler.h"
#include "pdf/pdfium/pdfium_page.h" #include "pdf/pdfium/pdfium_page.h"
#include "pdf/pdfium/pdfium_print.h"
#include "pdf/pdfium/pdfium_range.h" #include "pdf/pdfium/pdfium_range.h"
#include "ppapi/cpp/completion_callback.h" #include "ppapi/cpp/completion_callback.h"
#include "ppapi/cpp/dev/buffer_dev.h" #include "ppapi/cpp/dev/buffer_dev.h"
...@@ -316,12 +316,6 @@ class PDFiumEngine : public PDFEngine, ...@@ -316,12 +316,6 @@ class PDFiumEngine : public PDFEngine,
bool ExtendSelection(int page_index, int char_index); bool ExtendSelection(int page_index, int char_index);
FPDF_DOCUMENT CreateSinglePageRasterPdf(
double source_page_width,
double source_page_height,
const PP_PrintSettings_Dev& print_settings,
PDFiumPage* page_to_print);
pp::Buffer_Dev PrintPagesAsRasterPDF( pp::Buffer_Dev PrintPagesAsRasterPDF(
const PP_PrintPageNumberRange_Dev* page_ranges, const PP_PrintPageNumberRange_Dev* page_ranges,
uint32_t page_range_count, uint32_t page_range_count,
...@@ -331,20 +325,6 @@ class PDFiumEngine : public PDFEngine, ...@@ -331,20 +325,6 @@ class PDFiumEngine : public PDFEngine,
uint32_t page_range_count, uint32_t page_range_count,
const PP_PrintSettings_Dev& print_settings); const PP_PrintSettings_Dev& print_settings);
bool FlattenPrintData(FPDF_DOCUMENT doc);
pp::Buffer_Dev GetPrintData(FPDF_DOCUMENT doc);
pp::Buffer_Dev GetFlattenedPrintData(FPDF_DOCUMENT doc);
// Perform N-up PDF generation from |doc| based on the parameters in
// |print_settings|. On success, the returned buffer contains the N-up version
// of |doc|. On failure, the returned buffer is empty.
pp::Buffer_Dev NupPdfToPdf(FPDF_DOCUMENT doc,
const PP_PrintSettings_Dev& print_settings);
void FitContentsToPrintableAreaIfRequired(
FPDF_DOCUMENT doc,
const PP_PrintSettings_Dev& print_settings);
// Checks if |page| has selected text in a form element. If so, sets that as // Checks if |page| has selected text in a form element. If so, sets that as
// the plugin's text selection. // the plugin's text selection.
void SetFormSelectedText(FPDF_FORMHANDLE form_handle, FPDF_PAGE page); void SetFormSelectedText(FPDF_FORMHANDLE form_handle, FPDF_PAGE page);
...@@ -447,10 +427,6 @@ class PDFiumEngine : public PDFEngine, ...@@ -447,10 +427,6 @@ class PDFiumEngine : public PDFEngine,
// triggers as necessary. // triggers as necessary.
void SetCurrentPage(int index); void SetCurrentPage(int index);
// Transform |page| contents to fit in the selected printer paper size.
void TransformPDFPageForPrinting(FPDF_PAGE page,
const PP_PrintSettings_Dev& print_settings);
void DrawPageShadow(const pp::Rect& page_rect, void DrawPageShadow(const pp::Rect& page_rect,
const pp::Rect& shadow_rect, const pp::Rect& shadow_rect,
const pp::Rect& clip_rect, const pp::Rect& clip_rect,
...@@ -695,6 +671,7 @@ class PDFiumEngine : public PDFEngine, ...@@ -695,6 +671,7 @@ class PDFiumEngine : public PDFEngine,
bool edit_mode_; bool edit_mode_;
PDFiumFormFiller form_filler_; PDFiumFormFiller form_filler_;
PDFiumPrint print_;
DISALLOW_COPY_AND_ASSIGN(PDFiumEngine); DISALLOW_COPY_AND_ASSIGN(PDFiumEngine);
}; };
......
// Copyright 2018 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.
#include "pdf/pdfium/pdfium_print.h"
#include <string>
#include <utility>
#include "base/strings/string_number_conversions.h"
#include "pdf/pdf_transform.h"
#include "pdf/pdfium/pdfium_engine.h"
#include "pdf/pdfium/pdfium_mem_buffer_file_read.h"
#include "pdf/pdfium/pdfium_mem_buffer_file_write.h"
#include "ppapi/c/dev/ppp_printing_dev.h"
#include "printing/nup_parameters.h"
#include "printing/units.h"
#include "third_party/pdfium/public/cpp/fpdf_scopers.h"
#include "third_party/pdfium/public/fpdf_flatten.h"
#include "third_party/pdfium/public/fpdf_ppo.h"
#include "third_party/pdfium/public/fpdf_transformpage.h"
#include "ui/gfx/codec/jpeg_codec.h"
#include "ui/gfx/geometry/rect.h"
using printing::ConvertUnit;
using printing::ConvertUnitDouble;
using printing::kPointsPerInch;
namespace chrome_pdf {
namespace {
// UI should have done parameter sanity check, when execution
// reaches here, |num_pages_per_sheet| should be a positive integer.
bool ShouldDoNup(int num_pages_per_sheet) {
return num_pages_per_sheet > 1;
}
// Check the source doc orientation. Returns true if the doc is landscape.
// For now the orientation of the doc is determined by its first page's
// orientation. Improvement can be added in the future to better determine the
// orientation of the source docs that have mixed orientation.
// TODO(xlou): rotate pages if the source doc has mixed orientation. So that
// the orientation of all pages of the doc are uniform. Pages of square size
// will not be rotated.
bool IsSourcePdfLandscape(FPDF_DOCUMENT doc) {
DCHECK(doc);
ScopedFPDFPage pdf_page(FPDF_LoadPage(doc, 0));
DCHECK(pdf_page);
bool is_source_landscape =
FPDF_GetPageWidth(pdf_page.get()) > FPDF_GetPageHeight(pdf_page.get());
return is_source_landscape;
}
// Set the destination page size and content area in points based on source
// page rotation and orientation.
//
// |rotated| True if source page is rotated 90 degree or 270 degree.
// |is_src_page_landscape| is true if the source page orientation is landscape.
// |page_size| has the actual destination page size in points.
// |content_rect| has the actual destination page printable area values in
// points.
void SetPageSizeAndContentRect(bool rotated,
bool is_src_page_landscape,
pp::Size* page_size,
pp::Rect* content_rect) {
bool is_dst_page_landscape = page_size->width() > page_size->height();
bool page_orientation_mismatched =
is_src_page_landscape != is_dst_page_landscape;
bool rotate_dst_page = rotated ^ page_orientation_mismatched;
if (rotate_dst_page) {
page_size->SetSize(page_size->height(), page_size->width());
content_rect->SetRect(content_rect->y(), content_rect->x(),
content_rect->height(), content_rect->width());
}
}
// Transform |page| contents to fit in the selected printer paper size.
void TransformPDFPageForPrinting(FPDF_PAGE page,
const PP_PrintSettings_Dev& print_settings) {
// Get the source page width and height in points.
const double src_page_width = FPDF_GetPageWidth(page);
const double src_page_height = FPDF_GetPageHeight(page);
const int src_page_rotation = FPDFPage_GetRotation(page);
const bool fit_to_page = print_settings.print_scaling_option ==
PP_PRINTSCALINGOPTION_FIT_TO_PRINTABLE_AREA;
pp::Size page_size(print_settings.paper_size);
pp::Rect content_rect(print_settings.printable_area);
const bool rotated = (src_page_rotation % 2 == 1);
SetPageSizeAndContentRect(rotated, src_page_width > src_page_height,
&page_size, &content_rect);
// Compute the screen page width and height in points.
const int actual_page_width =
rotated ? page_size.height() : page_size.width();
const int actual_page_height =
rotated ? page_size.width() : page_size.height();
const gfx::Rect gfx_content_rect(content_rect.x(), content_rect.y(),
content_rect.width(), content_rect.height());
const double scale_factor =
fit_to_page ? CalculateScaleFactor(gfx_content_rect, src_page_width,
src_page_height, rotated)
: 1.0;
// Calculate positions for the clip box.
PdfRectangle media_box;
PdfRectangle crop_box;
bool has_media_box =
!!FPDFPage_GetMediaBox(page, &media_box.left, &media_box.bottom,
&media_box.right, &media_box.top);
bool has_crop_box = !!FPDFPage_GetCropBox(
page, &crop_box.left, &crop_box.bottom, &crop_box.right, &crop_box.top);
CalculateMediaBoxAndCropBox(rotated, has_media_box, has_crop_box, &media_box,
&crop_box);
PdfRectangle source_clip_box = CalculateClipBoxBoundary(media_box, crop_box);
ScalePdfRectangle(scale_factor, &source_clip_box);
// Calculate the translation offset values.
double offset_x = 0;
double offset_y = 0;
if (fit_to_page) {
CalculateScaledClipBoxOffset(gfx_content_rect, source_clip_box, &offset_x,
&offset_y);
} else {
CalculateNonScaledClipBoxOffset(gfx_content_rect, src_page_rotation,
actual_page_width, actual_page_height,
source_clip_box, &offset_x, &offset_y);
}
// Reset the media box and crop box. When the page has crop box and media box,
// the plugin will display the crop box contents and not the entire media box.
// If the pages have different crop box values, the plugin will display a
// document of multiple page sizes. To give better user experience, we
// decided to have same crop box and media box values. Hence, the user will
// see a list of uniform pages.
FPDFPage_SetMediaBox(page, 0, 0, page_size.width(), page_size.height());
FPDFPage_SetCropBox(page, 0, 0, page_size.width(), page_size.height());
// Transformation is not required, return. Do this check only after updating
// the media box and crop box. For more detailed information, please refer to
// the comment block right before FPDF_SetMediaBox and FPDF_GetMediaBox calls.
if (scale_factor == 1.0 && offset_x == 0 && offset_y == 0)
return;
// All the positions have been calculated, now manipulate the PDF.
FS_MATRIX matrix = {static_cast<float>(scale_factor),
0,
0,
static_cast<float>(scale_factor),
static_cast<float>(offset_x),
static_cast<float>(offset_y)};
FS_RECTF cliprect = {static_cast<float>(source_clip_box.left + offset_x),
static_cast<float>(source_clip_box.top + offset_y),
static_cast<float>(source_clip_box.right + offset_x),
static_cast<float>(source_clip_box.bottom + offset_y)};
FPDFPage_TransFormWithClip(page, &matrix, &cliprect);
FPDFPage_TransformAnnots(page, scale_factor, 0, 0, scale_factor, offset_x,
offset_y);
}
void FitContentsToPrintableAreaIfRequired(
FPDF_DOCUMENT doc,
const PP_PrintSettings_Dev& print_settings) {
// Check to see if we need to fit pdf contents to printer paper size.
if (print_settings.print_scaling_option == PP_PRINTSCALINGOPTION_SOURCE_SIZE)
return;
int num_pages = FPDF_GetPageCount(doc);
// In-place transformation is more efficient than creating a new
// transformed document from the source document. Therefore, transform
// every page to fit the contents in the selected printer paper.
for (int i = 0; i < num_pages; ++i) {
ScopedFPDFPage page(FPDF_LoadPage(doc, i));
TransformPDFPageForPrinting(page.get(), print_settings);
}
}
int GetBlockForJpeg(void* param,
unsigned long pos,
unsigned char* buf,
unsigned long size) {
std::vector<uint8_t>* data_vector = static_cast<std::vector<uint8_t>*>(param);
if (pos + size < pos || pos + size > data_vector->size())
return 0;
memcpy(buf, data_vector->data() + pos, size);
return 1;
}
std::string GetPageRangeStringFromRange(
const PP_PrintPageNumberRange_Dev* page_ranges,
uint32_t page_range_count) {
DCHECK(page_range_count);
std::string page_number_str;
for (uint32_t i = 0; i < page_range_count; ++i) {
if (!page_number_str.empty())
page_number_str.push_back(',');
const PP_PrintPageNumberRange_Dev& range = page_ranges[i];
page_number_str.append(base::UintToString(range.first_page_number + 1));
if (range.first_page_number != range.last_page_number) {
page_number_str.push_back('-');
page_number_str.append(base::UintToString(range.last_page_number + 1));
}
}
return page_number_str;
}
} // namespace
PDFiumPrint::PDFiumPrint(PDFiumEngine* engine) : engine_(engine) {}
PDFiumPrint::~PDFiumPrint() = default;
// static
std::vector<uint32_t> PDFiumPrint::GetPageNumbersFromPrintPageNumberRange(
const PP_PrintPageNumberRange_Dev* page_ranges,
uint32_t page_range_count) {
DCHECK(page_range_count);
std::vector<uint32_t> page_numbers;
for (uint32_t i = 0; i < page_range_count; ++i) {
for (uint32_t page_number = page_ranges[i].first_page_number;
page_number <= page_ranges[i].last_page_number; ++page_number) {
page_numbers.push_back(page_number);
}
}
return page_numbers;
}
pp::Buffer_Dev PDFiumPrint::PrintPagesAsRasterPDF(
const PP_PrintPageNumberRange_Dev* page_ranges,
uint32_t page_range_count,
const PP_PrintSettings_Dev& print_settings) {
std::vector<PDFiumPage> pages_to_print;
// width and height of source PDF pages.
std::vector<std::pair<double, double>> source_page_sizes;
// Collect pages to print and sizes of source pages.
std::vector<uint32_t> page_numbers =
PDFiumPrint::GetPageNumbersFromPrintPageNumberRange(page_ranges,
page_range_count);
for (uint32_t page_number : page_numbers) {
ScopedFPDFPage pdf_page(FPDF_LoadPage(engine_->doc(), page_number));
double source_page_width = FPDF_GetPageWidth(pdf_page.get());
double source_page_height = FPDF_GetPageHeight(pdf_page.get());
source_page_sizes.push_back(
std::make_pair(source_page_width, source_page_height));
// For computing size in pixels, use a square dpi since the source PDF page
// has square DPI.
int width_in_pixels =
ConvertUnit(source_page_width, kPointsPerInch, print_settings.dpi);
int height_in_pixels =
ConvertUnit(source_page_height, kPointsPerInch, print_settings.dpi);
pp::Rect rect(width_in_pixels, height_in_pixels);
pages_to_print.push_back(PDFiumPage(engine_, page_number, rect, true));
}
ScopedFPDFDocument output_doc(FPDF_CreateNewDocument());
DCHECK(output_doc);
size_t i = 0;
for (; i < pages_to_print.size(); ++i) {
double source_page_width = source_page_sizes[i].first;
double source_page_height = source_page_sizes[i].second;
// Use |temp_doc| to compress image by saving PDF to |buffer|.
pp::Buffer_Dev buffer;
{
ScopedFPDFDocument temp_doc(
CreateSinglePageRasterPdf(source_page_width, source_page_height,
print_settings, &pages_to_print[i]));
if (!temp_doc)
break;
buffer = GetFlattenedPrintData(temp_doc.get());
}
PDFiumMemBufferFileRead file_read(buffer.data(), buffer.size());
ScopedFPDFDocument temp_doc(FPDF_LoadCustomDocument(&file_read, nullptr));
if (!FPDF_ImportPages(output_doc.get(), temp_doc.get(), "1", i))
break;
}
pp::Buffer_Dev buffer;
if (i == pages_to_print.size()) {
FPDF_CopyViewerPreferences(output_doc.get(), engine_->doc());
if (ShouldDoNup(print_settings.num_pages_per_sheet)) {
buffer = NupPdfToPdf(output_doc.get(), print_settings);
} else {
FitContentsToPrintableAreaIfRequired(output_doc.get(), print_settings);
buffer = GetPrintData(output_doc.get());
}
}
return buffer;
}
pp::Buffer_Dev PDFiumPrint::PrintPagesAsPDF(
const PP_PrintPageNumberRange_Dev* page_ranges,
uint32_t page_range_count,
const PP_PrintSettings_Dev& print_settings) {
ScopedFPDFDocument output_doc(FPDF_CreateNewDocument());
DCHECK(output_doc);
FPDF_CopyViewerPreferences(output_doc.get(), engine_->doc());
std::string page_number_str =
GetPageRangeStringFromRange(page_ranges, page_range_count);
if (!FPDF_ImportPages(output_doc.get(), engine_->doc(),
page_number_str.c_str(), 0)) {
return pp::Buffer_Dev();
}
// Now flatten all the output pages.
if (!FlattenPrintData(output_doc.get()))
return pp::Buffer_Dev();
pp::Buffer_Dev buffer;
if (ShouldDoNup(print_settings.num_pages_per_sheet)) {
buffer = NupPdfToPdf(output_doc.get(), print_settings);
} else {
FitContentsToPrintableAreaIfRequired(output_doc.get(), print_settings);
buffer = GetPrintData(output_doc.get());
}
return buffer;
}
FPDF_DOCUMENT PDFiumPrint::CreateSinglePageRasterPdf(
double source_page_width,
double source_page_height,
const PP_PrintSettings_Dev& print_settings,
PDFiumPage* page_to_print) {
FPDF_DOCUMENT temp_doc = FPDF_CreateNewDocument();
DCHECK(temp_doc);
const pp::Size& bitmap_size(page_to_print->rect().size());
pp::ImageData image =
pp::ImageData(engine_->GetPluginInstance(),
PP_IMAGEDATAFORMAT_BGRA_PREMUL, bitmap_size, false);
ScopedFPDFBitmap bitmap(
FPDFBitmap_CreateEx(bitmap_size.width(), bitmap_size.height(),
FPDFBitmap_BGRx, image.data(), image.stride()));
// Clear the bitmap
FPDFBitmap_FillRect(bitmap.get(), 0, 0, bitmap_size.width(),
bitmap_size.height(), 0xFFFFFFFF);
pp::Rect page_rect = page_to_print->rect();
FPDF_RenderPageBitmap(bitmap.get(), page_to_print->GetPrintPage(),
page_rect.x(), page_rect.y(), page_rect.width(),
page_rect.height(), print_settings.orientation,
FPDF_PRINTING | FPDF_NO_CATCH);
// Draw the forms.
FPDF_FFLDraw(engine_->form(), bitmap.get(), page_to_print->GetPrintPage(),
page_rect.x(), page_rect.y(), page_rect.width(),
page_rect.height(), print_settings.orientation,
FPDF_ANNOT | FPDF_PRINTING | FPDF_NO_CATCH);
unsigned char* bitmap_data =
static_cast<unsigned char*>(FPDFBitmap_GetBuffer(bitmap.get()));
double ratio_x = ConvertUnitDouble(bitmap_size.width(), print_settings.dpi,
kPointsPerInch);
double ratio_y = ConvertUnitDouble(bitmap_size.height(), print_settings.dpi,
kPointsPerInch);
// Add the bitmap to an image object and add the image object to the output
// page.
FPDF_PAGEOBJECT temp_img = FPDFPageObj_NewImageObj(temp_doc);
bool encoded = false;
std::vector<uint8_t> compressed_bitmap_data;
if (!(print_settings.format & PP_PRINTOUTPUTFORMAT_PDF)) {
// Use quality = 40 as this does not significantly degrade the printed
// document relative to a normal bitmap and provides better compression than
// a higher quality setting.
const int kQuality = 40;
SkImageInfo info = SkImageInfo::Make(
FPDFBitmap_GetWidth(bitmap.get()), FPDFBitmap_GetHeight(bitmap.get()),
kBGRA_8888_SkColorType, kOpaque_SkAlphaType);
SkPixmap src(info, bitmap_data, FPDFBitmap_GetStride(bitmap.get()));
encoded = gfx::JPEGCodec::Encode(src, kQuality, &compressed_bitmap_data);
}
{
ScopedFPDFPage temp_page_holder(
FPDFPage_New(temp_doc, 0, source_page_width, source_page_height));
FPDF_PAGE temp_page = temp_page_holder.get();
if (encoded) {
FPDF_FILEACCESS file_access = {};
file_access.m_FileLen =
static_cast<unsigned long>(compressed_bitmap_data.size());
file_access.m_GetBlock = &GetBlockForJpeg;
file_access.m_Param = &compressed_bitmap_data;
FPDFImageObj_LoadJpegFileInline(&temp_page, 1, temp_img, &file_access);
} else {
FPDFImageObj_SetBitmap(&temp_page, 1, temp_img, bitmap.get());
}
FPDFImageObj_SetMatrix(temp_img, ratio_x, 0, 0, ratio_y, 0, 0);
FPDFPage_InsertObject(temp_page, temp_img);
FPDFPage_GenerateContent(temp_page);
}
page_to_print->ClosePrintPage();
return temp_doc;
}
pp::Buffer_Dev PDFiumPrint::NupPdfToPdf(
FPDF_DOCUMENT doc,
const PP_PrintSettings_Dev& print_settings) {
DCHECK(doc);
PP_Size page_size = print_settings.paper_size;
printing::NupParameters nup_params;
bool is_landscape = IsSourcePdfLandscape(doc);
nup_params.SetParameters(print_settings.num_pages_per_sheet, is_landscape);
// Import n pages to one.
bool paper_is_landscape = page_size.width > page_size.height;
if (nup_params.landscape() != paper_is_landscape)
std::swap(page_size.width, page_size.height);
ScopedFPDFDocument output_doc_nup(FPDF_ImportNPagesToOne(
doc, page_size.width, page_size.height, nup_params.num_pages_on_x_axis(),
nup_params.num_pages_on_y_axis()));
if (!output_doc_nup)
return pp::Buffer_Dev();
FitContentsToPrintableAreaIfRequired(output_doc_nup.get(), print_settings);
return GetPrintData(output_doc_nup.get());
}
bool PDFiumPrint::FlattenPrintData(FPDF_DOCUMENT doc) {
DCHECK(doc);
ScopedSubstFont scoped_subst_font(engine_);
int page_count = FPDF_GetPageCount(doc);
for (int i = 0; i < page_count; ++i) {
ScopedFPDFPage page(FPDF_LoadPage(doc, i));
DCHECK(page);
if (FPDFPage_Flatten(page.get(), FLAT_PRINT) == FLATTEN_FAIL)
return false;
}
return true;
}
pp::Buffer_Dev PDFiumPrint::GetPrintData(FPDF_DOCUMENT doc) {
DCHECK(doc);
pp::Buffer_Dev buffer;
PDFiumMemBufferFileWrite output_file_write;
if (FPDF_SaveAsCopy(doc, &output_file_write, 0)) {
size_t size = output_file_write.size();
buffer = pp::Buffer_Dev(engine_->GetPluginInstance(), size);
if (!buffer.is_null())
memcpy(buffer.data(), output_file_write.buffer().c_str(), size);
}
return buffer;
}
pp::Buffer_Dev PDFiumPrint::GetFlattenedPrintData(FPDF_DOCUMENT doc) {
DCHECK(doc);
pp::Buffer_Dev buffer;
if (FlattenPrintData(doc))
buffer = GetPrintData(doc);
return buffer;
}
} // namespace chrome_pdf
// Copyright 2018 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_PDFIUM_PDFIUM_PRINT_H_
#define PDF_PDFIUM_PDFIUM_PRINT_H_
#include <vector>
#include "base/macros.h"
#include "ppapi/cpp/dev/buffer_dev.h"
#include "third_party/pdfium/public/fpdfview.h"
struct PP_PrintSettings_Dev;
struct PP_PrintPageNumberRange_Dev;
namespace chrome_pdf {
class PDFiumEngine;
class PDFiumPage;
class PDFiumPrint {
public:
explicit PDFiumPrint(PDFiumEngine* engine);
~PDFiumPrint();
static std::vector<uint32_t> GetPageNumbersFromPrintPageNumberRange(
const PP_PrintPageNumberRange_Dev* page_ranges,
uint32_t page_range_count);
pp::Buffer_Dev PrintPagesAsRasterPDF(
const PP_PrintPageNumberRange_Dev* page_ranges,
uint32_t page_range_count,
const PP_PrintSettings_Dev& print_settings);
pp::Buffer_Dev PrintPagesAsPDF(const PP_PrintPageNumberRange_Dev* page_ranges,
uint32_t page_range_count,
const PP_PrintSettings_Dev& print_settings);
private:
FPDF_DOCUMENT CreateSinglePageRasterPdf(
double source_page_width,
double source_page_height,
const PP_PrintSettings_Dev& print_settings,
PDFiumPage* page_to_print);
// Perform N-up PDF generation from |doc| based on the parameters in
// |print_settings|. On success, the returned buffer contains the N-up version
// of |doc|. On failure, the returned buffer is empty.
pp::Buffer_Dev NupPdfToPdf(FPDF_DOCUMENT doc,
const PP_PrintSettings_Dev& print_settings);
bool FlattenPrintData(FPDF_DOCUMENT doc);
pp::Buffer_Dev GetPrintData(FPDF_DOCUMENT doc);
pp::Buffer_Dev GetFlattenedPrintData(FPDF_DOCUMENT doc);
PDFiumEngine* const engine_;
DISALLOW_COPY_AND_ASSIGN(PDFiumPrint);
};
} // namespace chrome_pdf
#endif // PDF_PDFIUM_PDFIUM_PRINT_H_
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