0

Windows: Make it possible to print text with GDI.

This only affects the printing of web pages directly on the host.

- Renderer tells the browser if the print job is HTML. (AKA modifiable)
-- Browser does lots of plumbing to get the bool into PrintSettings.
-- Print preview already sends this info and it just needs extraction.
- Add --disable-gdi-text-printing for reverting to old behavior.
- Browser plumbs bool to PdfToEmfConverter to the utility process.
- Utility plumbs bool into the PDF plugin code into PDFium.
- Move unused PreCacheFontCharacters code out of RenderThreadImpl.
-- Use it in PrintingHandler instead.
- Remove dead code, fix lint errors / typos.

BUG=409472

Review-Url: https://codereview.chromium.org/2114583002
Cr-Commit-Position: refs/heads/master@{#414209}
This commit is contained in:
thestig
2016-08-24 17:00:06 -07:00
committed by Commit bot
parent fcf3423ed3
commit e85e6b6cf8
39 changed files with 287 additions and 240 deletions

@ -11,5 +11,5 @@ pdf_enable_xfa_override = false
# Disable use of Skia backend.
pdf_use_skia_override = false
# Disable experimental win32 APIs.
pdf_use_win32_gdi_override = false
# Enable experimental win32 GDI APIs.
pdf_use_win32_gdi_override = true

@ -5,6 +5,7 @@
#include "chrome/browser/printing/pdf_to_emf_converter.h"
#include <stdint.h>
#include <windows.h>
#include <memory>
#include <queue>
@ -107,6 +108,7 @@ class PdfToEmfUtilityProcessHostClient
const PdfRenderSettings& settings);
void Start(const scoped_refptr<base::RefCountedMemory>& data,
bool print_text_with_gdi,
const PdfToEmfConverter::StartCallback& start_callback);
void GetPage(int page_number,
@ -114,6 +116,10 @@ class PdfToEmfUtilityProcessHostClient
void Stop();
// Needs to be public to handle ChromeUtilityHostMsg_PreCacheFontCharacters
// sync message replies.
bool Send(IPC::Message* msg);
// UtilityProcessHostClient implementation.
void OnProcessCrashed(int exit_code) override;
void OnProcessLaunchFailed(int exit_code) override;
@ -154,14 +160,14 @@ class PdfToEmfUtilityProcessHostClient
~PdfToEmfUtilityProcessHostClient() override;
bool Send(IPC::Message* msg);
// Message handlers.
void OnPageCount(int page_count);
void OnPageDone(bool success, float scale_factor);
void OnPreCacheFontCharacters(const LOGFONT& log_font,
const base::string16& characters);
void OnFailed();
void OnTempPdfReady(ScopedTempFile pdf);
void OnTempPdfReady(bool print_text_with_gdi, ScopedTempFile pdf);
void OnTempEmfReady(GetPageCallbackData* callback_data, ScopedTempFile emf);
scoped_refptr<RefCountedTempDir> temp_dir_;
@ -193,6 +199,7 @@ class PdfToEmfConverterImpl : public PdfToEmfConverter {
void Start(const scoped_refptr<base::RefCountedMemory>& data,
const PdfRenderSettings& conversion_settings,
bool print_text_with_gdi,
const StartCallback& start_callback) override;
void GetPage(int page_number,
@ -297,14 +304,13 @@ PdfToEmfUtilityProcessHostClient::~PdfToEmfUtilityProcessHostClient() {
void PdfToEmfUtilityProcessHostClient::Start(
const scoped_refptr<base::RefCountedMemory>& data,
bool print_text_with_gdi,
const PdfToEmfConverter::StartCallback& start_callback) {
if (!BrowserThread::CurrentlyOn(BrowserThread::IO)) {
BrowserThread::PostTask(BrowserThread::IO,
FROM_HERE,
base::Bind(&PdfToEmfUtilityProcessHostClient::Start,
this,
data,
start_callback));
BrowserThread::PostTask(
BrowserThread::IO, FROM_HERE,
base::Bind(&PdfToEmfUtilityProcessHostClient::Start, this, data,
print_text_with_gdi, start_callback));
return;
}
@ -321,20 +327,21 @@ void PdfToEmfUtilityProcessHostClient::Start(
IDS_UTILITY_PROCESS_EMF_CONVERTOR_NAME));
BrowserThread::PostTaskAndReplyWithResult(
BrowserThread::FILE,
FROM_HERE,
BrowserThread::FILE, FROM_HERE,
base::Bind(&CreateTempPdfFile, data, &temp_dir_),
base::Bind(&PdfToEmfUtilityProcessHostClient::OnTempPdfReady, this));
base::Bind(&PdfToEmfUtilityProcessHostClient::OnTempPdfReady, this,
print_text_with_gdi));
}
void PdfToEmfUtilityProcessHostClient::OnTempPdfReady(ScopedTempFile pdf) {
void PdfToEmfUtilityProcessHostClient::OnTempPdfReady(bool print_text_with_gdi,
ScopedTempFile pdf) {
DCHECK_CURRENTLY_ON(BrowserThread::IO);
if (!utility_process_host_ || !pdf)
return OnFailed();
// Should reply with OnPageCount().
Send(new ChromeUtilityMsg_RenderPDFPagesToMetafiles(
IPC::GetPlatformFileForTransit(pdf->GetPlatformFile(), false),
settings_));
IPC::GetPlatformFileForTransit(pdf->GetPlatformFile(), false), settings_,
print_text_with_gdi));
}
void PdfToEmfUtilityProcessHostClient::OnPageCount(int page_count) {
@ -418,6 +425,38 @@ void PdfToEmfUtilityProcessHostClient::OnPageDone(bool success,
get_page_callbacks_.pop();
}
void PdfToEmfUtilityProcessHostClient::OnPreCacheFontCharacters(
const LOGFONT& font,
const base::string16& str) {
// TODO(scottmg): pdf/ppapi still require the renderer to be able to precache
// GDI fonts (http://crbug.com/383227), even when using DirectWrite.
// Eventually this shouldn't be added and should be moved to
// FontCacheDispatcher too. http://crbug.com/356346.
// First, comments from FontCacheDispatcher::OnPreCacheFont do apply here too.
// Except that for True Type fonts,
// GetTextMetrics will not load the font in memory.
// The only way windows seem to load properly, it is to create a similar
// device (like the one in which we print), then do an ExtTextOut,
// as we do in the printing thread, which is sandboxed.
HDC hdc = CreateEnhMetaFile(nullptr, nullptr, nullptr, nullptr);
HFONT font_handle = CreateFontIndirect(&font);
DCHECK(font_handle != nullptr);
HGDIOBJ old_font = SelectObject(hdc, font_handle);
DCHECK(old_font != nullptr);
ExtTextOut(hdc, 0, 0, ETO_GLYPH_INDEX, 0, str.c_str(), str.length(), nullptr);
SelectObject(hdc, old_font);
DeleteObject(font_handle);
HENHMETAFILE metafile = CloseEnhMetaFile(hdc);
if (metafile)
DeleteEnhMetaFile(metafile);
}
void PdfToEmfUtilityProcessHostClient::Stop() {
if (!BrowserThread::CurrentlyOn(BrowserThread::IO)) {
BrowserThread::PostTask(
@ -445,6 +484,8 @@ bool PdfToEmfUtilityProcessHostClient::OnMessageReceived(
ChromeUtilityHostMsg_RenderPDFPagesToMetafiles_PageCount, OnPageCount)
IPC_MESSAGE_HANDLER(ChromeUtilityHostMsg_RenderPDFPagesToMetafiles_PageDone,
OnPageDone)
IPC_MESSAGE_HANDLER(ChromeUtilityHostMsg_PreCacheFontCharacters,
OnPreCacheFontCharacters)
IPC_MESSAGE_UNHANDLED(handled = false)
IPC_END_MESSAGE_MAP()
return handled;
@ -477,11 +518,12 @@ PdfToEmfConverterImpl::~PdfToEmfConverterImpl() {
void PdfToEmfConverterImpl::Start(
const scoped_refptr<base::RefCountedMemory>& data,
const PdfRenderSettings& conversion_settings,
bool print_text_with_gdi,
const StartCallback& start_callback) {
DCHECK(!utility_client_.get());
utility_client_ = new PdfToEmfUtilityProcessHostClient(
weak_ptr_factory_.GetWeakPtr(), conversion_settings);
utility_client_->Start(data, start_callback);
utility_client_->Start(data, print_text_with_gdi, start_callback);
}
void PdfToEmfConverterImpl::GetPage(int page_number,

@ -35,6 +35,7 @@ class PdfToEmfConverter {
// with positive |page_count|. |page_count| is 0 if initialization failed.
virtual void Start(const scoped_refptr<base::RefCountedMemory>& data,
const PdfRenderSettings& conversion_settings,
bool print_text_with_gdi,
const StartCallback& start_callback) = 0;
// Requests conversion of the page. |page_number| is 0-base page number in

@ -234,8 +234,10 @@ class PrintJob::PdfToEmfState {
void Start(const scoped_refptr<base::RefCountedMemory>& data,
const PdfRenderSettings& conversion_settings,
bool print_text_with_gdi,
const PdfToEmfConverter::StartCallback& start_callback) {
converter_->Start(data, conversion_settings, start_callback);
converter_->Start(data, conversion_settings, print_text_with_gdi,
start_callback);
}
void GetMorePages(
@ -277,13 +279,14 @@ void PrintJob::AppendPrintedPage(int page_number) {
void PrintJob::StartPdfToEmfConversion(
const scoped_refptr<base::RefCountedMemory>& bytes,
const gfx::Size& page_size,
const gfx::Rect& content_area) {
const gfx::Rect& content_area,
bool print_text_with_gdi) {
DCHECK(!pdf_to_emf_state_);
pdf_to_emf_state_ = base::MakeUnique<PdfToEmfState>(page_size, content_area);
const int kPrinterDpi = settings().dpi();
pdf_to_emf_state_->Start(bytes,
PdfRenderSettings(content_area, kPrinterDpi, true),
base::Bind(&PrintJob::OnPdfToEmfStarted, this));
pdf_to_emf_state_->Start(
bytes, PdfRenderSettings(content_area, kPrinterDpi, true),
print_text_with_gdi, base::Bind(&PrintJob::OnPdfToEmfStarted, this));
}
void PrintJob::OnPdfToEmfStarted(int page_count) {

@ -97,7 +97,8 @@ class PrintJob : public PrintJobWorkerOwner,
void StartPdfToEmfConversion(
const scoped_refptr<base::RefCountedMemory>& bytes,
const gfx::Size& page_size,
const gfx::Rect& content_area);
const gfx::Rect& content_area,
bool print_text_with_gdi);
#endif // defined(OS_WIN)
protected:

@ -134,12 +134,12 @@ void PrintJobWorker::SetNewOwner(PrintJobWorkerOwner* new_owner) {
owner_ = new_owner;
}
void PrintJobWorker::GetSettings(
bool ask_user_for_settings,
int document_page_count,
bool has_selection,
MarginType margin_type,
bool is_scripted) {
void PrintJobWorker::GetSettings(bool ask_user_for_settings,
int document_page_count,
bool has_selection,
MarginType margin_type,
bool is_scripted,
bool is_modifiable) {
DCHECK(task_runner_->RunsTasksOnCurrentThread());
DCHECK_EQ(page_number_, PageNumber::npos());
@ -150,6 +150,7 @@ void PrintJobWorker::GetSettings(
// should happen on the same thread. See http://crbug.com/73466
// MessageLoop::current()->SetNestableTasksAllowed(true);
printing_context_->set_margin_type(margin_type);
printing_context_->set_is_modifiable(is_modifiable);
// When we delegate to a destination, we don't ask the user for settings.
// TODO(mad): Ask the destination for settings.

@ -45,12 +45,13 @@ class PrintJobWorker {
// Initializes the print settings. If |ask_user_for_settings| is true, a
// Print... dialog box will be shown to ask the user his preference.
// |is_scripted| should be true for calls coming straight from window.print().
void GetSettings(
bool ask_user_for_settings,
int document_page_count,
bool has_selection,
MarginType margin_type,
bool is_scripted);
// |is_modifiable| implies HTML and not other formats like PDF.
void GetSettings(bool ask_user_for_settings,
int document_page_count,
bool has_selection,
MarginType margin_type,
bool is_scripted,
bool is_modifiable);
// Set the new print settings.
void SetSettings(std::unique_ptr<base::DictionaryValue> new_settings);

@ -41,6 +41,11 @@
#include "chrome/browser/printing/print_error_dialog.h"
#endif
#if defined(OS_WIN)
#include "base/command_line.h"
#include "chrome/common/chrome_switches.h"
#endif
using base::TimeDelta;
using content::BrowserThread;
@ -185,13 +190,17 @@ void PrintViewManagerBase::OnDidPrintPage(
#if defined(OS_WIN)
print_job_->AppendPrintedPage(params.page_number);
if (metafile_must_be_valid) {
bool print_text_with_gdi =
document->settings().print_text_with_gdi() &&
!base::CommandLine::ForCurrentProcess()->HasSwitch(
switches::kDisableGDITextPrinting);
scoped_refptr<base::RefCountedBytes> bytes = new base::RefCountedBytes(
reinterpret_cast<const unsigned char*>(shared_buf->memory()),
params.data_size);
document->DebugDumpData(bytes.get(), FILE_PATH_LITERAL(".pdf"));
print_job_->StartPdfToEmfConversion(
bytes, params.page_size, params.content_area);
bytes, params.page_size, params.content_area, print_text_with_gdi);
}
#else
// Update the rendered document. It will send notifications to the listener.

@ -65,13 +65,13 @@ int PrinterQuery::cookie() const {
return cookie_;
}
void PrinterQuery::GetSettings(
GetSettingsAskParam ask_user_for_settings,
int expected_page_count,
bool has_selection,
MarginType margin_type,
bool is_scripted,
const base::Closure& callback) {
void PrinterQuery::GetSettings(GetSettingsAskParam ask_user_for_settings,
int expected_page_count,
bool has_selection,
MarginType margin_type,
bool is_scripted,
bool is_modifiable,
const base::Closure& callback) {
DCHECK(RunsTasksOnCurrentThread());
DCHECK(!is_print_dialog_box_shown_ || !is_scripted);
@ -80,14 +80,11 @@ void PrinterQuery::GetSettings(
// Real work is done in PrintJobWorker::GetSettings().
is_print_dialog_box_shown_ =
ask_user_for_settings == GetSettingsAskParam::ASK_USER;
worker_->PostTask(FROM_HERE,
base::Bind(&PrintJobWorker::GetSettings,
base::Unretained(worker_.get()),
is_print_dialog_box_shown_,
expected_page_count,
has_selection,
margin_type,
is_scripted));
worker_->PostTask(
FROM_HERE,
base::Bind(&PrintJobWorker::GetSettings, base::Unretained(worker_.get()),
is_print_dialog_box_shown_, expected_page_count, has_selection,
margin_type, is_scripted, is_modifiable));
}
void PrinterQuery::SetSettings(

@ -44,13 +44,13 @@ class PrinterQuery : public PrintJobWorkerOwner {
// times to reinitialize the settings. |web_contents_observer| can be queried
// to find the owner of the print setting dialog box. It is unused when
// |ask_for_user_settings| is DEFAULTS.
void GetSettings(
GetSettingsAskParam ask_user_for_settings,
int expected_page_count,
bool has_selection,
MarginType margin_type,
bool is_scripted,
const base::Closure& callback);
void GetSettings(GetSettingsAskParam ask_user_for_settings,
int expected_page_count,
bool has_selection,
MarginType margin_type,
bool is_scripted,
bool is_modifiable,
const base::Closure& callback);
// Updates the current settings with |new_settings| dictionary values.
void SetSettings(std::unique_ptr<base::DictionaryValue> new_settings,

@ -26,15 +26,6 @@
#include "chrome/browser/ui/webui/print_preview/print_preview_ui.h"
#endif
#if defined(OS_CHROMEOS)
#include <fcntl.h>
#include <map>
#include "base/files/file_util.h"
#include "base/lazy_instance.h"
#endif
#if defined(OS_ANDROID)
#include "base/strings/string_number_conversions.h"
#include "chrome/browser/printing/print_view_manager_basic.h"
@ -163,15 +154,10 @@ void PrintingMessageFilter::OnGetDefaultPrintSettings(IPC::Message* reply_msg) {
// Loads default settings. This is asynchronous, only the IPC message sender
// will hang until the settings are retrieved.
printer_query->GetSettings(
PrinterQuery::GetSettingsAskParam::DEFAULTS,
0,
false,
DEFAULT_MARGINS,
false,
base::Bind(&PrintingMessageFilter::OnGetDefaultPrintSettingsReply,
this,
printer_query,
reply_msg));
PrinterQuery::GetSettingsAskParam::DEFAULTS, 0, false, DEFAULT_MARGINS,
false, false,
base::Bind(&PrintingMessageFilter::OnGetDefaultPrintSettingsReply, this,
printer_query, reply_msg));
}
void PrintingMessageFilter::OnGetDefaultPrintSettingsReply(
@ -208,15 +194,11 @@ void PrintingMessageFilter::OnScriptedPrint(
queue_->CreatePrinterQuery(render_process_id_, reply_msg->routing_id());
}
printer_query->GetSettings(
PrinterQuery::GetSettingsAskParam::ASK_USER,
params.expected_pages_count,
params.has_selection,
params.margin_type,
params.is_scripted,
base::Bind(&PrintingMessageFilter::OnScriptedPrintReply,
this,
printer_query,
reply_msg));
PrinterQuery::GetSettingsAskParam::ASK_USER, params.expected_pages_count,
params.has_selection, params.margin_type, params.is_scripted,
params.is_modifiable,
base::Bind(&PrintingMessageFilter::OnScriptedPrintReply, this,
printer_query, reply_msg));
}
void PrintingMessageFilter::OnScriptedPrintReply(

@ -1198,6 +1198,10 @@ const char kRelauncherProcessDMGDevice[] = "dmg-device";
#endif // defined(OS_MACOSX)
#if defined(OS_WIN)
// Disables using GDI to print text as simply text. Fallback to printing text
// as paths.
const char kDisableGDITextPrinting[] = "disable-gdi-text-printing";
// Disables per monitor DPI for supported Windows versions.
// This flag overrides kEnablePerMonitorDpi.
const char kDisablePerMonitorDpi[] = "disable-per-monitor-dpi";

@ -310,7 +310,7 @@ extern const char kWebApkServerUrl[];
#if defined(OS_CHROMEOS)
extern const char kEnableNativeCups[];
#endif // defined(OS_CHROMEOS)
#endif // defined(OS_CHROMEOS)
#if defined(USE_ASH)
extern const char kOpenAsh[];
@ -348,6 +348,7 @@ extern const char kRelauncherProcessDMGDevice[];
#endif // defined(OS_MACOSX)
#if defined(OS_WIN)
extern const char kDisableGDITextPrinting[];
extern const char kDisablePerMonitorDpi[];
extern const char kEnableCloudPrintXps[];
extern const char kEnablePerMonitorDpi[];

@ -7,6 +7,7 @@
#include <string>
#include <vector>
#include "base/strings/string16.h"
#include "build/build_config.h"
#include "components/printing/common/printing_param_traits_macros.h"
#include "ipc/ipc_message_macros.h"
@ -16,6 +17,10 @@
#include "printing/pdf_render_settings.h"
#include "printing/pwg_raster_settings.h"
#if defined(OS_WIN)
#include <windows.h>
#endif
#define IPC_MESSAGE_START ChromeUtilityPrintingMsgStart
// Preview and Cloud Print messages.
@ -66,8 +71,8 @@ IPC_STRUCT_TRAITS_END()
// Tell the utility process to render the given PDF into a PWGRaster.
IPC_MESSAGE_CONTROL4(ChromeUtilityMsg_RenderPDFPagesToPWGRaster,
IPC::PlatformFileForTransit, /* Input PDF file */
printing::PdfRenderSettings, /* PDF render settings */
IPC::PlatformFileForTransit /* Input PDF file */,
printing::PdfRenderSettings /* PDF render settings */,
// PWG transform settings.
printing::PwgRasterSettings,
IPC::PlatformFileForTransit /* Output PWG file */)
@ -93,9 +98,10 @@ IPC_MESSAGE_CONTROL1(ChromeUtilityMsg_GetPrinterSemanticCapsAndDefaults,
// Tell the utility process to start rendering the given PDF into a metafile.
// Utility process would be alive until
// ChromeUtilityMsg_RenderPDFPagesToMetafiles_Stop message.
IPC_MESSAGE_CONTROL2(ChromeUtilityMsg_RenderPDFPagesToMetafiles,
IPC::PlatformFileForTransit, /* input_file */
printing::PdfRenderSettings /* settings */)
IPC_MESSAGE_CONTROL3(ChromeUtilityMsg_RenderPDFPagesToMetafiles,
IPC::PlatformFileForTransit /* input_file */,
printing::PdfRenderSettings /* settings */,
bool /* print_text_with_gdi */)
// Requests conversion of the next page.
IPC_MESSAGE_CONTROL2(ChromeUtilityMsg_RenderPDFPagesToMetafiles_GetPage,
@ -152,4 +158,12 @@ IPC_MESSAGE_CONTROL1(ChromeUtilityHostMsg_RenderPDFPagesToMetafiles_PageCount,
IPC_MESSAGE_CONTROL2(ChromeUtilityHostMsg_RenderPDFPagesToMetafiles_PageDone,
bool /* success */,
float /* scale_factor */)
// Request that the given font characters be loaded by the browser so it's
// cached by the OS. Please see
// PdfToEmfUtilityProcessHostClient::OnPreCacheFontCharacters for details.
IPC_SYNC_MESSAGE_CONTROL2_0(ChromeUtilityHostMsg_PreCacheFontCharacters,
LOGFONT /* font_data */,
base::string16 /* characters */)
#endif // ENABLE_PRINTING && OS_WIN

@ -99,7 +99,7 @@ class ServiceUtilityProcessHost::PdfToEmfState {
return false;
return host_->Send(new ChromeUtilityMsg_RenderPDFPagesToMetafiles(
IPC::TakePlatformFileForTransit(std::move(pdf_file)),
conversion_settings));
conversion_settings, false /* print_text_with_gdi */));
}
void GetMorePages() {

@ -102,7 +102,7 @@ void CreateResourceUsageReporter(
mojo::InterfaceRequest<mojom::ResourceUsageReporter> request) {
new ResourceUsageReporterImpl(std::move(request));
}
#endif // OS_ANDROID
#endif // !defined(OS_ANDROID)
void CreateImageDecoder(mojo::InterfaceRequest<mojom::ImageDecoder> request) {
content::UtilityThread::Get()->EnsureBlinkInitialized();

@ -40,9 +40,22 @@ void ReleaseProcessIfNeeded() {
content::UtilityThread::Get()->ReleaseProcessIfNeeded();
}
#if defined(OS_WIN)
void PreCacheFontCharacters(const LOGFONT* logfont,
const wchar_t* text,
size_t text_length) {
Send(new ChromeUtilityHostMsg_PreCacheFontCharacters(
*logfont, base::string16(text, text_length)));
}
#endif
} // namespace
PrintingHandler::PrintingHandler() {}
PrintingHandler::PrintingHandler() {
#if defined(OS_WIN)
chrome_pdf::SetPDFEnsureTypefaceCharactersAccessible(PreCacheFontCharacters);
#endif
}
PrintingHandler::~PrintingHandler() {}
@ -73,8 +86,10 @@ bool PrintingHandler::OnMessageReceived(const IPC::Message& message) {
#if defined(OS_WIN)
void PrintingHandler::OnRenderPDFPagesToMetafile(
IPC::PlatformFileForTransit pdf_transit,
const PdfRenderSettings& settings) {
const PdfRenderSettings& settings,
bool print_text_with_gdi) {
pdf_rendering_settings_ = settings;
chrome_pdf::SetPDFUseGDIPrinting(print_text_with_gdi);
base::File pdf_file = IPC::PlatformFileForTransitToFile(pdf_transit);
int page_count = LoadPDF(std::move(pdf_file));
Send(

@ -36,7 +36,8 @@ class PrintingHandler : public UtilityMessageHandler {
// IPC message handlers.
#if defined(OS_WIN)
void OnRenderPDFPagesToMetafile(IPC::PlatformFileForTransit pdf_transit,
const PdfRenderSettings& settings);
const PdfRenderSettings& settings,
bool print_text_with_gdi);
void OnRenderPDFPagesToMetafileGetPage(
int page_number,
IPC::PlatformFileForTransit output_file);

@ -304,6 +304,7 @@ IPC_STRUCT_BEGIN(PrintHostMsg_ScriptedPrint_Params)
IPC_STRUCT_MEMBER(int, expected_pages_count)
IPC_STRUCT_MEMBER(bool, has_selection)
IPC_STRUCT_MEMBER(bool, is_scripted)
IPC_STRUCT_MEMBER(bool, is_modifiable)
IPC_STRUCT_MEMBER(printing::MarginType, margin_type)
IPC_STRUCT_END()

@ -1704,6 +1704,7 @@ bool PrintWebViewHelper::GetPrintSettingsFromUser(blink::WebLocalFrame* frame,
}
params.margin_type = margin_type;
params.is_scripted = is_scripted;
params.is_modifiable = !PrintingNodeOrPdfFrame(frame, node);
Send(new PrintHostMsg_DidShowPrintDialog(routing_id()));

@ -212,9 +212,6 @@ bool RenderMessageFilter::OnMessageReceived(const IPC::Message& message) {
OnCacheableMetadataAvailableForCacheStorage)
#if defined(OS_MACOSX)
IPC_MESSAGE_HANDLER_DELAY_REPLY(RenderProcessHostMsg_LoadFont, OnLoadFont)
#elif defined(OS_WIN)
IPC_MESSAGE_HANDLER(RenderProcessHostMsg_PreCacheFontCharacters,
OnPreCacheFontCharacters)
#endif
IPC_MESSAGE_HANDLER(ViewHostMsg_MediaLogEvents, OnMediaLogEvents)
IPC_MESSAGE_UNHANDLED(handled = false)
@ -321,42 +318,7 @@ void RenderMessageFilter::SendLoadFontReply(IPC::Message* reply,
Send(reply);
}
#elif defined(OS_WIN)
void RenderMessageFilter::OnPreCacheFontCharacters(
const LOGFONT& font,
const base::string16& str) {
// TODO(scottmg): pdf/ppapi still require the renderer to be able to precache
// GDI fonts (http://crbug.com/383227), even when using DirectWrite.
// Eventually this shouldn't be added and should be moved to
// FontCacheDispatcher too. http://crbug.com/356346.
// First, comments from FontCacheDispatcher::OnPreCacheFont do apply here too.
// Except that for True Type fonts,
// GetTextMetrics will not load the font in memory.
// The only way windows seem to load properly, it is to create a similar
// device (like the one in which we print), then do an ExtTextOut,
// as we do in the printing thread, which is sandboxed.
HDC hdc = CreateEnhMetaFile(NULL, NULL, NULL, NULL);
HFONT font_handle = CreateFontIndirect(&font);
DCHECK(NULL != font_handle);
HGDIOBJ old_font = SelectObject(hdc, font_handle);
DCHECK(NULL != old_font);
ExtTextOut(hdc, 0, 0, ETO_GLYPH_INDEX, 0, str.c_str(), str.length(), NULL);
SelectObject(hdc, old_font);
DeleteObject(font_handle);
HENHMETAFILE metafile = CloseEnhMetaFile(hdc);
if (metafile)
DeleteEnhMetaFile(metafile);
}
#endif // OS_*
#endif // defined(OS_MACOSX)
void RenderMessageFilter::AllocateSharedMemoryOnFileThread(
uint32_t buffer_size,

@ -132,9 +132,6 @@ class CONTENT_EXPORT RenderMessageFilter : public BrowserMessageFilter {
// Messages for OOP font loading.
void OnLoadFont(const FontDescriptor& font, IPC::Message* reply_msg);
void SendLoadFontReply(IPC::Message* reply, FontLoader::Result* result);
#elif defined(OS_WIN)
void OnPreCacheFontCharacters(const LOGFONT& log_font,
const base::string16& characters);
#endif
void OnGenerateRoutingID(int* route_id);

@ -77,11 +77,4 @@ IPC_SYNC_MESSAGE_CONTROL1_3(RenderProcessHostMsg_LoadFont,
uint32_t /* buffer size */,
base::SharedMemoryHandle /* font data */,
uint32_t /* font id */)
#elif defined(OS_WIN)
// Request that the given font characters be loaded by the browser so it's
// cached by the OS. Please see RenderMessageFilter::OnPreCacheFontCharacters
// for details.
IPC_SYNC_MESSAGE_CONTROL2_0(RenderProcessHostMsg_PreCacheFontCharacters,
LOGFONT /* font_data */,
base::string16 /* characters */)
#endif

@ -1506,14 +1506,6 @@ base::WaitableEvent* RenderThreadImpl::GetShutdownEvent() {
return ChildProcess::current()->GetShutDownEvent();
}
#if defined(OS_WIN)
void RenderThreadImpl::PreCacheFontCharacters(const LOGFONT& log_font,
const base::string16& str) {
Send(new RenderProcessHostMsg_PreCacheFontCharacters(log_font, str));
}
#endif // OS_WIN
bool RenderThreadImpl::IsGpuRasterizationForced() {
return is_gpu_rasterization_forced_;
}

@ -65,7 +65,8 @@ static_library("pdf") {
]
}
defines = [ "PDFIUM_PRINT_TEXT_WITH_GDI" ]
if (pdf_enable_xfa) {
defines = [ "PDF_ENABLE_XFA" ]
defines += [ "PDF_ENABLE_XFA" ]
}
}

@ -115,6 +115,14 @@ bool RenderPDFPageToDC(const void* pdf_buffer,
return ret;
}
void SetPDFEnsureTypefaceCharactersAccessible(
PDFEnsureTypefaceCharactersAccessible func) {
PDFEngineExports::Get()->SetPDFEnsureTypefaceCharactersAccessible(func);
}
void SetPDFUseGDIPrinting(bool enable) {
PDFEngineExports::Get()->SetPDFUseGDIPrinting(enable);
}
#endif // defined(OS_WIN)
bool GetPDFDocInfo(const void* pdf_buffer,

@ -8,6 +8,16 @@
#include "ppapi/c/ppb.h"
#include "ppapi/cpp/module.h"
#if defined(OS_WIN)
#include <windows.h>
#endif
#if defined(OS_WIN)
typedef void (*PDFEnsureTypefaceCharactersAccessible)(const LOGFONT* font,
const wchar_t* text,
size_t text_length);
#endif
namespace chrome_pdf {
class PDFModule : public pp::Module {
@ -67,7 +77,13 @@ bool RenderPDFPageToDC(const void* pdf_buffer,
bool keep_aspect_ratio,
bool center_in_bounds,
bool autorotate);
#endif
void SetPDFEnsureTypefaceCharactersAccessible(
PDFEnsureTypefaceCharactersAccessible func);
void SetPDFUseGDIPrinting(bool enable);
#endif // defined(OS_WIN)
// |page_count| and |max_page_width| are optional and can be NULL.
// Returns false if the document is not valid.
bool GetPDFDocInfo(const void* pdf_buffer,

@ -29,6 +29,12 @@
#include "ppapi/cpp/var_array.h"
#include "ui/base/window_open_disposition.h"
#if defined(OS_WIN)
typedef void (*PDFEnsureTypefaceCharactersAccessible)(const LOGFONT* font,
const wchar_t* text,
size_t text_length);
#endif
namespace pp {
class InputEvent;
class VarDictionary;
@ -329,7 +335,13 @@ class PDFEngineExports {
int page_number,
const RenderingSettings& settings,
HDC dc) = 0;
#endif // OS_WIN
virtual void SetPDFEnsureTypefaceCharactersAccessible(
PDFEnsureTypefaceCharactersAccessible func) = 0;
virtual void SetPDFUseGDIPrinting(bool enable) = 0;
#endif // defined(OS_WIN)
// See the definition of RenderPDFPageToBitmap in pdf.cc for details.
virtual bool RenderPDFPageToBitmap(const void* pdf_buffer,
int pdf_buffer_size,

@ -53,6 +53,7 @@
#include "third_party/pdfium/public/fpdf_searchex.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/gfx/geometry/rect.h"
#include "v8/include/v8.h"
@ -3876,6 +3877,16 @@ bool PDFiumEngineExports::RenderPDFPageToDC(const void* pdf_buffer,
FPDF_CloseDocument(doc);
return true;
}
void PDFiumEngineExports::SetPDFEnsureTypefaceCharactersAccessible(
PDFEnsureTypefaceCharactersAccessible func) {
FPDF_SetTypefaceAccessibleFunc(
reinterpret_cast<PDFiumEnsureTypefaceCharactersAccessible>(func));
}
void PDFiumEngineExports::SetPDFUseGDIPrinting(bool enable) {
FPDF_SetPrintTextWithGDI(enable);
}
#endif // defined(OS_WIN)
bool PDFiumEngineExports::RenderPDFPageToBitmap(

@ -742,6 +742,10 @@ class PDFiumEngineExports : public PDFEngineExports {
int page_number,
const RenderingSettings& settings,
HDC dc) override;
void SetPDFEnsureTypefaceCharactersAccessible(
PDFEnsureTypefaceCharactersAccessible func) override;
void SetPDFUseGDIPrinting(bool enable) override;
#endif // defined(OS_WIN)
bool RenderPDFPageToBitmap(const void* pdf_buffer,
int pdf_buffer_size,

@ -149,6 +149,9 @@ void PrintSettings::Clear() {
color_ = UNKNOWN_COLOR_MODEL;
copies_ = 0;
duplex_mode_ = UNKNOWN_DUPLEX_MODE;
#if defined(OS_WIN)
print_text_with_gdi_ = false;
#endif
}
void PrintSettings::SetPrinterPrintableArea(

@ -106,8 +106,8 @@ class PRINTING_EXPORT PrintSettings {
#endif // defined(OS_MACOSX)
}
void set_ranges(const PageRanges& ranges) { ranges_ = ranges; };
const PageRanges& ranges() const { return ranges_; };
void set_ranges(const PageRanges& ranges) { ranges_ = ranges; }
const PageRanges& ranges() const { return ranges_; }
void set_selection_only(bool selection_only) {
selection_only_ = selection_only;
@ -144,6 +144,11 @@ class PRINTING_EXPORT PrintSettings {
int desired_dpi() const { return desired_dpi_; }
#if defined(OS_WIN)
void set_print_text_with_gdi(bool use_gdi) { print_text_with_gdi_ = use_gdi; }
bool print_text_with_gdi() const { return print_text_with_gdi_; }
#endif
// Cookie generator. It is used to initialize PrintedDocument with its
// associated PrintSettings, to be sure that each generated PrintedPage is
// correctly associated with its corresponding PrintedDocument.
@ -204,6 +209,11 @@ class PRINTING_EXPORT PrintSettings {
// True if this printer supports AlphaBlend.
bool supports_alpha_blend_;
#if defined(OS_WIN)
// True to print text with GDI.
bool print_text_with_gdi_;
#endif
// If margin type is custom, this is what was requested.
PageMargins requested_custom_margins_in_points_;
};

@ -191,6 +191,13 @@ bool PrintSettingsFromJobSettings(const base::DictionaryValue& job_settings,
settings->set_duplex_mode(static_cast<DuplexMode>(duplex_mode));
settings->set_color(static_cast<ColorModel>(color));
#if defined(OS_WIN)
// Modifiable implies HTML and not other formats like PDF.
bool can_modify = false;
if (job_settings.GetBoolean(kSettingPreviewModifiable, &can_modify))
settings->set_print_text_with_gdi(can_modify);
#endif
return true;
}

@ -33,6 +33,12 @@ void PrintingContext::set_margin_type(MarginType type) {
settings_.set_margin_type(type);
}
void PrintingContext::set_is_modifiable(bool is_modifiable) {
#if defined(OS_WIN)
settings_.set_print_text_with_gdi(is_modifiable);
#endif
}
void PrintingContext::ResetSettings() {
ReleaseContext();

@ -29,8 +29,8 @@ class PRINTING_EXPORT PrintingContext {
// Printing context delegate.
class Delegate {
public:
Delegate() {};
virtual ~Delegate() {};
Delegate() {}
virtual ~Delegate() {}
// Returns parent view to use for modal dialogs.
virtual gfx::NativeView GetParentView() = 0;
@ -121,6 +121,7 @@ class PRINTING_EXPORT PrintingContext {
static std::unique_ptr<PrintingContext> Create(Delegate* delegate);
void set_margin_type(MarginType type);
void set_is_modifiable(bool is_modifiable);
const PrintSettings& settings() const {
return settings_;

@ -13,14 +13,13 @@
namespace printing {
PrintingContextSytemDialogWin::PrintingContextSytemDialogWin(Delegate* delegate)
: PrintingContextWin(delegate) {
}
PrintingContextSystemDialogWin::PrintingContextSystemDialogWin(
Delegate* delegate)
: PrintingContextWin(delegate) {}
PrintingContextSytemDialogWin::~PrintingContextSytemDialogWin() {
}
PrintingContextSystemDialogWin::~PrintingContextSystemDialogWin() {}
void PrintingContextSytemDialogWin::AskUserForSettings(
void PrintingContextSystemDialogWin::AskUserForSettings(
int max_pages,
bool has_selection,
bool is_scripted,
@ -32,11 +31,9 @@ void PrintingContextSytemDialogWin::AskUserForSettings(
// Show the OS-dependent dialog box.
// If the user press
// - OK, the settings are reset and reinitialized with the new settings. OK
// is
// - OK, the settings are reset and reinitialized with the new settings. OK is
// returned.
// - Apply then Cancel, the settings are reset and reinitialized with the
// new
// - Apply then Cancel, the settings are reset and reinitialized with the new
// settings. CANCEL is returned.
// - Cancel, the settings are not changed, the previous setting, if it was
// initialized before, are kept. CANCEL is returned.
@ -77,7 +74,7 @@ void PrintingContextSytemDialogWin::AskUserForSettings(
callback.Run(ParseDialogResultEx(dialog_options));
}
HRESULT PrintingContextSytemDialogWin::ShowPrintDialog(PRINTDLGEX* options) {
HRESULT PrintingContextSystemDialogWin::ShowPrintDialog(PRINTDLGEX* options) {
// Runs always on the UI thread.
static bool is_dialog_shown = false;
if (is_dialog_shown)
@ -97,7 +94,7 @@ HRESULT PrintingContextSytemDialogWin::ShowPrintDialog(PRINTDLGEX* options) {
return PrintDlgEx(options);
}
bool PrintingContextSytemDialogWin::InitializeSettingsWithRanges(
bool PrintingContextSystemDialogWin::InitializeSettingsWithRanges(
const DEVMODE& dev_mode,
const std::wstring& new_device_name,
const PRINTPAGERANGE* ranges,
@ -143,12 +140,14 @@ bool PrintingContextSytemDialogWin::InitializeSettingsWithRanges(
return true;
}
PrintingContext::Result PrintingContextSytemDialogWin::ParseDialogResultEx(
PrintingContext::Result PrintingContextSystemDialogWin::ParseDialogResultEx(
const PRINTDLGEX& dialog_options) {
// If the user clicked OK or Apply then Cancel, but not only Cancel.
if (dialog_options.dwResultAction != PD_RESULT_CANCEL) {
// Start fresh.
// Start fresh, but preserve GDI print setting.
bool print_text_with_gdi = settings_.print_text_with_gdi();
ResetSettings();
settings_.set_print_text_with_gdi(print_text_with_gdi);
DEVMODE* dev_mode = NULL;
if (dialog_options.hDevMode) {
@ -218,53 +217,4 @@ PrintingContext::Result PrintingContextSytemDialogWin::ParseDialogResultEx(
}
}
PrintingContext::Result PrintingContextSytemDialogWin::ParseDialogResult(
const PRINTDLG& dialog_options) {
// If the user clicked OK or Apply then Cancel, but not only Cancel.
// Start fresh.
ResetSettings();
DEVMODE* dev_mode = NULL;
if (dialog_options.hDevMode) {
dev_mode = reinterpret_cast<DEVMODE*>(GlobalLock(dialog_options.hDevMode));
DCHECK(dev_mode);
}
std::wstring device_name;
if (dialog_options.hDevNames) {
DEVNAMES* dev_names =
reinterpret_cast<DEVNAMES*>(GlobalLock(dialog_options.hDevNames));
DCHECK(dev_names);
if (dev_names) {
device_name = reinterpret_cast<const wchar_t*>(
reinterpret_cast<const wchar_t*>(dev_names) +
dev_names->wDeviceOffset);
GlobalUnlock(dialog_options.hDevNames);
}
}
bool success = false;
if (dev_mode && !device_name.empty()) {
set_context(dialog_options.hDC);
success =
InitializeSettingsWithRanges(*dev_mode, device_name, NULL, 0, false);
}
if (!success && dialog_options.hDC) {
DeleteDC(dialog_options.hDC);
set_context(NULL);
}
if (dev_mode) {
GlobalUnlock(dialog_options.hDevMode);
}
if (dialog_options.hDevMode != NULL)
GlobalFree(dialog_options.hDevMode);
if (dialog_options.hDevNames != NULL)
GlobalFree(dialog_options.hDevNames);
return context() ? OK : FAILED;
}
} // namespace printing

@ -16,11 +16,11 @@
namespace printing {
class PRINTING_EXPORT PrintingContextSytemDialogWin
class PRINTING_EXPORT PrintingContextSystemDialogWin
: public PrintingContextWin {
public:
explicit PrintingContextSytemDialogWin(Delegate* delegate);
~PrintingContextSytemDialogWin() override;
explicit PrintingContextSystemDialogWin(Delegate* delegate);
~PrintingContextSystemDialogWin() override;
// PrintingContext implementation.
void AskUserForSettings(
@ -44,9 +44,8 @@ class PRINTING_EXPORT PrintingContextSytemDialogWin
// Parses the result of a PRINTDLGEX result.
Result ParseDialogResultEx(const PRINTDLGEX& dialog_options);
Result ParseDialogResult(const PRINTDLG& dialog_options);
DISALLOW_COPY_AND_ASSIGN(PrintingContextSytemDialogWin);
DISALLOW_COPY_AND_ASSIGN(PrintingContextSystemDialogWin);
};
} // namespace printing

@ -26,7 +26,7 @@ namespace printing {
namespace {
void AssingResult(PrintingContext::Result* out, PrintingContext::Result in) {
void AssignResult(PrintingContext::Result* out, PrintingContext::Result in) {
*out = in;
}
@ -35,10 +35,10 @@ void AssingResult(PrintingContext::Result* out, PrintingContext::Result in) {
// static
std::unique_ptr<PrintingContext> PrintingContext::Create(Delegate* delegate) {
#if defined(ENABLE_BASIC_PRINTING)
return base::WrapUnique(new PrintingContextSytemDialogWin(delegate));
#else // ENABLE_BASIC_PRINTING
return base::WrapUnique(new PrintingContextSystemDialogWin(delegate));
#else
return base::WrapUnique(new PrintingContextWin(delegate));
#endif // EENABLE_BASIC_PRINTING
#endif
}
PrintingContextWin::PrintingContextWin(Delegate* delegate)
@ -209,12 +209,11 @@ PrintingContext::Result PrintingContextWin::UpdatePrinterSettings(
if (show_system_dialog) {
PrintingContext::Result result = PrintingContext::FAILED;
AskUserForSettings(page_count, false, false,
base::Bind(&AssingResult, &result));
base::Bind(&AssignResult, &result));
return result;
} else {
scoped_dev_mode = CreateDevMode(printer.Get(), scoped_dev_mode.get());
}
// Set printer then refresh printer settings.
scoped_dev_mode = CreateDevMode(printer.Get(), scoped_dev_mode.get());
return InitializeSettings(settings_.device_name(), scoped_dev_mode.get());
}

@ -40,6 +40,7 @@ class PrintingContextTest : public PrintingTest<testing::Test>,
};
namespace {
struct FreeHandleTraits {
typedef HANDLE Handle;
static void CloseHandle(HANDLE handle) { GlobalFree(handle); }
@ -49,12 +50,13 @@ struct FreeHandleTraits {
typedef base::win::GenericScopedHandle<FreeHandleTraits,
base::win::DummyVerifierTraits>
ScopedGlobalAlloc;
}
class MockPrintingContextWin : public PrintingContextSytemDialogWin {
} // namespace
class MockPrintingContextWin : public PrintingContextSystemDialogWin {
public:
MockPrintingContextWin(Delegate* delegate)
: PrintingContextSytemDialogWin(delegate) {}
explicit MockPrintingContextWin(Delegate* delegate)
: PrintingContextSystemDialogWin(delegate) {}
protected:
// This is a fake PrintDlgEx implementation that sets the right fields in