Skip to content

Commit

Permalink
Fixed printing gets cut-off issue for CloudPrint and Chrome.
Browse files Browse the repository at this point in the history
Background: Print output is rendering to metafile that is based on the screen DC. The metafile was scaled to 72/600 for Chrome printing and 96/600 for CloudPrint. When the resolution of the screen is low and print output is large, it is possible for metafile output to go outside of the boundaries and be cut-off the print out.
Fix: This CL calculates scaling dynamically based on the printer and metafile sizes and revert scaling correspondingly in the browser/service for the actual printout.

BUG=chromium-os:16088
TEST=Verify Chrome and CloudPrint printing is working fine. Lower screen resolution (to 800x600 for Chrome, for CloudPrint it is enough to lower to 1280x800). Run Chrome and enable CloudPrint support. Try printing files from the bug 16088.

Review URL: http://codereview.chromium.org/9288081

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@119546 0039d316-1c4b-4281-b951-d872f2087c98
  • Loading branch information
gene@chromium.org committed Jan 28, 2012
1 parent c8b657f commit 1a30dd3
Show file tree
Hide file tree
Showing 10 changed files with 107 additions and 57 deletions.
7 changes: 4 additions & 3 deletions chrome/common/chrome_utility_messages.h
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Copyright (c) 2011 The Chromium Authors. All rights reserved.
// Copyright (c) 2012 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.

