diff options
author | estade@chromium.org <estade@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2010-04-10 00:04:54 +0000 |
---|---|---|
committer | estade@chromium.org <estade@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2010-04-10 00:04:54 +0000 |
commit | e6fae168d6fd6556f4455265fb18323db9ca56de (patch) | |
tree | 492466a306ab8199e4c1bef36a5adfe035f7f06a | |
parent | ffec6bf36fb4527d051960d4871623a5b91ec122 (diff) | |
download | chromium_src-e6fae168d6fd6556f4455265fb18323db9ca56de.zip chromium_src-e6fae168d6fd6556f4455265fb18323db9ca56de.tar.gz chromium_src-e6fae168d6fd6556f4455265fb18323db9ca56de.tar.bz2 |
Linux: fix printing somewhat.
BUG=29148
TEST=prints documents greater than one page (to real printers)
Review URL: http://codereview.chromium.org/1520014
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@44161 0039d316-1c4b-4281-b951-d872f2087c98
-rw-r--r-- | chrome/renderer/print_web_view_helper_linux.cc | 33 | ||||
-rw-r--r-- | printing/pdf_ps_metafile_cairo.cc | 227 | ||||
-rw-r--r-- | printing/pdf_ps_metafile_cairo.h | 32 | ||||
-rw-r--r-- | printing/pdf_ps_metafile_cairo_unittest.cc | 8 |
4 files changed, 70 insertions, 230 deletions
diff --git a/chrome/renderer/print_web_view_helper_linux.cc b/chrome/renderer/print_web_view_helper_linux.cc index 415bf1d..ed977c3 100644 --- a/chrome/renderer/print_web_view_helper_linux.cc +++ b/chrome/renderer/print_web_view_helper_linux.cc @@ -103,38 +103,19 @@ void PrintWebViewHelper::PrintPage(const ViewMsg_PrintPage_Params& params, const gfx::Size& canvas_size, WebFrame* frame, printing::NativeMetafile* metafile) { - // Since WebKit extends the page width depending on the magical shrink - // factor we make sure the canvas covers the worst case scenario - // (x2.0 currently). PrintContext will then set the correct clipping region. - int size_x = static_cast<int>(canvas_size.width() * params.params.max_shrink); - int size_y = static_cast<int>(canvas_size.height() * - params.params.max_shrink); - // Calculate the dpi adjustment. - float shrink = static_cast<float>(canvas_size.width()) / - params.params.printable_size.width(); - - cairo_t* cairo_context = metafile->StartPage(size_x, size_y); - if (!cairo_context) { - // TODO(myhuang): We should handle such kind of error further! - // We already have had DLOG(ERROR) in NativeMetafile::StartPage(), - // log the error here, too? + cairo_t* cairo_context = + metafile->StartPage(canvas_size.width(), canvas_size.height()); + if (!cairo_context) return; - } - skia::VectorCanvas canvas(cairo_context, size_x, size_y); - float webkit_shrink = frame->printPage(params.page_number, &canvas); - if (webkit_shrink <= 0) { - NOTREACHED() << "Printing page " << params.page_number << " failed."; - } else { - // Update the dpi adjustment with the "page shrink" calculated in webkit. - shrink /= webkit_shrink; - } + skia::VectorCanvas canvas(cairo_context, + canvas_size.width(), canvas_size.height()); + frame->printPage(params.page_number, &canvas); // 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. - if (!metafile->FinishPage(shrink)) { + if (!metafile->FinishPage()) NOTREACHED() << "metafile failed"; - } } diff --git a/printing/pdf_ps_metafile_cairo.cc b/printing/pdf_ps_metafile_cairo.cc index fc2efda..81050b7 100644 --- a/printing/pdf_ps_metafile_cairo.cc +++ b/printing/pdf_ps_metafile_cairo.cc @@ -1,4 +1,4 @@ -// Copyright (c) 2009 The Chromium Authors. All rights reserved. +// Copyright (c) 2010 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. @@ -18,6 +18,13 @@ namespace { +// The hardcoded margins, in points. These values are based on 72 dpi, +// with approximately 0.25 margins on top, left, and right, and 0.56 on bottom. +const double kTopMargin = 0.25 * 72.0; +const double kBottomMargin = 0.56 * 72.0; +const double kLeftMargin = 0.25 * 72.0; +const double kRightMargin = 0.25 * 72.0; + // Tests if |surface| is valid. bool IsSurfaceValid(cairo_surface_t* surface) { return cairo_surface_status(surface) == CAIRO_STATUS_SUCCESS; @@ -65,8 +72,7 @@ namespace printing { PdfPsMetafile::PdfPsMetafile(const FileFormat& format) : format_(format), - surface_(NULL), context_(NULL), - page_surface_(NULL), page_context_(NULL) { + surface_(NULL), context_(NULL) { } PdfPsMetafile::~PdfPsMetafile() { @@ -76,31 +82,33 @@ PdfPsMetafile::~PdfPsMetafile() { bool PdfPsMetafile::Init() { // We need to check at least these two members to ensure Init() has not been - // called before. Passing these two checks also implies that surface_, - // page_surface_, and page_context_ are NULL, and current_page_ is empty. + // called before. DCHECK(!context_); - DCHECK(all_pages_.empty()); + DCHECK(data_.empty()); // Creates an 1 by 1 Cairo surface for entire PDF/PS file. // The size for each page will be overwritten later in StartPage(). switch (format_) { - case PDF: { + case PDF: surface_ = cairo_pdf_surface_create_for_stream(WriteCairoStream, - &all_pages_, 1, 1); - } - break; + &data_, 1, 1); + break; - case PS: { + case PS: surface_ = cairo_ps_surface_create_for_stream(WriteCairoStream, - &all_pages_, 1, 1); - } - break; + &data_, 1, 1); + break; default: NOTREACHED(); return false; } + // Don't let WebKit draw over the margins. + cairo_surface_set_device_offset(surface_, + static_cast<int>(kLeftMargin), + static_cast<int>(kTopMargin)); + // Cairo always returns a valid pointer. // Hence, we have to check if it points to a "nil" object. if (!IsSurfaceValid(surface_)) { @@ -123,16 +131,14 @@ bool PdfPsMetafile::Init() { bool PdfPsMetafile::Init(const void* src_buffer, uint32 src_buffer_size) { // We need to check at least these two members to ensure Init() has not been - // called before. Passing these two checks also implies that surface_, - // page_surface_, and page_context_ are NULL, and current_page_ is empty. + // called before DCHECK(!context_); - DCHECK(all_pages_.empty()); + DCHECK(data_.empty()); - if (src_buffer == NULL || src_buffer_size == 0) { + if (src_buffer == NULL || src_buffer_size == 0) return false; - } - all_pages_ = std::string(reinterpret_cast<const char*>(src_buffer), + data_ = std::string(reinterpret_cast<const char*>(src_buffer), src_buffer_size); return true; @@ -144,29 +150,22 @@ cairo_t* PdfPsMetafile::StartPage(double width_in_points, DCHECK(IsContextValid(context_)); // Passing this check implies page_surface_ is NULL, and current_page_ is // empty. - DCHECK(!page_context_); DCHECK_GT(width_in_points, 0.); DCHECK_GT(height_in_points, 0.); - // Creates a target surface for the new page. - // Cairo 1.6.0 does NOT allow the first argument be NULL, - // but some newer versions do support NULL pointer. + // We build in extra room for the margins. The Cairo PDF backend will scale + // the output to fit a page. + double width = width_in_points + kLeftMargin + kRightMargin; + double height = height_in_points + kTopMargin + kBottomMargin; + switch (format_) { - case PDF: { - page_surface_ = cairo_pdf_surface_create_for_stream(WriteCairoStream, - ¤t_page_, - width_in_points, - height_in_points); - } - break; + case PDF: + cairo_pdf_surface_set_size(surface_, width, height); + break; - case PS: { - page_surface_ = cairo_ps_surface_create_for_stream(WriteCairoStream, - ¤t_page_, - width_in_points, - height_in_points); - } - break; + case PS: + cairo_ps_surface_set_size(surface_, width, height); + break; default: NOTREACHED(); @@ -174,134 +173,25 @@ cairo_t* PdfPsMetafile::StartPage(double width_in_points, return NULL; } - // Cairo always returns a valid pointer. - // Hence, we have to check if it points to a "nil" object. - if (!IsSurfaceValid(page_surface_)) { - DLOG(ERROR) << "Cannot create Cairo surface for PdfPsMetafile!"; - CleanUpAll(); - return NULL; - } - - // Creates a context. - page_context_ = cairo_create(page_surface_); - if (!IsContextValid(page_context_)) { - DLOG(ERROR) << "Cannot create Cairo context for PdfPsMetafile!"; - CleanUpAll(); - return NULL; - } - - return page_context_; + return context_; } -bool PdfPsMetafile::FinishPage(float shrink) { +bool PdfPsMetafile::FinishPage() { DCHECK(IsSurfaceValid(surface_)); DCHECK(IsContextValid(context_)); - DCHECK(IsSurfaceValid(page_surface_)); - DCHECK(IsContextValid(page_context_)); - DCHECK_GT(shrink, 0); // Flushes all rendering for current page. - cairo_surface_flush(page_surface_); - - // TODO(myhuang): Use real page settings. - // We hard-coded page settings here for testing purpose. - // The paper size is US Letter (8.5 in. by 11 in.). - // The default margins are: - // Left = 0.25 in. - // Right = 0.25 in. - // Top = 0.25 in. - // Bottom = 0.56 in. - const double kDPI = 72.0; // Dots (points) per inch. - const double kWidthInInch = 8.5; - const double kHeightInInch = 11.0; - const double kWidthInPoint = kWidthInInch * kDPI; - const double kHeightInPoint = kHeightInInch * kDPI; - switch (format_) { - case PDF: { - cairo_pdf_surface_set_size(surface_, kWidthInPoint, kHeightInPoint); - } - break; - - case PS: { - cairo_ps_surface_set_size(surface_, kWidthInPoint, kHeightInPoint); - } - break; - - default: - NOTREACHED(); - CleanUpAll(); - return false; - } - - // Checks if our surface is still valid after resizing. - if (!IsSurfaceValid(surface_)) { - DLOG(ERROR) << "Cannot resize Cairo surface for PdfPsMetafile!"; - CleanUpAll(); - return false; - } - - // Saves context's states. - cairo_save(context_); - // Copies current page onto the surface of final result. - // Margins are done by coordinates transformation. - // Please NOTE that we have to call cairo_scale() before we call - // cairo_set_source_surface(). - const double scale_factor = 1. / shrink; - cairo_scale(context_, scale_factor, scale_factor); - const double kLeftMarginInInch = 0.25; - const double kTopMarginInInch = 0.25; - const double kLeftMarginInPoint = kLeftMarginInInch * kDPI; - const double kTopMarginInPoint = kTopMarginInInch * kDPI; - const double kScaledLeftMarginInPoint = kLeftMarginInPoint * shrink; - const double kScaledTopMarginInPoint = kTopMarginInPoint * shrink; - cairo_set_source_surface(context_, - page_surface_, - kScaledLeftMarginInPoint, - kScaledTopMarginInPoint); - // In Cairo 1.6.0, if we use the following API, either the renderer will - // crash, or we will get an empty page. This might be a bug in Cairo. - // cairo_set_operator(context_, CAIRO_OPERATOR_SOURCE); - const double kRightMarginInInch = 0.25; - const double kBottomMarginInInch = 0.56; - const double kPrintableWidthInInch = - kWidthInInch - kLeftMarginInInch - kRightMarginInInch; - const double kPrintableHeightInInch = - kHeightInInch - kTopMarginInInch - kBottomMarginInInch; - const double kScaledPrintableWidthInPoint = - kPrintableWidthInInch * kDPI * shrink; - const double kScaledPrintableHeightInPoint = - kPrintableHeightInInch * kDPI * shrink; - cairo_rectangle(context_, - kScaledLeftMarginInPoint, - kScaledTopMarginInPoint, - kScaledPrintableWidthInPoint, - kScaledPrintableHeightInPoint); - cairo_fill(context_); - - // Finishes the duplication of current page. - cairo_show_page(context_); cairo_surface_flush(surface_); - - // Destroys resources for current page. - CleanUpContext(&page_context_); - CleanUpSurface(&page_surface_); - current_page_.clear(); - - // Restores context's states. - cairo_restore(context_); - + cairo_show_page(context_); return true; } void PdfPsMetafile::Close() { DCHECK(IsSurfaceValid(surface_)); DCHECK(IsContextValid(context_)); - // Passing this check implies page_surface_ is NULL, and current_page_ is - // empty. - DCHECK(!page_context_); cairo_surface_finish(surface_); - DCHECK(!all_pages_.empty()); // Make sure we did get something. + DCHECK(!data_.empty()); // Make sure we did get something. CleanUpContext(&context_); CleanUpSurface(&surface_); @@ -309,42 +199,26 @@ void PdfPsMetafile::Close() { uint32 PdfPsMetafile::GetDataSize() const { // We need to check at least these two members to ensure that either Init() - // has been called to initialize |all_pages_|, or metafile has been closed. - // Passing these two checks also implies that surface_, page_surface_, and - // page_context_ are NULL, and current_page_ is empty. + // has been called to initialize |data_|, or metafile has been closed. DCHECK(!context_); - DCHECK(!all_pages_.empty()); + DCHECK(!data_.empty()); - return all_pages_.size(); + return data_.size(); } bool PdfPsMetafile::GetData(void* dst_buffer, uint32 dst_buffer_size) const { DCHECK(dst_buffer); DCHECK_GT(dst_buffer_size, 0u); - // We need to check at least these two members to ensure that either Init() - // has been called to initialize |all_pages_|, or metafile has been closed. - // Passing these two checks also implies that surface_, page_surface_, and - // page_context_ are NULL, and current_page_ is empty. - DCHECK(!context_); - DCHECK(!all_pages_.empty()); - - uint32 data_size = GetDataSize(); - if (dst_buffer_size > data_size) { - return false; - } - - memcpy(dst_buffer, all_pages_.data(), dst_buffer_size); + memcpy(dst_buffer, data_.data(), dst_buffer_size); return true; } bool PdfPsMetafile::SaveTo(const base::FileDescriptor& fd) const { // We need to check at least these two members to ensure that either Init() - // has been called to initialize |all_pages_|, or metafile has been closed. - // Passing these two checks also implies that surface_, page_surface_, and - // page_context_ are NULL, and current_page_ is empty. + // has been called to initialize |data_|, or metafile has been closed. DCHECK(!context_); - DCHECK(!all_pages_.empty()); + DCHECK(!data_.empty()); if (fd.fd < 0) { DLOG(ERROR) << "Invalid file descriptor!"; @@ -352,7 +226,7 @@ bool PdfPsMetafile::SaveTo(const base::FileDescriptor& fd) const { } bool success = true; - if (file_util::WriteFileDescriptor(fd.fd, all_pages_.data(), + if (file_util::WriteFileDescriptor(fd.fd, data_.data(), GetDataSize()) < 0) { DLOG(ERROR) << "Failed to save file with fd " << fd.fd; success = false; @@ -371,10 +245,7 @@ bool PdfPsMetafile::SaveTo(const base::FileDescriptor& fd) const { void PdfPsMetafile::CleanUpAll() { CleanUpContext(&context_); CleanUpSurface(&surface_); - CleanUpContext(&page_context_); - CleanUpSurface(&page_surface_); - current_page_.clear(); - all_pages_.clear(); + data_.clear(); skia::VectorPlatformDevice::ClearFontCache(); } diff --git a/printing/pdf_ps_metafile_cairo.h b/printing/pdf_ps_metafile_cairo.h index 9930f5b..a5ea5be 100644 --- a/printing/pdf_ps_metafile_cairo.h +++ b/printing/pdf_ps_metafile_cairo.h @@ -1,4 +1,4 @@ -// Copyright (c) 2009 The Chromium Authors. All rights reserved. +// Copyright (c) 2010 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. @@ -32,7 +32,7 @@ class PdfPsMetafile { // In the renderer process, callers should also call Init(void) to see if the // metafile can obtain all necessary rendering resources. // In the browser process, callers should also call Init(const void*, uint32) - // to initialize the buffer |all_pages_| to use SaveTo(). + // to initialize the buffer |data_| to use SaveTo(). explicit PdfPsMetafile(const FileFormat& format); ~PdfPsMetafile(); @@ -45,7 +45,7 @@ class PdfPsMetafile { // Returns true on success. // |src_buffer| should point to the shared memory which stores PDF/PS // contents generated in the renderer. - // Note: Only call in the browser to initialize |all_pages_|. + // Note: Only call in the browser to initialize |data_|. bool Init(const void* src_buffer, uint32 src_buffer_size); FileFormat GetFileFormat() const { return format_; } @@ -56,28 +56,23 @@ class PdfPsMetafile { cairo_t* StartPage(double width, double height); // Destroys the surface and the context used in rendering current page. - // The results of current page will be appended into buffer |all_pages_|. - // Returns true on success - // TODO(myhuang): I plan to also do page setup here (margins, the header - // and the footer). At this moment, only pre-defined margins for US letter - // paper are hard-coded here. - // |shrink| decides the scaling factor to fit raw printing results into - // printable area. - bool FinishPage(float shrink); + // The results of current page will be appended into buffer |data_|. + // Returns true on success. + bool FinishPage(); // Closes resulting PDF/PS file. No further rendering is allowed. void Close(); - // Returns size of PDF/PS contents stored in buffer |all_pages_|. + // Returns size of PDF/PS contents stored in buffer |data_|. // This function should ONLY be called after PDF/PS file is closed. uint32 GetDataSize() const; - // Copies PDF/PS contents stored in buffer |all_pages_| into |dst_buffer|. + // Copies PDF/PS contents stored in buffer |data_| into |dst_buffer|. // This function should ONLY be called after PDF/PS file is closed. // Returns true only when success. bool GetData(void* dst_buffer, uint32 dst_buffer_size) const; - // Saves PDF/PS contents stored in buffer |all_pages_| into the file + // Saves PDF/PS contents stored in buffer |data_| into the file // associated with |fd|. // This function should ONLY be called after PDF/PS file is closed. bool SaveTo(const base::FileDescriptor& fd) const; @@ -92,15 +87,8 @@ class PdfPsMetafile { cairo_surface_t* surface_; cairo_t* context_; - // Cairo surface and context for current page only. - cairo_surface_t* page_surface_; - cairo_t* page_context_; - // Buffer stores PDF/PS contents for entire PDF/PS file. - std::string all_pages_; - - // Buffer stores PDF/PS contents for current page only. - std::string current_page_; + std::string data_; DISALLOW_COPY_AND_ASSIGN(PdfPsMetafile); }; diff --git a/printing/pdf_ps_metafile_cairo_unittest.cc b/printing/pdf_ps_metafile_cairo_unittest.cc index 0510878..6fcc170 100644 --- a/printing/pdf_ps_metafile_cairo_unittest.cc +++ b/printing/pdf_ps_metafile_cairo_unittest.cc @@ -30,13 +30,13 @@ TEST_F(PdfPsTest, Pdf) { cairo_t* context = pdf.StartPage(72, 72); EXPECT_TRUE(context != NULL); // In theory, we should use Cairo to draw something on |context|. - EXPECT_TRUE(pdf.FinishPage(1.5)); + EXPECT_TRUE(pdf.FinishPage()); // Renders page 2. context = pdf.StartPage(64, 64); EXPECT_TRUE(context != NULL); // In theory, we should use Cairo to draw something on |context|. - EXPECT_TRUE(pdf.FinishPage(0.5)); + EXPECT_TRUE(pdf.FinishPage()); // Closes the file. pdf.Close(); @@ -74,13 +74,13 @@ TEST_F(PdfPsTest, Ps) { cairo_t* context = ps.StartPage(72, 72); EXPECT_TRUE(context != NULL); // In theory, we should use Cairo to draw something on |context|. - EXPECT_TRUE(ps.FinishPage(1.5)); + EXPECT_TRUE(ps.FinishPage()); // Renders page 2. context = ps.StartPage(64, 64); EXPECT_TRUE(context != NULL); // In theory, we should use Cairo to draw something on |context|. - EXPECT_TRUE(ps.FinishPage(0.5)); + EXPECT_TRUE(ps.FinishPage()); // Closes the file. ps.Close(); |