Skip to content

Commit

Permalink
Added support for vector printing for Pepper v1 plugins for Linux.
Browse files Browse the repository at this point in the history
BUG=None
TEST=Test printing from Chrome PDF plugin on Linux.

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

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@51181 0039d316-1c4b-4281-b951-d872f2087c98
  • Loading branch information
sanjeevr@chromium.org committed Jun 29, 2010
1 parent 10fc3db commit 37f3105
Show file tree
Hide file tree
Showing 6 changed files with 135 additions and 14 deletions.
50 changes: 42 additions & 8 deletions chrome/renderer/webplugin_delegate_pepper.cc
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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)) {
Expand Down Expand Up @@ -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() {
Expand All @@ -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
Expand Down
14 changes: 13 additions & 1 deletion chrome/renderer/webplugin_delegate_pepper.h
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down
36 changes: 36 additions & 0 deletions printing/pdf_ps_metafile_cairo.cc
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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 {
Expand Down Expand Up @@ -115,6 +121,8 @@ bool PdfPsMetafile::Init() {
return false;
}

cairo_set_user_data(context_, &kPdfMetafileKey, this, DestroyContextData);

return true;
}

Expand All @@ -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,
Expand Down Expand Up @@ -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_);
Expand Down Expand Up @@ -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_);
Expand Down
12 changes: 12 additions & 0 deletions printing/pdf_ps_metafile_cairo.h
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down Expand Up @@ -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();
Expand All @@ -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);
};
Expand Down
18 changes: 18 additions & 0 deletions printing/pdf_ps_metafile_cairo_unittest.cc
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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());

Expand Down Expand Up @@ -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) {
Expand All @@ -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());

Expand Down
19 changes: 14 additions & 5 deletions third_party/npapi/bindings/npapi_extensions.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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
Expand All @@ -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 */
Expand Down

0 comments on commit 37f3105

Please sign in to comment.