Commit 220cf4d0 authored by vandebo@chromium.org's avatar vandebo@chromium.org

Change printing of PDFs for preview on Windows to not rasterize.

Also cleaned up a few hacks.

BUG=80220
TEST=Navigate to a PDF and start print preview.

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

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@86431 0039d316-1c4b-4281-b951-d872f2087c98
parent e2ca8cc8
......@@ -75,8 +75,11 @@ PrepareFrameAndViewForPrint::PrepareFrameAndViewForPrint(
WebFrame* frame,
WebNode* node,
WebView* web_view)
: frame_(frame), web_view_(web_view), expected_pages_count_(0),
use_browser_overlays_(true) {
: frame_(frame),
web_view_(web_view),
expected_pages_count_(0),
use_browser_overlays_(true),
finished_(false) {
int dpi = GetDPI(&print_params);
print_canvas_size_.set_width(
ConvertUnit(print_params.printable_size.width(), dpi,
......@@ -110,12 +113,18 @@ PrepareFrameAndViewForPrint::PrepareFrameAndViewForPrint(
}
PrepareFrameAndViewForPrint::~PrepareFrameAndViewForPrint() {
frame_->printEnd();
web_view_->resize(prev_view_size_);
if (WebFrame* web_frame = web_view_->mainFrame())
web_frame->setScrollOffset(prev_scroll_offset_);
FinishPrinting();
}
void PrepareFrameAndViewForPrint::FinishPrinting() {
if (!finished_) {
finished_ = true;
frame_->printEnd();
web_view_->resize(prev_view_size_);
if (WebFrame* web_frame = web_view_->mainFrame())
web_frame->setScrollOffset(prev_scroll_offset_);
}
}
PrintWebViewHelper::PrintWebViewHelper(RenderView* render_view)
: RenderViewObserver(render_view),
......
......@@ -21,12 +21,6 @@ struct PrintMsg_Print_Params;
struct PrintMsg_PrintPage_Params;
struct PrintMsg_PrintPages_Params;
#if defined(USE_X11)
namespace skia {
class VectorCanvas;
}
#endif
// Class that calls the Begin and End print functions on the frame and changes
// the size of the view temporarily to support full page printing..
// Do not serve any events in the time between construction and destruction of
......@@ -53,6 +47,8 @@ class PrepareFrameAndViewForPrint {
return print_canvas_size_;
}
void FinishPrinting();
private:
WebKit::WebFrame* frame_;
WebKit::WebView* web_view_;
......@@ -61,6 +57,7 @@ class PrepareFrameAndViewForPrint {
gfx::Size prev_scroll_offset_;
int expected_pages_count_;
bool use_browser_overlays_;
bool finished_;
DISALLOW_COPY_AND_ASSIGN(PrepareFrameAndViewForPrint);
};
......@@ -165,8 +162,7 @@ class PrintWebViewHelper : public RenderViewObserver ,
void PrintPageInternal(const PrintMsg_PrintPage_Params& params,
const gfx::Size& canvas_size,
WebKit::WebFrame* frame,
printing::Metafile* metafile,
scoped_ptr<skia::VectorCanvas>* canvas);
printing::Metafile* metafile);
#else
void PrintPageInternal(const PrintMsg_PrintPage_Params& params,
const gfx::Size& canvas_size,
......
......@@ -14,6 +14,7 @@
#include "printing/metafile_impl.h"
#include "printing/metafile_skia_wrapper.h"
#include "skia/ext/vector_canvas.h"
#include "third_party/skia/include/core/SkRefCnt.h"
#include "third_party/WebKit/Source/WebKit/chromium/public/WebFrame.h"
#include "ui/gfx/point.h"
......@@ -156,42 +157,32 @@ bool PrintWebViewHelper::RenderPages(const PrintMsg_PrintPages_Params& params,
int* page_count,
printing::Metafile* metafile) {
PrintMsg_Print_Params printParams = params.params;
scoped_ptr<skia::VectorCanvas> canvas;
UpdatePrintableSizeInPrintParameters(frame, node, &printParams);
{
// Hack - when |prep_frame_view| goes out of scope, PrintEnd() gets called.
// Doing this before closing |metafile| below ensures
// webkit::ppapi::PluginInstance::PrintEnd() has a valid canvas/metafile to
// save the final output to. See pepper_plugin_instance.cc for the whole
// story.
PrepareFrameAndViewForPrint prep_frame_view(printParams,
frame,
node,
frame->view());
*page_count = prep_frame_view.GetExpectedPageCount();
if (send_expected_page_count) {
Send(new PrintHostMsg_DidGetPrintedPagesCount(routing_id(),
printParams.document_cookie,
*page_count));
}
if (!*page_count)
return false;
PrepareFrameAndViewForPrint prep_frame_view(printParams, frame, node,
frame->view());
*page_count = prep_frame_view.GetExpectedPageCount();
if (send_expected_page_count) {
Send(new PrintHostMsg_DidGetPrintedPagesCount(routing_id(),
printParams.document_cookie,
*page_count));
}
if (!*page_count)
return false;
PrintMsg_PrintPage_Params page_params;
page_params.params = printParams;
const gfx::Size& canvas_size = prep_frame_view.GetPrintCanvasSize();
if (params.pages.empty()) {
for (int i = 0; i < *page_count; ++i) {
page_params.page_number = i;
PrintPageInternal(page_params, canvas_size, frame, metafile, &canvas);
}
} else {
for (size_t i = 0; i < params.pages.size(); ++i) {
page_params.page_number = params.pages[i];
PrintPageInternal(page_params, canvas_size, frame, metafile, &canvas);
}
PrintMsg_PrintPage_Params page_params;
page_params.params = printParams;
const gfx::Size& canvas_size = prep_frame_view.GetPrintCanvasSize();
if (params.pages.empty()) {
for (int i = 0; i < *page_count; ++i) {
page_params.page_number = i;
PrintPageInternal(page_params, canvas_size, frame, metafile);
}
} else {
for (size_t i = 0; i < params.pages.size(); ++i) {
page_params.page_number = params.pages[i];
PrintPageInternal(page_params, canvas_size, frame, metafile);
}
}
......@@ -204,8 +195,7 @@ void PrintWebViewHelper::PrintPageInternal(
const PrintMsg_PrintPage_Params& params,
const gfx::Size& canvas_size,
WebFrame* frame,
printing::Metafile* metafile,
scoped_ptr<skia::VectorCanvas>* canvas) {
printing::Metafile* metafile) {
double content_width_in_points;
double content_height_in_points;
double margin_top_in_points;
......@@ -235,11 +225,13 @@ void PrintWebViewHelper::PrintPageInternal(
if (!device)
return;
canvas->reset(new skia::VectorCanvas(device));
printing::MetafileSkiaWrapper::SetMetafileOnCanvas(canvas->get(), metafile);
frame->printPage(params.page_number, canvas->get());
// The printPage method take a reference to the canvas we pass down, so it
// can't be a stack object.
SkRefPtr<skia::VectorCanvas> canvas = new skia::VectorCanvas(device);
canvas->unref(); // SkRefPtr and new both took a reference.
printing::MetafileSkiaWrapper::SetMetafileOnCanvas(canvas.get(), metafile);
frame->printPage(params.page_number, canvas.get());
// TODO(myhuang): We should handle transformation for paper margins.
// TODO(myhuang): We should render the header and the footer.
// Done printing. Close the device context to retrieve the compiled metafile.
......
......@@ -11,9 +11,11 @@
#include "chrome/common/print_messages.h"
#include "printing/metafile.h"
#include "printing/metafile_impl.h"
#include "printing/metafile_skia_wrapper.h"
#include "printing/units.h"
#include "skia/ext/vector_canvas.h"
#include "skia/ext/vector_platform_device_emf_win.h"
#include "third_party/skia/include/core/SkRefCnt.h"
#include "third_party/WebKit/Source/WebKit/chromium/public/WebFrame.h"
#include "ui/gfx/gdi_util.h"
#include "ui/gfx/point.h"
......@@ -154,18 +156,24 @@ bool PrintWebViewHelper::CreatePreviewDocument(
break;
float scale_factor = shrink;
RenderPage(print_params, &scale_factor,
static_cast<int>(params.pages[i]), true, frame, &metafile);
static_cast<int>(params.pages[i]), true, frame, &metafile);
}
}
// Ensure that printing has finished before we start cleaning up and
// allocating buffers; this causes prep_frame_view to flush anything pending
// into the metafile. Then we can get the final size and copy it into a
// shared segment.
prep_frame_view.FinishPrinting();
if (!metafile->FinishDocument())
NOTREACHED();
// Calculate the time taken to render the requested page for preview and add
// the net time in the histogram.
UMA_HISTOGRAM_TIMES("PrintPreview.RenderTime",
base::TimeTicks::Now() - begin_time);
if (!metafile->FinishDocument())
NOTREACHED();
// Get the size of the compiled metafile.
uint32 buf_size = metafile->GetDataSize();
DCHECK_GT(buf_size, 128u);
......@@ -223,9 +231,16 @@ void PrintWebViewHelper::RenderPage(
skia::PlatformDevice* device = (*metafile)->StartPageForVectorCanvas(
page_size, content_area, frame->getPrintPageShrink(page_number));
DCHECK(device);
skia::VectorCanvas canvas(device);
// The printPage method may take a reference to the canvas we pass down, so it
// can't be a stack object.
SkRefPtr<skia::VectorCanvas> canvas = new skia::VectorCanvas(device);
canvas->unref(); // SkRefPtr and new both took a reference.
if (is_preview) {
printing::MetafileSkiaWrapper::SetMetafileOnCanvas(canvas.get(),
metafile->get());
}
float webkit_scale_factor = frame->printPage(page_number, &canvas);
float webkit_scale_factor = frame->printPage(page_number, canvas.get());
if (*scale_factor <= 0 || webkit_scale_factor <= 0) {
NOTREACHED() << "Printing page " << page_number << " failed.";
} else {
......
......@@ -38,6 +38,8 @@
'image.h',
'metafile.h',
'metafile_impl.h',
'metafile_skia_wrapper.h',
'metafile_skia_wrapper.cc',
'page_number.cc',
'page_number.h',
'page_overlays.cc',
......@@ -98,10 +100,6 @@
'sources/': [['exclude', '_posix\\.cc$']]
}],
['toolkit_uses_gtk == 1', {
'sources': [
'metafile_skia_wrapper.cc',
'metafile_skia_wrapper.h',
],
'dependencies': [
# For FT_Init_FreeType and friends.
'../build/linux/system.gyp:freetype2',
......@@ -110,8 +108,10 @@
],
}],
['OS=="mac"',
{'sources/': [['exclude', 'pdf_metafile_skia\\.(cc|h)$']]}
],
{'sources/': [
['exclude', 'pdf_metafile_skia\\.(cc|h)$'],
['exclude', 'metafile_skia_wrapper\\.(cc|h)$'],
]}],
['OS=="win"', {
'defines': [
# PRINT_BACKEND_AVAILABLE disables the default dummy implementation
......
......@@ -67,7 +67,7 @@
#include "printing/metafile_impl.h"
#endif
#if defined(OS_LINUX)
#if defined(OS_LINUX) || defined(OS_WIN)
#include "printing/metafile.h"
#include "printing/metafile_skia_wrapper.h"
#endif
......@@ -353,9 +353,6 @@ PluginInstance::PluginInstance(PluginDelegate* delegate,
plugin_selection_interface_(NULL),
plugin_zoom_interface_(NULL),
checked_for_plugin_messaging_interface_(false),
#if defined(OS_LINUX)
canvas_(NULL),
#endif // defined(OS_LINUX)
plugin_print_interface_(NULL),
plugin_graphics_3d_interface_(NULL),
always_on_top_(false),
......@@ -388,9 +385,6 @@ PluginInstance::~PluginInstance() {
module_->InstanceDeleted(this);
ResourceTracker::Get()->InstanceDeleted(pp_instance_);
#if defined(OS_LINUX)
ranges_.clear();
#endif // defined(OS_LINUX)
}
// static
......@@ -1125,10 +1119,10 @@ int PluginInstance::PrintBegin(const gfx::Rect& printable_area,
if (!num_pages)
return 0;
current_print_settings_ = print_settings;
#if defined(OS_LINUX)
#if WEBKIT_USING_SKIA
canvas_ = NULL;
ranges_.clear();
#endif // defined(OS_LINUX)
#endif // WEBKIT_USING_SKIA
return num_pages;
}
......@@ -1136,13 +1130,17 @@ bool PluginInstance::PrintPage(int page_number, WebKit::WebCanvas* canvas) {
DCHECK(plugin_print_interface_.get());
PP_PrintPageNumberRange_Dev page_range;
page_range.first_page_number = page_range.last_page_number = page_number;
#if defined(OS_LINUX)
ranges_.push_back(page_range);
canvas_ = canvas;
return true;
#else
return PrintPageHelper(&page_range, 1, canvas);
#endif // defined(OS_LINUX)
#if WEBKIT_USING_SKIA
// The canvas only has a metafile on it for print preview.
if (printing::MetafileSkiaWrapper::GetMetafileFromCanvas(canvas)) {
ranges_.push_back(page_range);
canvas_ = canvas;
return true;
} else
#endif // WEBKIT_USING_SKIA
{
return PrintPageHelper(&page_range, 1, canvas);
}
}
bool PluginInstance::PrintPageHelper(PP_PrintPageNumberRange_Dev* page_ranges,
......@@ -1171,13 +1169,12 @@ bool PluginInstance::PrintPageHelper(PP_PrintPageNumberRange_Dev* page_ranges,
void PluginInstance::PrintEnd() {
// Keep a reference on the stack. See NOTE above.
scoped_refptr<PluginInstance> ref(this);
#if defined(OS_LINUX)
// This hack is here because all pages need to be written to PDF at once.
#if WEBKIT_USING_SKIA
if (!ranges_.empty())
PrintPageHelper(&(ranges_.front()), ranges_.size(), canvas_);
PrintPageHelper(&(ranges_.front()), ranges_.size(), canvas_.get());
canvas_ = NULL;
ranges_.clear();
#endif // defined(OS_LINUX)
#endif // WEBKIT_USING_SKIA
DCHECK(plugin_print_interface_.get());
if (plugin_print_interface_.get())
......@@ -1321,31 +1318,39 @@ bool PluginInstance::PrintPDFOutput(PP_Resource print_output,
CGContextRestoreGState(canvas);
}
#elif defined(OS_WIN)
// On Windows, we now need to render the PDF to the DC that backs the
// supplied canvas.
HDC dc = skia::BeginPlatformPaint(canvas);
gfx::Size size_in_pixels;
size_in_pixels.set_width(
printing::ConvertUnit(current_print_settings_.printable_area.size.width,
static_cast<int>(printing::kPointsPerInch),
current_print_settings_.dpi));
size_in_pixels.set_height(
printing::ConvertUnit(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);
ret = render_proc(buffer->mapped_buffer(), buffer->size(), 0, dc,
current_print_settings_.dpi, current_print_settings_.dpi,
0, 0, size_in_pixels.width(),
size_in_pixels.height(), true, false, true, true);
skia::EndPlatformPaint(canvas);
printing::Metafile* metafile =
printing::MetafileSkiaWrapper::GetMetafileFromCanvas(canvas);
if (metafile) {
// We only have a metafile when doing print preview, so we just want to
// pass the PDF off to preview.
ret = metafile->InitFromData(buffer->mapped_buffer(), buffer->size());
} else {
// On Windows, we now need to render the PDF to the DC that backs the
// supplied canvas.
HDC dc = skia::BeginPlatformPaint(canvas);
gfx::Size size_in_pixels;
size_in_pixels.set_width(printing::ConvertUnit(
current_print_settings_.printable_area.size.width,
static_cast<int>(printing::kPointsPerInch),
current_print_settings_.dpi));
size_in_pixels.set_height(printing::ConvertUnit(
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);
ret = render_proc(buffer->mapped_buffer(), buffer->size(), 0, dc,
current_print_settings_.dpi, current_print_settings_.dpi,
0, 0, size_in_pixels.width(),
size_in_pixels.height(), true, false, true, true);
skia::EndPlatformPaint(canvas);
}
#endif // defined(OS_WIN)
return ret;
......
......@@ -24,6 +24,7 @@
#include "ppapi/c/pp_instance.h"
#include "ppapi/c/pp_resource.h"
#include "third_party/skia/include/core/SkBitmap.h"
#include "third_party/skia/include/core/SkRefCnt.h"
#include "third_party/WebKit/Source/WebKit/chromium/public/WebCanvas.h"
#include "ui/gfx/rect.h"
#include "webkit/plugins/ppapi/plugin_delegate.h"
......@@ -375,20 +376,21 @@ class PluginInstance : public base::RefCounted<PluginInstance> {
// to keep the pixels valid until CGContextEndPage is called. We use this
// variable to hold on to the pixels.
scoped_refptr<PPB_ImageData_Impl> last_printed_page_;
#elif defined(OS_LINUX)
// On Linux, all pages need to be written to a PDF file in one shot. However,
// when users print only a subset of all the pages, it is impossible to know
// if a call to PrintPage() is the last call. Thus in PrintPage(), just store
// the page number in |ranges_|.
#endif // defined(OS_MACOSX)
#if WEBKIT_USING_SKIA
// When printing to PDF (print preview, Linux) the entire document goes into
// one metafile. However, when users print only a subset of all the pages,
// it is impossible to know if a call to PrintPage() is the last call.
// Thus in PrintPage(), just store the page number in |ranges_|.
// The hack is in PrintEnd(), where a valid |canvas_| is preserved in
// PrintWebViewHelper::PrintPages. This makes it possible to generate the
// entire PDF given the variables below:
//
// The most recently used WebCanvas, guaranteed to be valid.
WebKit::WebCanvas* canvas_;
SkRefPtr<WebKit::WebCanvas> canvas_;
// An array of page ranges.
std::vector<PP_PrintPageNumberRange_Dev> ranges_;
#endif // defined(OS_LINUX)
#endif // WEBKIT_USING_SKIA
// The plugin print interface. This nested struct adds functions needed for
// backwards compatibility.
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment