summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--printing/native_metafile.h15
-rw-r--r--printing/pdf_metafile_mac.cc117
-rw-r--r--printing/pdf_metafile_mac.h72
-rw-r--r--printing/pdf_metafile_mac_unittest.cc49
-rw-r--r--printing/printing.gyp3
5 files changed, 248 insertions, 8 deletions
diff --git a/printing/native_metafile.h b/printing/native_metafile.h
index e30a43e..2c71986 100644
--- a/printing/native_metafile.h
+++ b/printing/native_metafile.h
@@ -26,14 +26,13 @@ typedef Emf NativeMetafile;
#elif defined(OS_MACOSX)
-// TODO(port): Printing using CG/PDF?
-// The mock class is here so we can compile.
-class NativeMetafile {
- public:
- int GetDataSize() const { return 0; }
- private:
- DISALLOW_COPY_AND_ASSIGN(NativeMetafile);
-};
+#include "printing/pdf_metafile_mac.h"
+
+namespace printing {
+
+typedef PdfMetafile NativeMetafile;
+
+} // namespace printing
#elif defined(OS_LINUX)
diff --git a/printing/pdf_metafile_mac.cc b/printing/pdf_metafile_mac.cc
new file mode 100644
index 0000000..6a8cd55
--- /dev/null
+++ b/printing/pdf_metafile_mac.cc
@@ -0,0 +1,117 @@
+// Copyright (c) 2009 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.
+
+#include "printing/pdf_metafile_mac.h"
+
+#include "base/logging.h"
+
+namespace printing {
+
+PdfMetafile::PdfMetafile()
+ : page_is_open_(false) {
+}
+
+CGContextRef PdfMetafile::Init() {
+ // Ensure that Init hasn't already been called.
+ DCHECK(!context_.get());
+ DCHECK(!pdf_data_.get());
+
+ pdf_data_.reset(CFDataCreateMutable(kCFAllocatorDefault, 0));
+ if (!pdf_data_.get()) {
+ LOG(ERROR) << "Failed to create pdf data for metafile";
+ return NULL;
+ }
+ scoped_cftyperef<CGDataConsumerRef> pdf_consumer(
+ CGDataConsumerCreateWithCFData(pdf_data_));
+ if (!pdf_consumer.get()) {
+ LOG(ERROR) << "Failed to create data consumer for metafile";
+ pdf_data_.reset(NULL);
+ return NULL;
+ }
+ context_.reset(CGPDFContextCreate(pdf_consumer, NULL, NULL));
+ if (!context_.get()) {
+ LOG(ERROR) << "Failed to create pdf context for metafile";
+ pdf_data_.reset(NULL);
+ }
+
+ return context_.get();
+}
+
+bool PdfMetafile::Init(const void* src_buffer, size_t src_buffer_size) {
+ DCHECK(!context_.get());
+ DCHECK(!pdf_data_.get());
+
+ if (!src_buffer || src_buffer_size == 0) {
+ return false;
+ }
+
+ pdf_data_.reset(CFDataCreateMutable(kCFAllocatorDefault, src_buffer_size));
+ CFDataAppendBytes(pdf_data_, static_cast<const UInt8*>(src_buffer),
+ src_buffer_size);
+
+ return true;
+}
+
+bool PdfMetafile::CreateFromData(const void* src_buffer,
+ size_t src_buffer_size) {
+ return Init(src_buffer, src_buffer_size);
+}
+
+void PdfMetafile::StartPage(double width, double height, double scale_factor) {
+ DCHECK(context_.get());
+ DCHECK(!page_is_open_);
+
+ CGRect bounds = CGRectMake(0, 0, width, height);
+ CGContextBeginPage(context_, &bounds);
+ page_is_open_ = true;
+ CGContextSaveGState(context_);
+
+ // Flip the context.
+ CGContextTranslateCTM(context_, 0, height);
+ CGContextScaleCTM(context_, scale_factor, -scale_factor);
+}
+
+void PdfMetafile::FinishPage() {
+ DCHECK(context_.get());
+ DCHECK(page_is_open_);
+
+ CGContextRestoreGState(context_);
+ CGContextEndPage(context_);
+ page_is_open_ = false;
+}
+
+void PdfMetafile::Close() {
+ DCHECK(context_.get());
+ DCHECK(!page_is_open_);
+
+ context_.reset(NULL);
+}
+
+unsigned int PdfMetafile::GetDataSize() const {
+ // PDF data is only valid/complete once the context is released.
+ DCHECK(!context_);
+
+ if (!pdf_data_)
+ return 0;
+ return static_cast<unsigned int>(CFDataGetLength(pdf_data_));
+}
+
+bool PdfMetafile::GetData(void* dst_buffer, size_t dst_buffer_size) const {
+ // PDF data is only valid/complete once the context is released.
+ DCHECK(!context_);
+ DCHECK(pdf_data_);
+ DCHECK(dst_buffer);
+ DCHECK_GT(dst_buffer_size, 0U);
+
+ size_t data_size = GetDataSize();
+ if (dst_buffer_size > data_size) {
+ return false;
+ }
+
+ CFDataGetBytes(pdf_data_, CFRangeMake(0, dst_buffer_size),
+ static_cast<UInt8*>(dst_buffer));
+ return true;
+}
+
+} // namespace printing
diff --git a/printing/pdf_metafile_mac.h b/printing/pdf_metafile_mac.h
new file mode 100644
index 0000000..607abf5
--- /dev/null
+++ b/printing/pdf_metafile_mac.h
@@ -0,0 +1,72 @@
+// Copyright (c) 2009 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.
+
+#ifndef PRINTING_PDF_METAFILE_MAC_H_
+#define PRINTING_PDF_METAFILE_MAC_H_
+
+#import <ApplicationServices/ApplicationServices.h>
+#import <CoreFoundation/CoreFoundation.h>
+
+#include "base/basictypes.h"
+#include "base/scoped_cftyperef.h"
+
+namespace printing {
+
+// This class creates a graphics context that renders into a PDF data stream.
+class PdfMetafile {
+ public:
+ // To create PDF data, callers should also call Init() to set up the
+ // rendering context.
+ // To create a metafile from existing Data, callers should also call
+ // Init(const void*, size_t).
+ PdfMetafile();
+
+ ~PdfMetafile() {}
+
+ // Initializes a new metafile, and returns a drawing context for rendering
+ // into the PDF. Returns NULL on failure.
+ // Note: The returned context *must not be retained* past Close(). If it is,
+ // the data returned from GetData will not be valid PDF data.
+ CGContextRef Init();
+
+ // Initializes a copy of metafile from PDF data. Returns true on success.
+ bool Init(const void* src_buffer, size_t src_buffer_size);
+ // Alias for Init, for compatibility with Emf-based code.
+ bool CreateFromData(const void* src_buffer, size_t src_buffer_size);
+
+ // Prepares a new pdf page with the given width and height and a scale
+ // factor to use for the drawing.
+ void StartPage(double width, double height, double scale_factor);
+
+ // Closes the current page.
+ void FinishPage();
+
+ // Closes the PDF file; no further rendering is allowed.
+ void Close();
+
+ // Returns the size of the underlying PDF data. Only valid after Close() has
+ // been called.
+ unsigned int GetDataSize() const;
+
+ // Copies the first |dst_buffer_size| bytes of the PDF data into |dst_buffer|.
+ // Only valid after Close() has been called.
+ // Returns true if the copy succeeds.
+ bool GetData(void* dst_buffer, size_t dst_buffer_size) const;
+
+ private:
+ // Context for rendering to the pdf.
+ scoped_cftyperef<CGContextRef> context_;
+
+ // PDF backing store.
+ scoped_cftyperef<CFMutableDataRef> pdf_data_;
+
+ // Whether or not a page is currently open.
+ bool page_is_open_;
+
+ DISALLOW_COPY_AND_ASSIGN(PdfMetafile);
+};
+
+} // namespace printing
+
+#endif // PRINTING_PDF_METAFILE_MAC_H_
diff --git a/printing/pdf_metafile_mac_unittest.cc b/printing/pdf_metafile_mac_unittest.cc
new file mode 100644
index 0000000..1a1bf44
--- /dev/null
+++ b/printing/pdf_metafile_mac_unittest.cc
@@ -0,0 +1,49 @@
+// Copyright (c) 2009 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.
+
+#include "printing/pdf_metafile_mac.h"
+
+#import <ApplicationServices/ApplicationServices.h>
+
+#include <string>
+#include <vector>
+
+#include "testing/gtest/include/gtest/gtest.h"
+
+TEST(PdfMetafileTest, Pdf) {
+ // Test in-renderer constructor.
+ printing::PdfMetafile pdf;
+ CGContextRef context = pdf.Init();
+ EXPECT_TRUE(context != NULL);
+
+ // Render page 1.
+ pdf.StartPage(540, 720, 1.25);
+ pdf.FinishPage();
+
+ // Render page 2.
+ pdf.StartPage(720, 540, 2.0);
+ pdf.FinishPage();
+
+ pdf.Close();
+
+ // Check data size.
+ unsigned int size = pdf.GetDataSize();
+ EXPECT_GT(size, 0U);
+
+ // Get resulting data.
+ std::vector<char> buffer(size, 0);
+ pdf.GetData(&buffer.front(), size);
+
+ // Test browser-side constructor.
+ printing::PdfMetafile pdf2;
+ EXPECT_TRUE(pdf2.Init(&buffer.front(), size));
+
+ // Get the first 4 characters from pdf2.
+ std::vector<char> buffer2(4, 0);
+ pdf2.GetData(&buffer2.front(), 4);
+
+ // Test that the header begins with "%PDF".
+ std::string header(&buffer2.front(), 4);
+ EXPECT_EQ(0U, header.find("%PDF", 0));
+}
diff --git a/printing/printing.gyp b/printing/printing.gyp
index c4fe2b8..84545a8 100644
--- a/printing/printing.gyp
+++ b/printing/printing.gyp
@@ -37,6 +37,8 @@
'page_range.h',
'page_setup.cc',
'page_setup.h',
+ 'pdf_metafile_mac.h',
+ 'pdf_metafile_mac.cc',
'pdf_ps_metafile_linux.h',
'pdf_ps_metafile_linux.cc',
'print_settings.cc',
@@ -88,6 +90,7 @@
'page_overlays_unittest.cc',
'page_range_unittest.cc',
'page_setup_unittest.cc',
+ 'pdf_metafile_mac_unittest.cc',
'pdf_ps_metafile_linux_unittest.cc',
'printing_context_win_unittest.cc',
'run_all_unittests.cc',