diff options
-rw-r--r-- | chrome/renderer/webplugin_delegate_pepper.cc | 50 | ||||
-rw-r--r-- | chrome/renderer/webplugin_delegate_pepper.h | 14 | ||||
-rw-r--r-- | printing/pdf_ps_metafile_cairo.cc | 36 | ||||
-rw-r--r-- | printing/pdf_ps_metafile_cairo.h | 12 | ||||
-rw-r--r-- | printing/pdf_ps_metafile_cairo_unittest.cc | 18 | ||||
-rw-r--r-- | third_party/npapi/bindings/npapi_extensions.h | 19 |
6 files changed, 135 insertions, 14 deletions
diff --git a/chrome/renderer/webplugin_delegate_pepper.cc b/chrome/renderer/webplugin_delegate_pepper.cc index d388f1c..3bb4ee2 100644 --- a/chrome/renderer/webplugin_delegate_pepper.cc +++ b/chrome/renderer/webplugin_delegate_pepper.cc @@ -1161,15 +1161,15 @@ int WebPluginDelegatePepper::PrintBegin(const gfx::Rect& printable_area, current_printer_dpi_ = printer_dpi; } } +#if defined (OS_LINUX) + num_pages_ = num_pages; + pdf_output_done_ = false; +#endif // (OS_LINUX) return num_pages; } bool WebPluginDelegatePepper::VectorPrintPage(int page_number, WebKit::WebCanvas* canvas) { -#if !defined(OS_WIN) && !defined(OS_MACOSX) - // TODO(sanjeevr): Add vector print support for Linux. - return false; -#endif // !defined(OS_WIN) && !defined(OS_MACOSX) NPPPrintExtensions* print_extensions = GetPrintExtensions(); if (!print_extensions) return false; @@ -1189,13 +1189,40 @@ bool WebPluginDelegatePepper::VectorPrintPage(int page_number, unsigned char* pdf_output = NULL; int32 output_size = 0; - NPError err = print_extensions->printPageAsPDF(instance()->npp(), page_number, - &pdf_output, &output_size); + NPPrintPageNumberRange page_range; +#if defined(OS_LINUX) + // On Linux we will try and output all pages as PDF in the first call to + // PrintPage. This is a temporary hack. + // TODO(sanjeevr): Remove this hack and fix this by changing the print + // interfaces for WebFrame and WebPlugin. + if (page_number != 0) + return pdf_output_done_; + page_range.firstPageNumber = 0; + page_range.lastPageNumber = num_pages_ - 1; +#else // defined(OS_LINUX) + page_range.firstPageNumber = page_range.lastPageNumber = page_number; +#endif // defined(OS_LINUX) + NPError err = print_extensions->printPagesAsPDF(instance()->npp(), + &page_range, 1, + &pdf_output, &output_size); if (err != NPERR_NO_ERROR) return false; bool ret = false; -#if defined(OS_MACOSX) +#if defined(OS_LINUX) + // On Linux we need to get the backing PdfPsMetafile and write the bits + // directly. + cairo_t* context = canvas->beginPlatformPaint(); + printing::NativeMetafile* metafile = + printing::NativeMetafile::FromCairoContext(context); + DCHECK(metafile); + if (metafile) { + ret = metafile->SetRawData(pdf_output, output_size); + if (ret) + pdf_output_done_ = true; + } + canvas->endPlatformPaint(); +#elif defined(OS_MACOSX) printing::NativeMetafile metafile; // Create a PDF metafile and render from there into the passed in context. if (metafile.Init(pdf_output, output_size)) { @@ -1335,7 +1362,10 @@ void WebPluginDelegatePepper::PrintEnd() { current_printer_dpi_ = -1; #if defined(OS_MACOSX) last_printed_page_ = SkBitmap(); -#endif // defined(OS_MACOSX) +#elif defined(OS_LINUX) + num_pages_ = 0; + pdf_output_done_ = false; +#endif // defined(OS_LINUX) } bool WebPluginDelegatePepper::SupportsFind() { @@ -1351,6 +1381,10 @@ WebPluginDelegatePepper::WebPluginDelegatePepper( instance_(instance), nested_delegate_(NULL), current_printer_dpi_(-1), +#if defined (OS_LINUX) + num_pages_(0), + pdf_output_done_(false), +#endif // (OS_LINUX) #if defined(ENABLE_GPU) command_buffer_(NULL), #endif diff --git a/chrome/renderer/webplugin_delegate_pepper.h b/chrome/renderer/webplugin_delegate_pepper.h index 3524112..e812cd9 100644 --- a/chrome/renderer/webplugin_delegate_pepper.h +++ b/chrome/renderer/webplugin_delegate_pepper.h @@ -301,10 +301,22 @@ class WebPluginDelegatePepper : public webkit_glue::WebPluginDelegate, int current_printer_dpi_; #if defined(OS_MACOSX) // On the Mac, when we draw the bitmap to the PDFContext, it seems necessary - // to keep the pixels valis until CGContextEndPage is called. We use this + // to keep the pixels valid until CGContextEndPage is called. We use this // variable to hold on to the pixels. SkBitmap last_printed_page_; #endif // defined(OS_MACOSX) +#if defined (OS_LINUX) + // On Linux, we always send all pages from the renderer to the browser. + // So, if the plugin supports printPagesAsPDF we print the entire output + // in one shot in the first call to PrintPage. + // (This is a temporary hack until we change the WebFrame and WebPlugin print + // interfaces). + // Specifies the total number of pages to be printed. It it set in PrintBegin. + int32 num_pages_; + // Specifies whether we have already output all pages. This is used to ignore + // subsequent PrintPage requests. + bool pdf_output_done_; +#endif // defined(OS_LINUX) #if defined(ENABLE_GPU) // The command buffer used to issue commands to the nested GPU plugin. diff --git a/printing/pdf_ps_metafile_cairo.cc b/printing/pdf_ps_metafile_cairo.cc index a4b10b2..47f4c14 100644 --- a/printing/pdf_ps_metafile_cairo.cc +++ b/printing/pdf_ps_metafile_cairo.cc @@ -19,6 +19,8 @@ namespace { +const cairo_user_data_key_t kPdfMetafileKey = {0}; + // Tests if |surface| is valid. bool IsSurfaceValid(cairo_surface_t* surface) { return cairo_surface_status(surface) == CAIRO_STATUS_SUCCESS; @@ -60,6 +62,10 @@ cairo_status_t WriteCairoStream(void* dst_buffer, return CAIRO_STATUS_SUCCESS; } +void DestroyContextData(void* data) { + // Nothing to be done here. +} + } // namespace namespace printing { @@ -115,6 +121,8 @@ bool PdfPsMetafile::Init() { return false; } + cairo_set_user_data(context_, &kPdfMetafileKey, this, DestroyContextData); + return true; } @@ -133,6 +141,23 @@ bool PdfPsMetafile::Init(const void* src_buffer, uint32 src_buffer_size) { return true; } +bool PdfPsMetafile::SetRawData(const void* src_buffer, + uint32 src_buffer_size) { + if (!context_) { + // If Init has not already been called, just call Init() + return Init(src_buffer, src_buffer_size); + } + // If a context has already been created, remember this data in + // raw_override_data_ + if (src_buffer == NULL || src_buffer_size == 0) + return false; + + raw_override_data_ = std::string(reinterpret_cast<const char*>(src_buffer), + src_buffer_size); + + return true; +} + cairo_t* PdfPsMetafile::StartPage(double width_in_points, double height_in_points, double margin_top_in_points, @@ -191,6 +216,12 @@ void PdfPsMetafile::Close() { DCHECK(IsContextValid(context_)); cairo_surface_finish(surface_); + + // If we have raw PDF/PS data set use that instead of what was drawn. + if (!raw_override_data_.empty()) { + data_ = raw_override_data_; + raw_override_data_.clear(); + } DCHECK(!data_.empty()); // Make sure we did get something. CleanUpContext(&context_); @@ -242,6 +273,11 @@ bool PdfPsMetafile::SaveTo(const base::FileDescriptor& fd) const { return success; } +PdfPsMetafile* PdfPsMetafile::FromCairoContext(cairo_t* context) { + return reinterpret_cast<PdfPsMetafile*>( + cairo_get_user_data(context, &kPdfMetafileKey)); +} + void PdfPsMetafile::CleanUpAll() { CleanUpContext(&context_); CleanUpSurface(&surface_); diff --git a/printing/pdf_ps_metafile_cairo.h b/printing/pdf_ps_metafile_cairo.h index 24b5d36..7a7b470 100644 --- a/printing/pdf_ps_metafile_cairo.h +++ b/printing/pdf_ps_metafile_cairo.h @@ -48,6 +48,12 @@ class PdfPsMetafile { // Note: Only call in the browser to initialize |data_|. bool Init(const void* src_buffer, uint32 src_buffer_size); + // Sets raw PS/PDF data for the document. This is used when a cairo drawing + // surface has already been created. This method will cause all subsequent + // drawing on the surface to be discarded (in Close()). If Init() has not yet + // been called this method simply calls the second version of Init. + bool SetRawData(const void* src_buffer, uint32 src_buffer_size); + FileFormat GetFileFormat() const { return format_; } // Prepares a new cairo surface/context for rendering a new page. @@ -89,6 +95,10 @@ class PdfPsMetafile { static const double kBottomMarginInInch; static const double kLeftMarginInInch; + // Returns the PdfPsMetafile object that owns the given context. Returns NULL + // if the context was not created by a PdfPdMetafile object. + static PdfPsMetafile* FromCairoContext(cairo_t* context); + private: // Cleans up all resources. void CleanUpAll(); @@ -101,6 +111,8 @@ class PdfPsMetafile { // Buffer stores PDF/PS contents for entire PDF/PS file. std::string data_; + // Buffer stores raw PDF/PS contents set by SetRawPageData. + std::string raw_override_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 e1b84d0..9273066 100644 --- a/printing/pdf_ps_metafile_cairo_unittest.cc +++ b/printing/pdf_ps_metafile_cairo_unittest.cc @@ -10,6 +10,7 @@ #include "base/file_descriptor_posix.h" #include "base/file_util.h" +#include "base/string_util.h" #include "testing/gtest/include/gtest/gtest.h" typedef struct _cairo cairo_t; @@ -29,6 +30,7 @@ TEST_F(PdfPsTest, Pdf) { // Renders page 1. cairo_t* context = pdf.StartPage(72, 72, 1, 2, 3, 4); EXPECT_TRUE(context != NULL); + EXPECT_EQ(printing::PdfPsMetafile::FromCairoContext(context), &pdf); // In theory, we should use Cairo to draw something on |context|. EXPECT_TRUE(pdf.FinishPage()); @@ -63,6 +65,21 @@ TEST_F(PdfPsTest, Pdf) { // Tests if we can save data. EXPECT_TRUE(pdf.SaveTo(DevNullFD())); + + // Test overriding the metafile with raw data. + printing::PdfPsMetafile pdf3(printing::PdfPsMetafile::PDF); + EXPECT_TRUE(pdf3.Init()); + context = pdf3.StartPage(72, 72, 1, 2, 3, 4); + EXPECT_TRUE(context != NULL); + std::string test_raw_data = "Dummy PDF"; + EXPECT_TRUE(pdf3.SetRawData(test_raw_data.c_str(), test_raw_data.size())); + EXPECT_TRUE(pdf3.FinishPage()); + pdf3.Close(); + size = pdf3.GetDataSize(); + EXPECT_EQ(test_raw_data.size(), size); + std::string output; + pdf3.GetData(WriteInto(&output, size + 1), size); + EXPECT_EQ(test_raw_data, output); } TEST_F(PdfPsTest, Ps) { @@ -73,6 +90,7 @@ TEST_F(PdfPsTest, Ps) { // Renders page 1. cairo_t* context = ps.StartPage(72, 72, 1, 2, 3, 4); EXPECT_TRUE(context != NULL); + EXPECT_EQ(printing::PdfPsMetafile::FromCairoContext(context), &ps); // In theory, we should use Cairo to draw something on |context|. EXPECT_TRUE(ps.FinishPage()); diff --git a/third_party/npapi/bindings/npapi_extensions.h b/third_party/npapi/bindings/npapi_extensions.h index ec0eaf9..0ce4360 100644 --- a/third_party/npapi/bindings/npapi_extensions.h +++ b/third_party/npapi/bindings/npapi_extensions.h @@ -952,6 +952,13 @@ struct _NPDeviceContextAudio { /* Printing related APIs ---------------------------------------------------*/ +/* Defines a contiguous range of pages to be printed. Page numbers use a + * zero-based index. */ +typedef struct _NPPrintPageNumberRange { + int32_t firstPageNumber; + int32_t lastPageNumber; +} NPPrintPageNumberRange; + /* Being a print operation. Returns the total number of pages to print at the * given printableArea size and DPI. printableArea is in points (a point is 1/72 * of an inch). The plugin is expected to remember the values of printableArea @@ -975,12 +982,14 @@ typedef NPError (*NPPPrintPageRasterPtr) ( NPDeviceContext2D* printSurface); /* Ends the print operation */ typedef NPError (*NPPPrintEndPtr) (NPP instance); -/* Prints the specified page as PDF. The plugin allocates the output buffer +/* Prints the specified pages as PDF. The plugin allocates the output buffer * pointed to by pdf_output using the browser-supplied NPN_MemAlloc function. * The caller is expected to free the output buffer upon success.*/ -typedef NPError (*NPPrintPageAsPDFPtr)(NPP instance, int32_t page_number, - unsigned char** pdf_output, - int32_t* output_size); +typedef NPError (*NPPrintPagesAsPDFPtr)(NPP instance, + NPPrintPageNumberRange* page_ranges, + int32_t page_range_count, + unsigned char** pdf_output, + int32_t* output_size); /* TODO(sanjeevr) : Provide a vector interface for printing. We need to decide @@ -992,7 +1001,7 @@ typedef struct _NPPPrintExtensions { NPPGetRasterDimensionsPtr getRasterDimensions; NPPPrintPageRasterPtr printPageRaster; NPPPrintEndPtr printEnd; - NPPrintPageAsPDFPtr printPageAsPDF; + NPPrintPagesAsPDFPtr printPagesAsPDF; } NPPPrintExtensions; /* Returns NULL if the plugin does not support print extensions */ |