diff options
-rw-r--r-- | printing/native_metafile.h | 15 | ||||
-rw-r--r-- | printing/pdf_metafile_mac.cc | 117 | ||||
-rw-r--r-- | printing/pdf_metafile_mac.h | 72 | ||||
-rw-r--r-- | printing/pdf_metafile_mac_unittest.cc | 49 | ||||
-rw-r--r-- | printing/printing.gyp | 3 |
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', |