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_FULL_PRINTING)
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_FULL_PRINTING)
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_FULL_PRINTING
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 double scale_factor
= 1.0;
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_FULL_PRINTING)
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_FULL_PRINTING
330 int PrintingHandler::LoadPDF(base::File pdf_file
) {
331 if (!g_pdf_lib
.Get().IsValid())
334 int64 length
= pdf_file
.GetLength();
338 pdf_data_
.resize(length
);
339 if (length
!= pdf_file
.Read(0, pdf_data_
.data(), pdf_data_
.size()))
342 int total_page_count
= 0;
343 if (!g_pdf_lib
.Get().GetPDFDocInfo(
344 &pdf_data_
.front(), pdf_data_
.size(), &total_page_count
, NULL
)) {
347 return total_page_count
;
350 bool PrintingHandler::RenderPdfPageToMetafile(int page_number
,
351 base::File output_file
,
352 double* scale_factor
) {
353 printing::Emf metafile
;
356 // We need to scale down DC to fit an entire page into DC available area.
357 // Current metafile is based on screen DC and have current screen size.
358 // Writing outside of those boundaries will result in the cut-off output.
359 // On metafiles (this is the case here), scaling down will still record
360 // original coordinates and we'll be able to print in full resolution.
361 // Before playback we'll need to counter the scaling up that will happen
362 // in the service (print_system_win.cc).
364 gfx::CalculatePageScale(metafile
.context(),
365 pdf_rendering_settings_
.area().right(),
366 pdf_rendering_settings_
.area().bottom());
367 gfx::ScaleDC(metafile
.context(), *scale_factor
);
369 // The underlying metafile is of type Emf and ignores the arguments passed
371 metafile
.StartPage(gfx::Size(), gfx::Rect(), 1);
372 if (!g_pdf_lib
.Get().RenderPDFPageToDC(
377 pdf_rendering_settings_
.dpi(),
378 pdf_rendering_settings_
.dpi(),
379 pdf_rendering_settings_
.area().x(),
380 pdf_rendering_settings_
.area().y(),
381 pdf_rendering_settings_
.area().width(),
382 pdf_rendering_settings_
.area().height(),
387 pdf_rendering_settings_
.autorotate())) {
390 metafile
.FinishPage();
391 metafile
.FinishDocument();
392 return metafile
.SaveTo(&output_file
);
397 #if defined(ENABLE_FULL_PRINTING)
398 bool PrintingHandler::RenderPDFPagesToPWGRaster(
400 const printing::PdfRenderSettings
& settings
,
401 const printing::PwgRasterSettings
& bitmap_settings
,
402 base::File bitmap_file
) {
403 bool autoupdate
= true;
404 if (!g_pdf_lib
.Get().IsValid())
407 base::File::Info info
;
408 if (!pdf_file
.GetInfo(&info
) || info
.size
<= 0)
411 std::string
data(info
.size
, 0);
412 int data_size
= pdf_file
.Read(0, &data
[0], data
.size());
413 if (data_size
!= static_cast<int>(data
.size()))
416 int total_page_count
= 0;
417 if (!g_pdf_lib
.Get().GetPDFDocInfo(data
.data(), data
.size(),
418 &total_page_count
, NULL
)) {
422 cloud_print::PwgEncoder encoder
;
423 std::string pwg_header
;
424 encoder
.EncodeDocumentHeader(&pwg_header
);
425 int bytes_written
= bitmap_file
.WriteAtCurrentPos(pwg_header
.data(),
427 if (bytes_written
!= static_cast<int>(pwg_header
.size()))
430 cloud_print::BitmapImage
image(settings
.area().size(),
431 cloud_print::BitmapImage::BGRA
);
432 for (int i
= 0; i
< total_page_count
; ++i
) {
435 if (bitmap_settings
.reverse_page_order
) {
436 page_number
= total_page_count
- 1 - page_number
;
439 if (!g_pdf_lib
.Get().RenderPDFPageToBitmap(data
.data(),
443 image
.size().width(),
444 image
.size().height(),
451 cloud_print::PwgHeaderInfo header_info
;
452 header_info
.dpi
= settings
.dpi();
453 header_info
.total_pages
= total_page_count
;
455 // Transform odd pages.
456 if (page_number
% 2) {
457 switch (bitmap_settings
.odd_page_transform
) {
458 case printing::TRANSFORM_NORMAL
:
460 case printing::TRANSFORM_ROTATE_180
:
461 header_info
.flipx
= true;
462 header_info
.flipy
= true;
464 case printing::TRANSFORM_FLIP_HORIZONTAL
:
465 header_info
.flipx
= true;
467 case printing::TRANSFORM_FLIP_VERTICAL
:
468 header_info
.flipy
= true;
473 if (bitmap_settings
.rotate_all_pages
) {
474 header_info
.flipx
= !header_info
.flipx
;
475 header_info
.flipy
= !header_info
.flipy
;
478 std::string pwg_page
;
479 if (!encoder
.EncodePage(image
, header_info
, &pwg_page
))
481 bytes_written
= bitmap_file
.WriteAtCurrentPos(pwg_page
.data(),
483 if (bytes_written
!= static_cast<int>(pwg_page
.size()))
489 void PrintingHandler::OnGetPrinterCapsAndDefaults(
490 const std::string
& printer_name
) {
491 scoped_refptr
<printing::PrintBackend
> print_backend
=
492 printing::PrintBackend::CreateInstance(NULL
);
493 printing::PrinterCapsAndDefaults printer_info
;
495 crash_keys::ScopedPrinterInfo
crash_key(
496 print_backend
->GetPrinterDriverInfo(printer_name
));
498 if (print_backend
->GetPrinterCapsAndDefaults(printer_name
, &printer_info
)) {
499 Send(new ChromeUtilityHostMsg_GetPrinterCapsAndDefaults_Succeeded(
500 printer_name
, printer_info
));
502 Send(new ChromeUtilityHostMsg_GetPrinterCapsAndDefaults_Failed(
505 ReleaseProcessIfNeeded();
508 void PrintingHandler::OnGetPrinterSemanticCapsAndDefaults(
509 const std::string
& printer_name
) {
510 scoped_refptr
<printing::PrintBackend
> print_backend
=
511 printing::PrintBackend::CreateInstance(NULL
);
512 printing::PrinterSemanticCapsAndDefaults printer_info
;
514 crash_keys::ScopedPrinterInfo
crash_key(
515 print_backend
->GetPrinterDriverInfo(printer_name
));
517 if (print_backend
->GetPrinterSemanticCapsAndDefaults(printer_name
,
519 Send(new ChromeUtilityHostMsg_GetPrinterSemanticCapsAndDefaults_Succeeded(
520 printer_name
, printer_info
));
522 Send(new ChromeUtilityHostMsg_GetPrinterSemanticCapsAndDefaults_Failed(
525 ReleaseProcessIfNeeded();
527 #endif // ENABLE_FULL_PRINTING