summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--chrome/browser/printing/printing_layout_uitest.cc4
-rw-r--r--chrome/renderer/mock_printer.cc29
-rw-r--r--chrome/renderer/mock_printer.h4
-rw-r--r--chrome/renderer/render_view_unittest.cc24
-rw-r--r--printing/image.cc29
-rw-r--r--printing/image.h3
-rw-r--r--printing/pdf_metafile_mac.cc81
-rw-r--r--printing/pdf_metafile_mac.h30
-rw-r--r--printing/pdf_metafile_mac_unittest.cc10
-rw-r--r--printing/printed_document_mac.cc20
10 files changed, 185 insertions, 49 deletions
diff --git a/chrome/browser/printing/printing_layout_uitest.cc b/chrome/browser/printing/printing_layout_uitest.cc
index fb0b6c0..a5de41a 100644
--- a/chrome/browser/printing/printing_layout_uitest.cc
+++ b/chrome/browser/printing/printing_layout_uitest.cc
@@ -82,7 +82,7 @@ class PrintingLayoutTest : public PrintingTest<UITest> {
// Copy the .emf and generate an .png.
file_util::CopyFile(test_result, emf);
Image emf_content(emf.value());
- emf_content.SaveToPng(png.value());
+ emf_content.SaveToPng(png);
// Saving is always fine.
return 0;
} else {
@@ -109,7 +109,7 @@ class PrintingLayoutTest : public PrintingTest<UITest> {
L" result size:" << test_content.size();
if (diff_png) {
// Backup the rendered emf file to detect the rendering difference.
- emf_content.SaveToPng(verification_file + L"_rendering.png");
+ emf_content.SaveToPng(FilePath(verification_file + L"_rendering.png"));
}
return std::max(diff_png, diff_emf);
}
diff --git a/chrome/renderer/mock_printer.cc b/chrome/renderer/mock_printer.cc
index 2da66ae..e8fbac0 100644
--- a/chrome/renderer/mock_printer.cc
+++ b/chrome/renderer/mock_printer.cc
@@ -105,19 +105,22 @@ void MockPrinter::PrintPage(const ViewHostMsg_DidPrintPage_Params& params) {
EXPECT_EQ(page_number_, params.page_number);
EXPECT_LE(params.page_number, number_pages_);
-#if defined(OS_WIN)
- // Load the EMF data sent from a RenderView object and create a PageData
- // object.
+#if defined(OS_WIN) || defined(OS_MACOSX)
+ // Load the data sent from a RenderView object and create a PageData object.
// We duplicate the given file handle when creating a base::SharedMemory
// instance so that its destructor closes the copy.
EXPECT_GT(params.data_size, 0U);
- base::SharedMemory emf_data(params.metafile_data_handle, true,
- GetCurrentProcess());
- emf_data.Map(params.data_size);
+#if defined(OS_WIN)
+ base::SharedMemory metafile_data(params.metafile_data_handle, true,
+ GetCurrentProcess());
+#elif defined(OS_MACOSX)
+ base::SharedMemory metafile_data(params.metafile_data_handle, true);
+#endif
+ metafile_data.Map(params.data_size);
printing::NativeMetafile metafile;
- metafile.CreateFromData(emf_data.memory(), params.data_size);
+ metafile.CreateFromData(metafile_data.memory(), params.data_size);
printing::Image image(metafile);
- MockPrinterPage* page_data = new MockPrinterPage(emf_data.memory(),
+ MockPrinterPage* page_data = new MockPrinterPage(metafile_data.memory(),
params.data_size,
image);
if (!page_data) {
@@ -168,23 +171,21 @@ bool MockPrinter::GetBitmapChecksum(size_t page, std::string* checksum) const {
return true;
}
-bool MockPrinter::SaveSource(size_t page,
- const std::wstring& filename) const {
+bool MockPrinter::SaveSource(size_t page, const FilePath& filepath) const {
if (printer_status_ != PRINTER_READY || page >= pages_.size())
return false;
const uint8* source_data = pages_[page]->source_data();
size_t source_size = pages_[page]->source_size();
- file_util::WriteFile(filename, reinterpret_cast<const char*>(source_data),
+ file_util::WriteFile(filepath, reinterpret_cast<const char*>(source_data),
source_size);
return true;
}
-bool MockPrinter::SaveBitmap(size_t page,
- const std::wstring& filename) const {
+bool MockPrinter::SaveBitmap(size_t page, const FilePath& filepath) const {
if (printer_status_ != PRINTER_READY || page >= pages_.size())
return false;
- pages_[page]->image().SaveToPng(filename);
+ pages_[page]->image().SaveToPng(filepath);
return true;
}
diff --git a/chrome/renderer/mock_printer.h b/chrome/renderer/mock_printer.h
index ba3f0de..80f6c4b 100644
--- a/chrome/renderer/mock_printer.h
+++ b/chrome/renderer/mock_printer.h
@@ -96,8 +96,8 @@ class MockPrinter {
bool GetBitmapChecksum(size_t page, std::string* checksum) const;
bool GetSource(size_t page, const void** data, size_t* size) const;
bool GetBitmap(size_t page, const void** data, size_t* size) const;
- bool SaveSource(size_t page, const std::wstring& filename) const;
- bool SaveBitmap(size_t page, const std::wstring& filename) const;
+ bool SaveSource(size_t page, const FilePath& filepath) const;
+ bool SaveBitmap(size_t page, const FilePath& filepath) const;
protected:
int CreateDocumentCookie();
diff --git a/chrome/renderer/render_view_unittest.cc b/chrome/renderer/render_view_unittest.cc
index 980ba38..2626096 100644
--- a/chrome/renderer/render_view_unittest.cc
+++ b/chrome/renderer/render_view_unittest.cc
@@ -372,7 +372,7 @@ TEST_F(RenderViewTest, PrintWithJavascript) {
}
TEST_F(RenderViewTest, PrintWithIframe) {
-#if defined(OS_WIN)
+#if defined(OS_WIN) || defined(OS_MACOSX)
// Document that populates an iframe..
const char html[] =
"<html><body>Lorem Ipsum:"
@@ -416,14 +416,16 @@ TEST_F(RenderViewTest, PrintWithIframe) {
// i.e. a simplified version of the PrintingLayoutTextTest UI test.
namespace {
// Test cases used in this test.
-const struct {
+struct TestPageData {
const char* page;
- int printed_pages;
+ size_t printed_pages;
int width;
int height;
const char* checksum;
const wchar_t* file;
-} kTestPages[] = {
+};
+
+const TestPageData kTestPages[] = {
{"<html>"
"<head>"
"<meta"
@@ -434,7 +436,13 @@ const struct {
"<body style=\"background-color: white;\">"
"<p style=\"font-family: arial;\">Hello World!</p>"
"</body>",
+#if defined(OS_MACOSX)
+ // Mac printing code compensates for the WebKit scale factor while generating
+ // the metafile, so we expect smaller pages.
+ 1, 612, 792,
+#else
1, 764, 972,
+#endif
NULL,
NULL,
},
@@ -442,7 +450,7 @@ const struct {
} // namespace
TEST_F(RenderViewTest, PrintLayoutTest) {
-#if defined(OS_WIN)
+#if defined(OS_WIN) || defined(OS_MACOSX)
bool baseline = false;
EXPECT_TRUE(render_thread_.printer() != NULL);
@@ -484,11 +492,11 @@ TEST_F(RenderViewTest, PrintLayoutTest) {
// create base-line results.
FilePath source_path;
file_util::CreateTemporaryFile(&source_path);
- render_thread_.printer()->SaveSource(0, source_path.value());
+ render_thread_.printer()->SaveSource(0, source_path);
FilePath bitmap_path;
file_util::CreateTemporaryFile(&bitmap_path);
- render_thread_.printer()->SaveBitmap(0, bitmap_path.value());
+ render_thread_.printer()->SaveBitmap(0, bitmap_path);
}
}
#else
@@ -498,7 +506,7 @@ TEST_F(RenderViewTest, PrintLayoutTest) {
// Print page as bitmap test.
TEST_F(RenderViewTest, OnPrintPageAsBitmap) {
-#if defined(OS_WIN)
+#if defined(OS_WIN) || defined(OS_MACOSX)
// Lets simulate a print pages with Hello world.
LoadHTML("<body><p>Hello world!</p></body>");
diff --git a/printing/image.cc b/printing/image.cc
index beff637..ba52567 100644
--- a/printing/image.cc
+++ b/printing/image.cc
@@ -13,6 +13,9 @@
#if defined(OS_WIN)
#include "app/gfx/gdi_util.h" // EMF support
+#elif defined(OS_MACOSX)
+#include <ApplicationServices/ApplicationServices.h>
+#include "base/scoped_cftyperef.h"
#endif
namespace {
@@ -97,7 +100,7 @@ std::string Image::checksum() const {
return HexEncode(&digest, sizeof(digest));
}
-bool Image::SaveToPng(const std::wstring& filename) const {
+bool Image::SaveToPng(const FilePath& filepath) const {
DCHECK(!data_.empty());
std::vector<unsigned char> compressed;
bool success = gfx::PNGCodec::Encode(&*data_.begin(),
@@ -110,7 +113,7 @@ bool Image::SaveToPng(const std::wstring& filename) const {
DCHECK(success && compressed.size());
if (success) {
int write_bytes = file_util::WriteFile(
- filename,
+ filepath,
reinterpret_cast<char*>(&*compressed.begin()), compressed.size());
success = (write_bytes == static_cast<int>(compressed.size()));
DCHECK(success);
@@ -188,7 +191,7 @@ bool Image::LoadPng(const std::string& compressed) {
bool Image::LoadMetafile(const std::string& data) {
DCHECK(!data.empty());
-#if defined(OS_WIN)
+#if defined(OS_WIN) || defined(OS_MACOSX)
NativeMetafile metafile;
metafile.CreateFromData(data.data(), data.size());
return LoadMetafile(metafile);
@@ -229,6 +232,26 @@ bool Image::LoadMetafile(const NativeMetafile& metafile) {
DeleteObject(bitmap);
return success;
}
+#elif defined(OS_MACOSX)
+ // The printing system uses single-page metafiles (page indexes are 1-based).
+ const unsigned int page_number = 1;
+ gfx::Rect rect(metafile.GetPageBounds(page_number));
+ if (rect.width() > 0 && rect.height() > 0) {
+ size_ = rect.size();
+ row_length_ = size_.width() * sizeof(uint32);
+ size_t bytes = row_length_ * size_.height();
+ DCHECK(bytes);
+ data_.resize(bytes);
+ scoped_cftyperef<CGColorSpaceRef> color_space(
+ CGColorSpaceCreateWithName(kCGColorSpaceGenericRGB));
+ scoped_cftyperef<CGContextRef> bitmap_context(
+ CGBitmapContextCreate(&*data_.begin(), size_.width(), size_.height(),
+ 8, row_length_, color_space,
+ kCGImageAlphaPremultipliedLast));
+ DCHECK(bitmap_context.get());
+ metafile.RenderPage(page_number, bitmap_context,
+ CGRectMake(0, 0, size_.width(), size_.height()));
+ }
#else
NOTIMPLEMENTED();
#endif
diff --git a/printing/image.h b/printing/image.h
index a927549..f8755275 100644
--- a/printing/image.h
+++ b/printing/image.h
@@ -9,6 +9,7 @@
#include <vector>
#include "base/basictypes.h"
+#include "base/file_path.h"
#include "base/gfx/size.h"
#include "base/logging.h"
#include "printing/native_metafile.h"
@@ -39,7 +40,7 @@ class Image {
std::string checksum() const;
// Save image as PNG.
- bool SaveToPng(const std::wstring& filename) const;
+ bool SaveToPng(const FilePath& filepath) const;
// Returns % of pixels different
double PercentageDifferent(const Image& rhs) const;
diff --git a/printing/pdf_metafile_mac.cc b/printing/pdf_metafile_mac.cc
index 6a8cd55..381c6a3 100644
--- a/printing/pdf_metafile_mac.cc
+++ b/printing/pdf_metafile_mac.cc
@@ -4,7 +4,11 @@
#include "printing/pdf_metafile_mac.h"
+#include "base/file_path.h"
+#include "base/gfx/rect.h"
#include "base/logging.h"
+#include "base/scoped_cftyperef.h"
+#include "base/sys_string_conversions.h"
namespace printing {
@@ -85,9 +89,60 @@ void PdfMetafile::Close() {
DCHECK(context_.get());
DCHECK(!page_is_open_);
+#ifndef NDEBUG
+ // Check that the context will be torn down properly; if it's not, pdf_data_
+ // will be incomplete and generate invalid PDF files/documents.
+ if (context_.get()) {
+ CFIndex extra_retain_count = CFGetRetainCount(context_.get()) - 1;
+ if (extra_retain_count > 0) {
+ LOG(ERROR) << "Metafile context has " << extra_retain_count
+ << " extra retain(s) on Close";
+ }
+ }
+#endif
context_.reset(NULL);
}
+bool PdfMetafile::RenderPage(unsigned int page_number, CGContextRef context,
+ const CGRect rect) const {
+ CGPDFDocumentRef pdf_doc = GetPDFDocument();
+ if (!pdf_doc) {
+ LOG(ERROR) << "Unable to create PDF document from data";
+ return false;
+ }
+ CGPDFPageRef pdf_page = CGPDFDocumentGetPage(pdf_doc, page_number);
+ CGRect source_rect = CGPDFPageGetBoxRect(pdf_page, kCGPDFMediaBox);
+
+ CGContextSaveGState(context);
+ CGContextTranslateCTM(context, rect.origin.x, rect.origin.y);
+ CGContextScaleCTM(context, rect.size.width / source_rect.size.width,
+ rect.size.height / source_rect.size.height);
+ CGContextDrawPDFPage(context, pdf_page);
+ CGContextRestoreGState(context);
+
+ return true;
+}
+
+size_t PdfMetafile::GetPageCount() const {
+ CGPDFDocumentRef pdf_doc = GetPDFDocument();
+ return pdf_doc ? CGPDFDocumentGetNumberOfPages(pdf_doc) : 0;
+}
+
+gfx::Rect PdfMetafile::GetPageBounds(unsigned int page_number) const {
+ CGPDFDocumentRef pdf_doc = GetPDFDocument();
+ if (!pdf_doc) {
+ LOG(ERROR) << "Unable to create PDF document from data";
+ return gfx::Rect();
+ }
+ if (page_number > GetPageCount()) {
+ LOG(ERROR) << "Invalid page number: " << page_number;
+ return gfx::Rect();
+ }
+ CGPDFPageRef pdf_page = CGPDFDocumentGetPage(pdf_doc, page_number);
+ CGRect page_rect = CGPDFPageGetBoxRect(pdf_page, kCGPDFMediaBox);
+ return gfx::Rect(page_rect);
+}
+
unsigned int PdfMetafile::GetDataSize() const {
// PDF data is only valid/complete once the context is released.
DCHECK(!context_);
@@ -114,4 +169,30 @@ bool PdfMetafile::GetData(void* dst_buffer, size_t dst_buffer_size) const {
return true;
}
+bool PdfMetafile::SaveTo(const FilePath& file_path) const {
+ DCHECK(pdf_data_.get());
+ DCHECK(!context_.get());
+
+ std::string path_string = file_path.value();
+ scoped_cftyperef<CFURLRef> path_url(CFURLCreateFromFileSystemRepresentation(
+ kCFAllocatorDefault, reinterpret_cast<const UInt8*>(path_string.c_str()),
+ path_string.length(), false));
+ SInt32 error_code;
+ CFURLWriteDataAndPropertiesToResource(path_url, pdf_data_, NULL, &error_code);
+ return error_code == 0;
+}
+
+CGPDFDocumentRef PdfMetafile::GetPDFDocument() const {
+ // Make sure that we have data, and that it's not being modified any more.
+ DCHECK(pdf_data_.get());
+ DCHECK(!context_.get());
+
+ if (!pdf_doc_.get()) {
+ scoped_cftyperef<CGDataProviderRef> pdf_data_provider(
+ CGDataProviderCreateWithCFData(pdf_data_));
+ pdf_doc_.reset(CGPDFDocumentCreateWithProvider(pdf_data_provider));
+ }
+ return pdf_doc_.get();
+}
+
} // namespace printing
diff --git a/printing/pdf_metafile_mac.h b/printing/pdf_metafile_mac.h
index 607abf5..61ba98e 100644
--- a/printing/pdf_metafile_mac.h
+++ b/printing/pdf_metafile_mac.h
@@ -5,12 +5,17 @@
#ifndef PRINTING_PDF_METAFILE_MAC_H_
#define PRINTING_PDF_METAFILE_MAC_H_
-#import <ApplicationServices/ApplicationServices.h>
-#import <CoreFoundation/CoreFoundation.h>
+#include <ApplicationServices/ApplicationServices.h>
+#include <CoreFoundation/CoreFoundation.h>
#include "base/basictypes.h"
#include "base/scoped_cftyperef.h"
+namespace gfx {
+class Rect;
+}
+class FilePath;
+
namespace printing {
// This class creates a graphics context that renders into a PDF data stream.
@@ -45,6 +50,17 @@ class PdfMetafile {
// Closes the PDF file; no further rendering is allowed.
void Close();
+ // Renders the given page into |rect| in the given context.
+ // Pages use a 1-based index.
+ bool RenderPage(unsigned int page_number, CGContextRef context,
+ const CGRect rect) const;
+
+ size_t GetPageCount() const;
+
+ // Returns the bounds of the given page.
+ // Pages use a 1-based index.
+ gfx::Rect GetPageBounds(unsigned int page_number) const;
+
// Returns the size of the underlying PDF data. Only valid after Close() has
// been called.
unsigned int GetDataSize() const;
@@ -54,13 +70,23 @@ class PdfMetafile {
// Returns true if the copy succeeds.
bool GetData(void* dst_buffer, size_t dst_buffer_size) const;
+ // Saves the raw PDF data to the given file. For testing only.
+ // Returns true if writing succeeded.
+ bool SaveTo(const FilePath& file_path) const;
+
private:
+ // Returns a CGPDFDocumentRef version of pdf_data_.
+ CGPDFDocumentRef GetPDFDocument() const;
+
// Context for rendering to the pdf.
scoped_cftyperef<CGContextRef> context_;
// PDF backing store.
scoped_cftyperef<CFMutableDataRef> pdf_data_;
+ // Lazily-created CGPDFDocument representation of pdf_data_.
+ mutable scoped_cftyperef<CGPDFDocumentRef> pdf_doc_;
+
// Whether or not a page is currently open.
bool page_is_open_;
diff --git a/printing/pdf_metafile_mac_unittest.cc b/printing/pdf_metafile_mac_unittest.cc
index 1a1bf44..3a38e68 100644
--- a/printing/pdf_metafile_mac_unittest.cc
+++ b/printing/pdf_metafile_mac_unittest.cc
@@ -9,6 +9,7 @@
#include <string>
#include <vector>
+#include "base/gfx/rect.h"
#include "testing/gtest/include/gtest/gtest.h"
TEST(PdfMetafileTest, Pdf) {
@@ -46,4 +47,13 @@ TEST(PdfMetafileTest, Pdf) {
// Test that the header begins with "%PDF".
std::string header(&buffer2.front(), 4);
EXPECT_EQ(0U, header.find("%PDF", 0));
+
+ // Test that the PDF is correctly reconstructed.
+ EXPECT_EQ(2U, pdf2.GetPageCount());
+ gfx::Size page_size = pdf2.GetPageBounds(1).size();
+ EXPECT_EQ(540, page_size.width());
+ EXPECT_EQ(720, page_size.height());
+ page_size = pdf2.GetPageBounds(2).size();
+ EXPECT_EQ(720, page_size.width());
+ EXPECT_EQ(540, page_size.height());
}
diff --git a/printing/printed_document_mac.cc b/printing/printed_document_mac.cc
index ace57f3..e9bd044 100644
--- a/printing/printed_document_mac.cc
+++ b/printing/printed_document_mac.cc
@@ -24,28 +24,14 @@ void PrintedDocument::RenderPrintedPage(
}
#endif
- const printing::NativeMetafile* metafile = page.native_metafile();
- unsigned int data_length = metafile->GetDataSize();
- scoped_cftyperef<CFMutableDataRef> pdf_data(
- CFDataCreateMutable(kCFAllocatorDefault, data_length));
- CFDataIncreaseLength(pdf_data, data_length);
- metafile->GetData(CFDataGetMutableBytePtr(pdf_data), data_length);
- scoped_cftyperef<CGDataProviderRef> pdf_data_provider(
- CGDataProviderCreateWithCFData(pdf_data));
- scoped_cftyperef<CGPDFDocumentRef> pdf_doc(
- CGPDFDocumentCreateWithProvider(pdf_data_provider));
- if (!pdf_doc.get()) {
- NOTREACHED() << "Unable to create PDF document from print data";
- return;
- }
-
const printing::PageSetup& page_setup(
immutable_.settings_.page_setup_pixels());
CGRect target_rect = page_setup.content_area().ToCGRect();
- // Each NativeMetafile is a one-page PDF.
+ const printing::NativeMetafile* metafile = page.native_metafile();
+ // Each NativeMetafile is a one-page PDF, and pages use 1-based indexing.
const int page_number = 1;
- CGContextDrawPDFDocument(context, target_rect, pdf_doc, page_number);
+ metafile->RenderPage(page_number, context, target_rect);
// TODO(stuartmorgan): Print the header and footer.
}