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
)
262 #if defined(WIN_PDF_METAFILE_FOR_PRINTING)
263 IPC_MESSAGE_HANDLER(ChromeUtilityMsg_RenderPDFPagesToMetafiles
,
264 OnRenderPDFPagesToMetafile
)
266 IPC_MESSAGE_HANDLER(ChromeUtilityMsg_RenderPDFPagesToPWGRaster
,
267 OnRenderPDFPagesToPWGRaster
)
268 IPC_MESSAGE_HANDLER(ChromeUtilityMsg_GetPrinterCapsAndDefaults
,
269 OnGetPrinterCapsAndDefaults
)
270 IPC_MESSAGE_HANDLER(ChromeUtilityMsg_GetPrinterSemanticCapsAndDefaults
,
271 OnGetPrinterSemanticCapsAndDefaults
)
272 IPC_MESSAGE_UNHANDLED(handled
= false)
273 IPC_END_MESSAGE_MAP()
277 #if defined(WIN_PDF_METAFILE_FOR_PRINTING)
278 void PrintingHandler::OnRenderPDFPagesToMetafile(
279 IPC::PlatformFileForTransit pdf_transit
,
280 const base::FilePath
& metafile_path
,
281 const printing::PdfRenderSettings
& settings
,
282 const std::vector
<printing::PageRange
>& page_ranges_const
) {
283 bool succeeded
= false;
284 base::File pdf_file
= IPC::PlatformFileForTransitToFile(pdf_transit
);
285 int highest_rendered_page_number
= 0;
286 double scale_factor
= 1.0;
287 std::vector
<printing::PageRange
> page_ranges
= page_ranges_const
;
288 succeeded
= RenderPDFToWinMetafile(pdf_file
.Pass(),
292 &highest_rendered_page_number
,
295 // TODO(vitalybuka|scottmg): http://crbug.com/170859. These could
296 // potentially be sent as each page is converted so that the spool could
298 Send(new ChromeUtilityHostMsg_RenderPDFPagesToMetafiles_Succeeded(
299 page_ranges
, scale_factor
));
301 Send(new ChromeUtilityHostMsg_RenderPDFPagesToMetafile_Failed());
303 ReleaseProcessIfNeeded();
307 void PrintingHandler::OnRenderPDFPagesToPWGRaster(
308 IPC::PlatformFileForTransit pdf_transit
,
309 const printing::PdfRenderSettings
& settings
,
310 const printing::PwgRasterSettings
& bitmap_settings
,
311 IPC::PlatformFileForTransit bitmap_transit
) {
312 base::File pdf
= IPC::PlatformFileForTransitToFile(pdf_transit
);
313 base::File bitmap
= IPC::PlatformFileForTransitToFile(bitmap_transit
);
314 if (RenderPDFPagesToPWGRaster(pdf
.Pass(), settings
, bitmap_settings
,
316 Send(new ChromeUtilityHostMsg_RenderPDFPagesToPWGRaster_Succeeded());
318 Send(new ChromeUtilityHostMsg_RenderPDFPagesToPWGRaster_Failed());
320 ReleaseProcessIfNeeded();
323 #if defined(WIN_PDF_METAFILE_FOR_PRINTING)
324 bool PrintingHandler::RenderPDFToWinMetafile(
326 const base::FilePath
& metafile_path
,
327 const printing::PdfRenderSettings
& settings
,
328 std::vector
<printing::PageRange
>* page_ranges
,
329 int* highest_rendered_page_number
,
330 double* scale_factor
) {
332 *highest_rendered_page_number
= -1;
335 if (!g_pdf_lib
.Get().IsValid())
338 // TODO(sanjeevr): Add a method to the PDF DLL that takes in a file handle
339 // and a page range array. That way we don't need to read the entire PDF into
341 int64 length
= pdf_file
.GetLength();
345 std::vector
<char> buffer
;
346 buffer
.resize(length
);
347 if (length
!= pdf_file
.Read(0, &buffer
.front(), length
))
350 int total_page_count
= 0;
351 if (!g_pdf_lib
.Get().GetPDFDocInfo(&buffer
.front(), buffer
.size(),
352 &total_page_count
, NULL
)) {
356 // If no range supplied, do all pages.
357 if (page_ranges
->empty()) {
358 printing::PageRange page_range_all
;
359 page_range_all
.from
= 0;
360 page_range_all
.to
= total_page_count
- 1;
361 page_ranges
->push_back(page_range_all
);
365 std::vector
<printing::PageRange
>::const_iterator iter
;
366 for (iter
= page_ranges
->begin(); iter
!= page_ranges
->end(); ++iter
) {
367 for (int page_number
= iter
->from
; page_number
<= iter
->to
; ++page_number
) {
368 if (page_number
>= total_page_count
)
371 printing::Emf metafile
;
372 metafile
.InitToFile(metafile_path
.InsertBeforeExtensionASCII(
373 base::StringPrintf(".%d", page_number
)));
375 // We need to scale down DC to fit an entire page into DC available area.
376 // Current metafile is based on screen DC and have current screen size.
377 // Writing outside of those boundaries will result in the cut-off output.
378 // On metafiles (this is the case here), scaling down will still record
379 // original coordinates and we'll be able to print in full resolution.
380 // Before playback we'll need to counter the scaling up that will happen
381 // in the service (print_system_win.cc).
382 *scale_factor
= gfx::CalculatePageScale(metafile
.context(),
383 settings
.area().right(),
384 settings
.area().bottom());
385 gfx::ScaleDC(metafile
.context(), *scale_factor
);
387 // The underlying metafile is of type Emf and ignores the arguments passed
389 metafile
.StartPage(gfx::Size(), gfx::Rect(), 1);
390 if (g_pdf_lib
.Get().RenderPDFPageToDC(
391 &buffer
.front(), buffer
.size(), page_number
, metafile
.context(),
392 settings
.dpi(), settings
.dpi(), settings
.area().x(),
393 settings
.area().y(), settings
.area().width(),
394 settings
.area().height(), true, false, true, true,
395 settings
.autorotate())) {
396 if (*highest_rendered_page_number
< page_number
)
397 *highest_rendered_page_number
= page_number
;
400 metafile
.FinishPage();
401 metafile
.FinishDocument();
406 #endif // defined(WIN_PDF_METAFILE_FOR_PRINTING)
408 bool PrintingHandler::RenderPDFPagesToPWGRaster(
410 const printing::PdfRenderSettings
& settings
,
411 const printing::PwgRasterSettings
& bitmap_settings
,
412 base::File bitmap_file
) {
413 bool autoupdate
= true;
414 if (!g_pdf_lib
.Get().IsValid())
417 base::File::Info info
;
418 if (!pdf_file
.GetInfo(&info
) || info
.size
<= 0)
421 std::string
data(info
.size
, 0);
422 int data_size
= pdf_file
.Read(0, &data
[0], data
.size());
423 if (data_size
!= static_cast<int>(data
.size()))
426 int total_page_count
= 0;
427 if (!g_pdf_lib
.Get().GetPDFDocInfo(data
.data(), data
.size(),
428 &total_page_count
, NULL
)) {
432 cloud_print::PwgEncoder encoder
;
433 std::string pwg_header
;
434 encoder
.EncodeDocumentHeader(&pwg_header
);
435 int bytes_written
= bitmap_file
.WriteAtCurrentPos(pwg_header
.data(),
437 if (bytes_written
!= static_cast<int>(pwg_header
.size()))
440 cloud_print::BitmapImage
image(settings
.area().size(),
441 cloud_print::BitmapImage::BGRA
);
442 for (int i
= 0; i
< total_page_count
; ++i
) {
445 if (bitmap_settings
.reverse_page_order
) {
446 page_number
= total_page_count
- 1 - page_number
;
449 if (!g_pdf_lib
.Get().RenderPDFPageToBitmap(data
.data(),
453 image
.size().width(),
454 image
.size().height(),
461 cloud_print::PwgHeaderInfo header_info
;
462 header_info
.dpi
= settings
.dpi();
463 header_info
.total_pages
= total_page_count
;
465 // Transform odd pages.
466 if (page_number
% 2) {
467 switch (bitmap_settings
.odd_page_transform
) {
468 case printing::TRANSFORM_NORMAL
:
470 case printing::TRANSFORM_ROTATE_180
:
471 header_info
.flipx
= true;
472 header_info
.flipy
= true;
474 case printing::TRANSFORM_FLIP_HORIZONTAL
:
475 header_info
.flipx
= true;
477 case printing::TRANSFORM_FLIP_VERTICAL
:
478 header_info
.flipy
= true;
483 if (bitmap_settings
.rotate_all_pages
) {
484 header_info
.flipx
= !header_info
.flipx
;
485 header_info
.flipy
= !header_info
.flipy
;
488 std::string pwg_page
;
489 if (!encoder
.EncodePage(image
, header_info
, &pwg_page
))
491 bytes_written
= bitmap_file
.WriteAtCurrentPos(pwg_page
.data(),
493 if (bytes_written
!= static_cast<int>(pwg_page
.size()))
499 void PrintingHandler::OnGetPrinterCapsAndDefaults(
500 const std::string
& printer_name
) {
501 scoped_refptr
<printing::PrintBackend
> print_backend
=
502 printing::PrintBackend::CreateInstance(NULL
);
503 printing::PrinterCapsAndDefaults printer_info
;
505 crash_keys::ScopedPrinterInfo
crash_key(
506 print_backend
->GetPrinterDriverInfo(printer_name
));
508 if (print_backend
->GetPrinterCapsAndDefaults(printer_name
, &printer_info
)) {
509 Send(new ChromeUtilityHostMsg_GetPrinterCapsAndDefaults_Succeeded(
510 printer_name
, printer_info
));
512 Send(new ChromeUtilityHostMsg_GetPrinterCapsAndDefaults_Failed(
515 ReleaseProcessIfNeeded();
518 void PrintingHandler::OnGetPrinterSemanticCapsAndDefaults(
519 const std::string
& printer_name
) {
520 scoped_refptr
<printing::PrintBackend
> print_backend
=
521 printing::PrintBackend::CreateInstance(NULL
);
522 printing::PrinterSemanticCapsAndDefaults printer_info
;
524 crash_keys::ScopedPrinterInfo
crash_key(
525 print_backend
->GetPrinterDriverInfo(printer_name
));
527 if (print_backend
->GetPrinterSemanticCapsAndDefaults(printer_name
,
529 Send(new ChromeUtilityHostMsg_GetPrinterSemanticCapsAndDefaults_Succeeded(
530 printer_name
, printer_info
));
532 Send(new ChromeUtilityHostMsg_GetPrinterSemanticCapsAndDefaults_Failed(
535 ReleaseProcessIfNeeded();