summaryrefslogtreecommitdiffstats
path: root/printing
diff options
context:
space:
mode:
authorstuartmorgan@chromium.org <stuartmorgan@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2009-10-14 20:02:27 +0000
committerstuartmorgan@chromium.org <stuartmorgan@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2009-10-14 20:02:27 +0000
commit72f966bbd75a095ef73a121e16f5713172b51d09 (patch)
tree6f7404eb02a40fa2337d59a3d5a65b2fe4368d28 /printing
parentd5ceb91979a8f47ca1e7e22a608eeaa7db933a14 (diff)
downloadchromium_src-72f966bbd75a095ef73a121e16f5713172b51d09.zip
chromium_src-72f966bbd75a095ef73a121e16f5713172b51d09.tar.gz
chromium_src-72f966bbd75a095ef73a121e16f5713172b51d09.tar.bz2
Enable the RenderViewTest printing tests on the Mac.
Migrates some test APIs from wstring path names to FilePath objects, and fixes some gcc compilation issues, to allow the tests to build on Mac. Moves rendering logic and some other pdf logic into PdfMetafile to avoid duplication with unit test code. Switches rendering from the deprecated CGContextDrawPDFDocument to the newer (but less convenient) CGContextDrawPDFPage. Added debugging helpers to PdfMetafile: SaveTo, matching the other platform metafiles, and context retain count checking to get early warning of issues that will cause printing failure. BUG=24750 TEST=N/A Review URL: http://codereview.chromium.org/274052 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@29003 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'printing')
-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
6 files changed, 150 insertions, 23 deletions
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.
}