1 // Copyright 2014 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "chrome/utility/printing_handler.h"
7 #include "base/files/file_util.h"
8 #include "base/lazy_instance.h"
9 #include "base/path_service.h"
10 #include "base/scoped_native_library.h"
11 #include "chrome/common/chrome_paths.h"
12 #include "chrome/common/chrome_utility_printing_messages.h"
13 #include "chrome/utility/cloud_print/bitmap_image.h"
14 #include "chrome/utility/cloud_print/pwg_encoder.h"
15 #include "content/public/utility/utility_thread.h"
16 #include "printing/page_range.h"
17 #include "printing/pdf_render_settings.h"
20 #include "base/win/iat_patch_function.h"
21 #include "printing/emf_win.h"
22 #include "ui/gfx/gdi_util.h"
25 #if defined(ENABLE_PRINT_PREVIEW)
26 #include "chrome/common/crash_keys.h"
27 #include "printing/backend/print_backend.h"
32 bool Send(IPC::Message
* message
) {
33 return content::UtilityThread::Get()->Send(message
);
36 void ReleaseProcessIfNeeded() {
37 content::UtilityThread::Get()->ReleaseProcessIfNeeded();
40 class PdfFunctionsBase
{
42 PdfFunctionsBase() : render_pdf_to_bitmap_func_(NULL
),
43 get_pdf_doc_info_func_(NULL
) {}
46 base::FilePath pdf_module_path
;
47 if (!PathService::Get(chrome::FILE_PDF_PLUGIN
, &pdf_module_path
) ||
48 !base::PathExists(pdf_module_path
)) {
52 pdf_lib_
.Reset(base::LoadNativeLibrary(pdf_module_path
, NULL
));
53 if (!pdf_lib_
.is_valid()) {
54 LOG(WARNING
) << "Couldn't load PDF plugin";
58 render_pdf_to_bitmap_func_
=
59 reinterpret_cast<RenderPDFPageToBitmapProc
>(
60 pdf_lib_
.GetFunctionPointer("RenderPDFPageToBitmap"));
61 LOG_IF(WARNING
, !render_pdf_to_bitmap_func_
) <<
62 "Missing RenderPDFPageToBitmap";
64 get_pdf_doc_info_func_
=
65 reinterpret_cast<GetPDFDocInfoProc
>(
66 pdf_lib_
.GetFunctionPointer("GetPDFDocInfo"));
67 LOG_IF(WARNING
, !get_pdf_doc_info_func_
) << "Missing GetPDFDocInfo";
69 if (!render_pdf_to_bitmap_func_
|| !get_pdf_doc_info_func_
||
70 !PlatformInit(pdf_module_path
, pdf_lib_
)) {
77 bool IsValid() const {
78 return pdf_lib_
.is_valid();
85 bool RenderPDFPageToBitmap(const void* pdf_buffer
,
94 if (!render_pdf_to_bitmap_func_
)
96 return render_pdf_to_bitmap_func_(pdf_buffer
, pdf_buffer_size
, page_number
,
97 bitmap_buffer
, bitmap_width
,
98 bitmap_height
, dpi_x
, dpi_y
, autorotate
);
101 bool GetPDFDocInfo(const void* pdf_buffer
,
104 double* max_page_width
) {
105 if (!get_pdf_doc_info_func_
)
107 return get_pdf_doc_info_func_(pdf_buffer
, buffer_size
, page_count
,
112 virtual bool PlatformInit(
113 const base::FilePath
& pdf_module_path
,
114 const base::ScopedNativeLibrary
& pdf_lib
) {
119 // Exported by PDF plugin.
120 typedef bool (*RenderPDFPageToBitmapProc
)(const void* pdf_buffer
,
129 typedef bool (*GetPDFDocInfoProc
)(const void* pdf_buffer
,
130 int buffer_size
, int* page_count
,
131 double* max_page_width
);
133 RenderPDFPageToBitmapProc render_pdf_to_bitmap_func_
;
134 GetPDFDocInfoProc get_pdf_doc_info_func_
;
136 base::ScopedNativeLibrary pdf_lib_
;
137 DISALLOW_COPY_AND_ASSIGN(PdfFunctionsBase
);
141 // The 2 below IAT patch functions are almost identical to the code in
142 // render_process_impl.cc. This is needed to work around specific Windows APIs
143 // used by the Chrome PDF plugin that will fail in the sandbox.
144 static base::win::IATPatchFunction g_iat_patch_createdca
;
145 HDC WINAPI
UtilityProcess_CreateDCAPatch(LPCSTR driver_name
,
148 const DEVMODEA
* init_data
) {
149 if (driver_name
&& (std::string("DISPLAY") == driver_name
)) {
150 // CreateDC fails behind the sandbox, but not CreateCompatibleDC.
151 return CreateCompatibleDC(NULL
);
155 return CreateDCA(driver_name
, device_name
, output
, init_data
);
158 static base::win::IATPatchFunction g_iat_patch_get_font_data
;
159 DWORD WINAPI
UtilityProcess_GetFontDataPatch(
160 HDC hdc
, DWORD table
, DWORD offset
, LPVOID buffer
, DWORD length
) {
161 int rv
= GetFontData(hdc
, table
, offset
, buffer
, length
);
162 if (rv
== GDI_ERROR
&& hdc
) {
163 HFONT font
= static_cast<HFONT
>(GetCurrentObject(hdc
, OBJ_FONT
));
166 if (GetObject(font
, sizeof(LOGFONT
), &logfont
)) {
167 content::UtilityThread::Get()->PreCacheFont(logfont
);
168 rv
= GetFontData(hdc
, table
, offset
, buffer
, length
);
169 content::UtilityThread::Get()->ReleaseCachedFonts();
175 class PdfFunctionsWin
: public PdfFunctionsBase
{
177 PdfFunctionsWin() : render_pdf_to_dc_func_(NULL
) {
181 const base::FilePath
& pdf_module_path
,
182 const base::ScopedNativeLibrary
& pdf_lib
) override
{
183 // Patch the IAT for handling specific APIs known to fail in the sandbox.
184 if (!g_iat_patch_createdca
.is_patched()) {
185 g_iat_patch_createdca
.Patch(pdf_module_path
.value().c_str(),
186 "gdi32.dll", "CreateDCA",
187 UtilityProcess_CreateDCAPatch
);
190 if (!g_iat_patch_get_font_data
.is_patched()) {
191 g_iat_patch_get_font_data
.Patch(pdf_module_path
.value().c_str(),
192 "gdi32.dll", "GetFontData",
193 UtilityProcess_GetFontDataPatch
);
195 render_pdf_to_dc_func_
=
196 reinterpret_cast<RenderPDFPageToDCProc
>(
197 pdf_lib
.GetFunctionPointer("RenderPDFPageToDC"));
198 LOG_IF(WARNING
, !render_pdf_to_dc_func_
) << "Missing RenderPDFPageToDC";
200 return render_pdf_to_dc_func_
!= NULL
;
203 bool RenderPDFPageToDC(const void* pdf_buffer
,
214 bool stretch_to_bounds
,
215 bool keep_aspect_ratio
,
216 bool center_in_bounds
,
218 if (!render_pdf_to_dc_func_
)
220 return render_pdf_to_dc_func_(pdf_buffer
, buffer_size
, page_number
,
221 dc
, dpi_x
, dpi_y
, bounds_origin_x
,
222 bounds_origin_y
, bounds_width
, bounds_height
,
223 fit_to_bounds
, stretch_to_bounds
,
224 keep_aspect_ratio
, center_in_bounds
,
229 // Exported by PDF plugin.
230 typedef bool (*RenderPDFPageToDCProc
)(
231 const void* pdf_buffer
, int buffer_size
, int page_number
, HDC dc
,
232 int dpi_x
, int dpi_y
, int bounds_origin_x
, int bounds_origin_y
,
233 int bounds_width
, int bounds_height
, bool fit_to_bounds
,
234 bool stretch_to_bounds
, bool keep_aspect_ratio
, bool center_in_bounds
,
236 RenderPDFPageToDCProc render_pdf_to_dc_func_
;
238 DISALLOW_COPY_AND_ASSIGN(PdfFunctionsWin
);
241 typedef PdfFunctionsWin PdfFunctions
;
243 typedef PdfFunctionsBase PdfFunctions
;
246 base::LazyInstance
<PdfFunctions
> g_pdf_lib
= LAZY_INSTANCE_INITIALIZER
;
250 PrintingHandler::PrintingHandler() {}
252 PrintingHandler::~PrintingHandler() {}
255 void PrintingHandler::PreSandboxStartup() {
256 g_pdf_lib
.Get().Init();
259 bool PrintingHandler::OnMessageReceived(const IPC::Message
& message
) {
261 IPC_BEGIN_MESSAGE_MAP(PrintingHandler
, message
)
263 IPC_MESSAGE_HANDLER(ChromeUtilityMsg_RenderPDFPagesToMetafiles
,
264 OnRenderPDFPagesToMetafile
)
265 IPC_MESSAGE_HANDLER(ChromeUtilityMsg_RenderPDFPagesToMetafiles_GetPage
,
266 OnRenderPDFPagesToMetafileGetPage
)
267 IPC_MESSAGE_HANDLER(ChromeUtilityMsg_RenderPDFPagesToMetafiles_Stop
,
268 OnRenderPDFPagesToMetafileStop
)
270 #if defined(ENABLE_PRINT_PREVIEW)
271 IPC_MESSAGE_HANDLER(ChromeUtilityMsg_RenderPDFPagesToPWGRaster
,
272 OnRenderPDFPagesToPWGRaster
)
273 IPC_MESSAGE_HANDLER(ChromeUtilityMsg_GetPrinterCapsAndDefaults
,
274 OnGetPrinterCapsAndDefaults
)
275 IPC_MESSAGE_HANDLER(ChromeUtilityMsg_GetPrinterSemanticCapsAndDefaults
,
276 OnGetPrinterSemanticCapsAndDefaults
)
277 #endif // ENABLE_PRINT_PREVIEW
278 IPC_MESSAGE_UNHANDLED(handled
= false)
279 IPC_END_MESSAGE_MAP()
284 void PrintingHandler::OnRenderPDFPagesToMetafile(
285 IPC::PlatformFileForTransit pdf_transit
,
286 const printing::PdfRenderSettings
& settings
) {
287 pdf_rendering_settings_
= settings
;
288 base::File pdf_file
= IPC::PlatformFileForTransitToFile(pdf_transit
);
289 int page_count
= LoadPDF(pdf_file
.Pass());
291 new ChromeUtilityHostMsg_RenderPDFPagesToMetafiles_PageCount(page_count
));
294 void PrintingHandler::OnRenderPDFPagesToMetafileGetPage(
296 IPC::PlatformFileForTransit output_file
) {
297 base::File emf_file
= IPC::PlatformFileForTransitToFile(output_file
);
298 float scale_factor
= 1.0f
;
300 RenderPdfPageToMetafile(page_number
, emf_file
.Pass(), &scale_factor
);
301 Send(new ChromeUtilityHostMsg_RenderPDFPagesToMetafiles_PageDone(
302 success
, scale_factor
));
305 void PrintingHandler::OnRenderPDFPagesToMetafileStop() {
306 ReleaseProcessIfNeeded();
311 #if defined(ENABLE_PRINT_PREVIEW)
312 void PrintingHandler::OnRenderPDFPagesToPWGRaster(
313 IPC::PlatformFileForTransit pdf_transit
,
314 const printing::PdfRenderSettings
& settings
,
315 const printing::PwgRasterSettings
& bitmap_settings
,
316 IPC::PlatformFileForTransit bitmap_transit
) {
317 base::File pdf
= IPC::PlatformFileForTransitToFile(pdf_transit
);
318 base::File bitmap
= IPC::PlatformFileForTransitToFile(bitmap_transit
);
319 if (RenderPDFPagesToPWGRaster(pdf
.Pass(), settings
, bitmap_settings
,
321 Send(new ChromeUtilityHostMsg_RenderPDFPagesToPWGRaster_Succeeded());
323 Send(new ChromeUtilityHostMsg_RenderPDFPagesToPWGRaster_Failed());
325 ReleaseProcessIfNeeded();
327 #endif // ENABLE_PRINT_PREVIEW
330 int PrintingHandler::LoadPDF(base::File pdf_file
) {
331 if (!g_pdf_lib
.Get().IsValid())
334 int64 length64
= pdf_file
.GetLength();
335 if (length64
<= 0 || length64
> std::numeric_limits
<int>::max())
337 int length
= static_cast<int>(length64
);
339 pdf_data_
.resize(length
);
340 if (length
!= pdf_file
.Read(0, pdf_data_
.data(), pdf_data_
.size()))
343 int total_page_count
= 0;
344 if (!g_pdf_lib
.Get().GetPDFDocInfo(
345 &pdf_data_
.front(), pdf_data_
.size(), &total_page_count
, NULL
)) {
348 return total_page_count
;
351 bool PrintingHandler::RenderPdfPageToMetafile(int page_number
,
352 base::File output_file
,
353 float* scale_factor
) {
354 printing::Emf metafile
;
357 // We need to scale down DC to fit an entire page into DC available area.
358 // Current metafile is based on screen DC and have current screen size.
359 // Writing outside of those boundaries will result in the cut-off output.
360 // On metafiles (this is the case here), scaling down will still record
361 // original coordinates and we'll be able to print in full resolution.
362 // Before playback we'll need to counter the scaling up that will happen
363 // in the service (print_system_win.cc).
365 gfx::CalculatePageScale(metafile
.context(),
366 pdf_rendering_settings_
.area().right(),
367 pdf_rendering_settings_
.area().bottom());
368 gfx::ScaleDC(metafile
.context(), *scale_factor
);
370 // The underlying metafile is of type Emf and ignores the arguments passed
372 metafile
.StartPage(gfx::Size(), gfx::Rect(), 1);
373 if (!g_pdf_lib
.Get().RenderPDFPageToDC(
378 pdf_rendering_settings_
.dpi(),
379 pdf_rendering_settings_
.dpi(),
380 pdf_rendering_settings_
.area().x(),
381 pdf_rendering_settings_
.area().y(),
382 pdf_rendering_settings_
.area().width(),
383 pdf_rendering_settings_
.area().height(),
388 pdf_rendering_settings_
.autorotate())) {
391 metafile
.FinishPage();
392 metafile
.FinishDocument();
393 return metafile
.SaveTo(&output_file
);
398 #if defined(ENABLE_PRINT_PREVIEW)
399 bool PrintingHandler::RenderPDFPagesToPWGRaster(
401 const printing::PdfRenderSettings
& settings
,
402 const printing::PwgRasterSettings
& bitmap_settings
,
403 base::File bitmap_file
) {
404 bool autoupdate
= true;
405 if (!g_pdf_lib
.Get().IsValid())
408 base::File::Info info
;
409 if (!pdf_file
.GetInfo(&info
) || info
.size
<= 0 ||
410 info
.size
> std::numeric_limits
<int>::max())
412 int data_size
= static_cast<int>(info
.size
);
414 std::string
data(data_size
, 0);
415 if (pdf_file
.Read(0, &data
[0], data_size
) != data_size
)
418 int total_page_count
= 0;
419 if (!g_pdf_lib
.Get().GetPDFDocInfo(data
.data(), data_size
,
420 &total_page_count
, NULL
)) {
424 cloud_print::PwgEncoder encoder
;
425 std::string pwg_header
;
426 encoder
.EncodeDocumentHeader(&pwg_header
);
427 int bytes_written
= bitmap_file
.WriteAtCurrentPos(pwg_header
.data(),
429 if (bytes_written
!= static_cast<int>(pwg_header
.size()))
432 cloud_print::BitmapImage
image(settings
.area().size(),
433 cloud_print::BitmapImage::BGRA
);
434 for (int i
= 0; i
< total_page_count
; ++i
) {
437 if (bitmap_settings
.reverse_page_order
) {
438 page_number
= total_page_count
- 1 - page_number
;
441 if (!g_pdf_lib
.Get().RenderPDFPageToBitmap(data
.data(),
445 image
.size().width(),
446 image
.size().height(),
453 cloud_print::PwgHeaderInfo header_info
;
454 header_info
.dpi
= settings
.dpi();
455 header_info
.total_pages
= total_page_count
;
457 // Transform odd pages.
458 if (page_number
% 2) {
459 switch (bitmap_settings
.odd_page_transform
) {
460 case printing::TRANSFORM_NORMAL
:
462 case printing::TRANSFORM_ROTATE_180
:
463 header_info
.flipx
= true;
464 header_info
.flipy
= true;
466 case printing::TRANSFORM_FLIP_HORIZONTAL
:
467 header_info
.flipx
= true;
469 case printing::TRANSFORM_FLIP_VERTICAL
:
470 header_info
.flipy
= true;
475 if (bitmap_settings
.rotate_all_pages
) {
476 header_info
.flipx
= !header_info
.flipx
;
477 header_info
.flipy
= !header_info
.flipy
;
480 std::string pwg_page
;
481 if (!encoder
.EncodePage(image
, header_info
, &pwg_page
))
483 bytes_written
= bitmap_file
.WriteAtCurrentPos(pwg_page
.data(),
485 if (bytes_written
!= static_cast<int>(pwg_page
.size()))
491 void PrintingHandler::OnGetPrinterCapsAndDefaults(
492 const std::string
& printer_name
) {
493 scoped_refptr
<printing::PrintBackend
> print_backend
=
494 printing::PrintBackend::CreateInstance(NULL
);
495 printing::PrinterCapsAndDefaults printer_info
;
497 crash_keys::ScopedPrinterInfo
crash_key(
498 print_backend
->GetPrinterDriverInfo(printer_name
));
500 if (print_backend
->GetPrinterCapsAndDefaults(printer_name
, &printer_info
)) {
501 Send(new ChromeUtilityHostMsg_GetPrinterCapsAndDefaults_Succeeded(
502 printer_name
, printer_info
));
504 Send(new ChromeUtilityHostMsg_GetPrinterCapsAndDefaults_Failed(
507 ReleaseProcessIfNeeded();
510 void PrintingHandler::OnGetPrinterSemanticCapsAndDefaults(
511 const std::string
& printer_name
) {
512 scoped_refptr
<printing::PrintBackend
> print_backend
=
513 printing::PrintBackend::CreateInstance(NULL
);
514 printing::PrinterSemanticCapsAndDefaults printer_info
;
516 crash_keys::ScopedPrinterInfo
crash_key(
517 print_backend
->GetPrinterDriverInfo(printer_name
));
519 if (print_backend
->GetPrinterSemanticCapsAndDefaults(printer_name
,
521 Send(new ChromeUtilityHostMsg_GetPrinterSemanticCapsAndDefaults_Succeeded(
522 printer_name
, printer_info
));
524 Send(new ChromeUtilityHostMsg_GetPrinterSemanticCapsAndDefaults_Failed(
527 ReleaseProcessIfNeeded();
529 #endif // ENABLE_PRINT_PREVIEW