Expand Down Expand Up @@ -140,8 +140,9 @@ IPC_MESSAGE_CONTROL1(ChromeUtilityHostMsg_DecodeImage_Succeeded,
IPC_MESSAGE_CONTROL0(ChromeUtilityHostMsg_DecodeImage_Failed)

// Reply when the utility process has succeeded in rendering the PDF.
IPC_MESSAGE_CONTROL1(ChromeUtilityHostMsg_RenderPDFPagesToMetafile_Succeeded,
int) // Highest rendered page number
IPC_MESSAGE_CONTROL2(ChromeUtilityHostMsg_RenderPDFPagesToMetafile_Succeeded,
int, // Highest rendered page number
double) // Scale factor

// Reply when an error occured rendering the PDF.
IPC_MESSAGE_CONTROL0(ChromeUtilityHostMsg_RenderPDFPagesToMetafile_Failed)
Expand Down
10 changes: 6 additions & 4 deletions chrome/renderer/print_web_view_helper_win.cc
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Copyright (c) 2011 The Chromium Authors. All rights reserved.
// Copyright (c) 2012 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.

Expand Down Expand Up @@ -108,9 +108,11 @@ void PrintWebViewHelper::PrintPageInternal(

int page_number = params.page_number;

// Calculate the dpi adjustment.
double actual_shrink = static_cast<float>(params.params.desired_dpi /
params.params.dpi);
// Calculate scaling.
double actual_shrink = gfx::CalculatePageScale(
metafile->context(),
params.params.content_size.width(),
params.params.content_size.height());

gfx::Size page_size_in_dpi;
gfx::Rect content_area_in_dpi;
Expand Down
36 changes: 19 additions & 17 deletions chrome/service/cloud_print/print_system_win.cc
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Copyright (c) 2011 The Chromium Authors. All rights reserved.
// Copyright (c) 2012 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.

Expand Down Expand Up @@ -420,22 +420,7 @@ class PrintSystemWin : public PrintSystem {
return false;

printer_dc_.Set(dc);
int printer_dpi = ::GetDeviceCaps(printer_dc_.Get(), LOGPIXELSX);
int offset_x = ::GetDeviceCaps(printer_dc_.Get(), PHYSICALOFFSETX);
int offset_y = ::GetDeviceCaps(printer_dc_.Get(), PHYSICALOFFSETY);
saved_dc_ = SaveDC(printer_dc_.Get());
SetGraphicsMode(printer_dc_.Get(), GM_ADVANCED);

// Setup the matrix to translate and scale to the right place. Take in
// account the actual shrinking factor.
// Note that the printing output is relative to printable area of
// the page. That is 0,0 is offset by PHYSICALOFFSETX/Y from the page.
XFORM xform = {0};
xform.eDx = static_cast<float>(-offset_x);
xform.eDy = static_cast<float>(-offset_y);
xform.eM11 = xform.eM22 = static_cast<float>(printer_dpi) /
static_cast<float>(GetDeviceCaps(GetDC(NULL), LOGPIXELSX));
ModifyWorldTransform(printer_dc_.Get(), &xform, MWT_LEFTMULTIPLY);
print_data_file_path_ = print_data_file_path;
delegate_ = delegate;
RenderNextPDFPages();
Expand All @@ -454,10 +439,27 @@ class PrintSystemWin : public PrintSystem {
return true;
}

void PreparePageDCForPrinting(HDC, double scale_factor) {
SetGraphicsMode(printer_dc_.Get(), GM_ADVANCED);
// Setup the matrix to translate and scale to the right place. Take in
// account the scale factor.
// Note that the printing output is relative to printable area of
// the page. That is 0,0 is offset by PHYSICALOFFSETX/Y from the page.
int offset_x = ::GetDeviceCaps(printer_dc_.Get(), PHYSICALOFFSETX);
int offset_y = ::GetDeviceCaps(printer_dc_.Get(), PHYSICALOFFSETY);
XFORM xform = {0};
xform.eDx = static_cast<float>(-offset_x);
xform.eDy = static_cast<float>(-offset_y);
xform.eM11 = xform.eM22 = 1.0 / scale_factor;
SetWorldTransform(printer_dc_.Get(), &xform);
}

// ServiceUtilityProcessHost::Client implementation.
virtual void OnRenderPDFPagesToMetafileSucceeded(
const printing::Emf& metafile,
int highest_rendered_page_number) OVERRIDE {
int highest_rendered_page_number,
double scale_factor) OVERRIDE {
PreparePageDCForPrinting(printer_dc_.Get(), scale_factor);
metafile.SafePlayback(printer_dc_.Get());
bool done_printing = (highest_rendered_page_number !=
last_page_printed_ + kPageCountPerBatch);
Expand Down
13 changes: 8 additions & 5 deletions chrome/service/service_utility_process_host.cc
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Copyright (c) 2011 The Chromium Authors. All rights reserved.
// Copyright (c) 2012 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.

Expand Down Expand Up @@ -181,7 +181,8 @@ bool ServiceUtilityProcessHost::OnMessageReceived(const IPC::Message& message) {
}

void ServiceUtilityProcessHost::OnRenderPDFPagesToMetafileSucceeded(
int highest_rendered_page_number) {
int highest_rendered_page_number,
double scale_factor) {
DCHECK(waiting_for_reply_);
waiting_for_reply_ = false;
// If the metafile was successfully created, we need to take our hands off the
Expand All @@ -191,7 +192,7 @@ void ServiceUtilityProcessHost::OnRenderPDFPagesToMetafileSucceeded(
client_message_loop_proxy_->PostTask(
FROM_HERE,
base::Bind(&Client::MetafileAvailable, client_.get(), metafile_path_,
highest_rendered_page_number));
highest_rendered_page_number, scale_factor));
}

void ServiceUtilityProcessHost::OnRenderPDFPagesToMetafileFailed() {
Expand Down Expand Up @@ -225,7 +226,8 @@ void ServiceUtilityProcessHost::OnGetPrinterCapsAndDefaultsFailed(

void ServiceUtilityProcessHost::Client::MetafileAvailable(
const FilePath& metafile_path,
int highest_rendered_page_number) {
int highest_rendered_page_number,
double scale_factor) {
// The metafile was created in a temp folder which needs to get deleted after
// we have processed it.
ScopedTempDir scratch_metafile_dir;
Expand All @@ -240,7 +242,8 @@ void ServiceUtilityProcessHost::Client::MetafileAvailable(
OnRenderPDFPagesToMetafileFailed();
} else {
OnRenderPDFPagesToMetafileSucceeded(metafile,
highest_rendered_page_number);
highest_rendered_page_number,
scale_factor);
}
#endif // defined(OS_WIN)
}
Expand Down
11 changes: 7 additions & 4 deletions chrome/service/service_utility_process_host.h
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Copyright (c) 2011 The Chromium Authors. All rights reserved.
// Copyright (c) 2012 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.

Expand Down Expand Up @@ -56,7 +56,8 @@ class ServiceUtilityProcessHost : public content::ChildProcessHostDelegate {
// successfully into |metafile|.
virtual void OnRenderPDFPagesToMetafileSucceeded(
const printing::Emf& metafile,
int highest_rendered_page_number) {}
int highest_rendered_page_number,
double scale_factor) {}
// Called when no page in the passed in PDF could be rendered.
virtual void OnRenderPDFPagesToMetafileFailed() {}

Expand All @@ -80,7 +81,8 @@ class ServiceUtilityProcessHost : public content::ChildProcessHostDelegate {

// Invoked when a metafile file is ready.
void MetafileAvailable(const FilePath& metafile_path,
int highest_rendered_page_number);
int highest_rendered_page_number,
double scale_factor);

DISALLOW_COPY_AND_ASSIGN(Client);
};
Expand Down Expand Up @@ -128,7 +130,8 @@ class ServiceUtilityProcessHost : public content::ChildProcessHostDelegate {
base::ProcessHandle handle() const { return handle_; }

// Messages handlers:
void OnRenderPDFPagesToMetafileSucceeded(int highest_rendered_page_number);
void OnRenderPDFPagesToMetafileSucceeded(int highest_rendered_page_number,
double scale_factor);
void OnRenderPDFPagesToMetafileFailed();
void OnGetPrinterCapsAndDefaultsSucceeded(
const std::string& printer_name,
Expand Down
33 changes: 20 additions & 13 deletions chrome/utility/chrome_content_utility_client.cc
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Copyright (c) 2011 The Chromium Authors. All rights reserved.
// Copyright (c) 2012 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.

Expand Down Expand Up @@ -35,6 +35,7 @@
#include "base/win/scoped_handle.h"
#include "content/public/common/content_switches.h"
#include "printing/emf_win.h"
#include "ui/gfx/gdi_util.h"
#endif // defined(OS_WIN)

namespace chrome {
Expand Down Expand Up @@ -181,16 +182,18 @@ void ChromeContentUtilityClient::OnRenderPDFPagesToMetafile(
bool succeeded = false;
#if defined(OS_WIN)
int highest_rendered_page_number = 0;
double scale_factor = 1.0;
succeeded = RenderPDFToWinMetafile(pdf_file,
metafile_path,
pdf_render_settings.area(),
pdf_render_settings.dpi(),
pdf_render_settings.autorotate(),
page_ranges,
&highest_rendered_page_number);
&highest_rendered_page_number,
&scale_factor);
if (succeeded) {
Send(new ChromeUtilityHostMsg_RenderPDFPagesToMetafile_Succeeded(
highest_rendered_page_number));
highest_rendered_page_number, scale_factor));
}
#endif // defined(OS_WIN)
if (!succeeded) {
Expand Down Expand Up @@ -254,8 +257,10 @@ bool ChromeContentUtilityClient::RenderPDFToWinMetafile(
int render_dpi,
bool autorotate,
const std::vector<printing::PageRange>& page_ranges,
int* highest_rendered_page_number) {
int* highest_rendered_page_number,
double* scale_factor) {
*highest_rendered_page_number = -1;
*scale_factor = 1.0;
base::win::ScopedHandle file(pdf_file);
FilePath pdf_module_path;
PathService::Get(chrome::FILE_PDF_PLUGIN, &pdf_module_path);
Expand Down Expand Up @@ -305,15 +310,17 @@ bool ChromeContentUtilityClient::RenderPDFToWinMetafile(

printing::Emf metafile;
metafile.InitToFile(metafile_path);
// Since we created the metafile using the screen DPI (but we actually want
// the PDF DLL to print using the passed in render_dpi, we apply the following
// transformation.
SetGraphicsMode(metafile.context(), GM_ADVANCED);
XFORM xform = {0};
int screen_dpi = GetDeviceCaps(GetDC(NULL), LOGPIXELSX);
xform.eM11 = xform.eM22 =
static_cast<float>(screen_dpi) / static_cast<float>(render_dpi);
ModifyWorldTransform(metafile.context(), &xform, MWT_LEFTMULTIPLY);
// We need to scale down DC to fit an entire page into DC available area.
// Current metafile is based on screen DC and have current screen size.
// Writing outside of those boundaries will result in the cut-off output.
// On metafiles (this is the case here), scaling down will still record
// original coordinates and we'll be able to print in full resolution.
// Before playback we'll need to counter the scaling up that will happen
// in the service (print_system_win.cc).
*scale_factor = gfx::CalculatePageScale(metafile.context(),
render_area.right(),
render_area.bottom());
gfx::ScaleDC(metafile.context(), *scale_factor);

bool ret = false;
std::vector<printing::PageRange>::const_iterator iter;
Expand Down
5 changes: 3 additions & 2 deletions chrome/utility/chrome_content_utility_client.h
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Copyright (c) 2011 The Chromium Authors. All rights reserved.
// Copyright (c) 2012 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.

Expand Down Expand Up @@ -71,7 +71,8 @@ class ChromeContentUtilityClient : public content::ContentUtilityClient {
int render_dpi,
bool autorotate,
const std::vector<printing::PageRange>& page_ranges,
int* highest_rendered_page_number);
int* highest_rendered_page_number,
double* scale_factor);
#endif // defined(OS_WIN)

void OnGetPrinterCapsAndDefaults(const std::string& printer_name);
Expand Down
25 changes: 24 additions & 1 deletion ui/gfx/gdi_util.cc
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Copyright (c) 2009 The Chromium Authors. All rights reserved.
// Copyright (c) 2012 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.

Expand Down Expand Up @@ -76,4 +76,27 @@ void SubtractRectanglesFromRegion(HRGN hrgn,
}
}

double CalculatePageScale(HDC dc, int page_width, int page_height) {
int dc_width = GetDeviceCaps(dc, HORZRES);
int dc_height = GetDeviceCaps(dc, VERTRES);

// If page fits DC - no scaling needed.
if (dc_width >= page_width && dc_height >= page_height)
return 1.0;

double x_factor =
static_cast<double>(dc_width) / static_cast<double>(page_width);
double y_factor =
static_cast<double>(dc_height) / static_cast<double>(page_height);
return std::min(x_factor, y_factor);
}

// Apply scaling to the DC.
bool ScaleDC(HDC dc, double scale_factor) {
SetGraphicsMode(dc, GM_ADVANCED);
XFORM xform = {0};
xform.eM11 = xform.eM22 = scale_factor;
return !!ModifyWorldTransform(dc, &xform, MWT_LEFTMULTIPLY);
}

} // namespace gfx
8 changes: 7 additions & 1 deletion ui/gfx/gdi_util.h
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Copyright (c) 2011 The Chromium Authors. All rights reserved.
// Copyright (c) 2012 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.

Expand Down Expand Up @@ -35,6 +35,12 @@ UI_EXPORT void SubtractRectanglesFromRegion(
HRGN hrgn,
const std::vector<gfx::Rect>& cutouts);

// Calculate scale to fit an entire page on DC.
double CalculatePageScale(HDC dc, int page_width, int page_height);

// Apply scaling to the DC.
bool ScaleDC(HDC dc, double scale_factor);

} // namespace gfx

#endif // UI_GFX_GDI_UTIL_H_
16 changes: 9 additions & 7 deletions webkit/plugins/ppapi/ppapi_plugin_instance.cc
Original file line number Diff line number Diff line change
Expand Up @@ -1462,13 +1462,15 @@ bool PluginInstance::PrintPDFOutput(PP_Resource print_output,
current_print_settings_.printable_area.size.height,
static_cast<int>(printing::kPointsPerInch),
current_print_settings_.dpi));
// We need to render using the actual printer DPI (rendering to a smaller
// set of pixels leads to a blurry output). However, we need to counter the
// scaling up that will happen in the browser.
XFORM xform = {0};
xform.eM11 = xform.eM22 = static_cast<float>(printing::kPointsPerInch) /
static_cast<float>(current_print_settings_.dpi);
ModifyWorldTransform(dc, &xform, MWT_LEFTMULTIPLY);
// We need to scale down DC to fit an entire page into DC available area.
// Current metafile is based on screen DC and have current screen size.
// Writing outside of those boundaries will result in the cut-off output.
// On metafiles (this is the case here), scaling down will still record
// original coordinates and we'll be able to print in full resolution.
// Before playback we'll need to counter the scaling up that will happen
// in the browser (printed_document_win.cc).
gfx::ScaleDC(dc, gfx::CalculatePageScale(dc, size_in_pixels.width(),
size_in_pixels.height()));

ret = render_proc(static_cast<unsigned char*>(mapper.data()), mapper.size(),
0, dc, current_print_settings_.dpi,
Expand Down

0 comments on commit 1a30dd3

Please sign in to comment.