summaryrefslogtreecommitdiffstats
path: root/printing
diff options
context:
space:
mode:
authorsverrir@google.com <sverrir@google.com@0039d316-1c4b-4281-b951-d872f2087c98>2009-07-06 15:25:50 +0000
committersverrir@google.com <sverrir@google.com@0039d316-1c4b-4281-b951-d872f2087c98>2009-07-06 15:25:50 +0000
commit0e0fca32b226a29a774728b642848bfdd732f791 (patch)
tree70547f886163e2a364ed47a8d5c85765d48f0e12 /printing
parentd09e2889c21d0a420b70680291906e4a17fb8503 (diff)
downloadchromium_src-0e0fca32b226a29a774728b642848bfdd732f791.zip
chromium_src-0e0fca32b226a29a774728b642848bfdd732f791.tar.gz
chromium_src-0e0fca32b226a29a774728b642848bfdd732f791.tar.bz2
Move Emf class to the printing library. Also creates a platform agnostic NativeMetafile definition to ease platform porting.
BUG=none TEST=none (No functional change) Review URL: http://codereview.chromium.org/149181 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@19943 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'printing')
-rw-r--r--printing/emf_win.cc317
-rw-r--r--printing/emf_win.h181
-rw-r--r--printing/emf_win_unittest.cc117
-rw-r--r--printing/native_metafile.h36
-rw-r--r--printing/printing.gyp15
5 files changed, 666 insertions, 0 deletions
diff --git a/printing/emf_win.cc b/printing/emf_win.cc
new file mode 100644
index 0000000..42380443
--- /dev/null
+++ b/printing/emf_win.cc
@@ -0,0 +1,317 @@
+// Copyright (c) 2006-2008 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/emf_win.h"
+
+#include "base/gfx/rect.h"
+#include "base/logging.h"
+
+namespace printing {
+
+Emf::Emf() : emf_(NULL), hdc_(NULL) {
+}
+
+Emf::~Emf() {
+ CloseEmf();
+ DCHECK(!emf_ && !hdc_);
+}
+
+bool Emf::CreateDc(HDC sibling, const RECT* rect) {
+ DCHECK(!emf_ && !hdc_);
+ hdc_ = CreateEnhMetaFile(sibling, NULL, rect, NULL);
+ DCHECK(hdc_);
+ return hdc_ != NULL;
+}
+
+bool Emf::CreateFromData(const void* buffer, size_t size) {
+ DCHECK(!emf_ && !hdc_);
+ emf_ = SetEnhMetaFileBits(static_cast<unsigned>(size),
+ reinterpret_cast<const BYTE*>(buffer));
+ DCHECK(emf_);
+ return emf_ != NULL;
+}
+
+bool Emf::CloseDc() {
+ DCHECK(!emf_ && hdc_);
+ emf_ = CloseEnhMetaFile(hdc_);
+ DCHECK(emf_);
+ hdc_ = NULL;
+ return emf_ != NULL;
+}
+
+void Emf::CloseEmf() {
+ DCHECK(!hdc_);
+ if (emf_) {
+ DeleteEnhMetaFile(emf_);
+ emf_ = NULL;
+ }
+}
+
+bool Emf::Playback(HDC hdc, const RECT* rect) const {
+ DCHECK(emf_ && !hdc_);
+ RECT bounds;
+ if (!rect) {
+ // Get the natural bounds of the EMF buffer.
+ bounds = GetBounds().ToRECT();
+ rect = &bounds;
+ }
+ return PlayEnhMetaFile(hdc, emf_, rect) != 0;
+}
+
+bool Emf::SafePlayback(HDC context) const {
+ DCHECK(emf_ && !hdc_);
+ XFORM base_matrix;
+ if (!GetWorldTransform(context, &base_matrix)) {
+ NOTREACHED();
+ return false;
+ }
+
+ return EnumEnhMetaFile(context,
+ emf_,
+ &Emf::SafePlaybackProc,
+ reinterpret_cast<void*>(&base_matrix),
+ &GetBounds().ToRECT()) != 0;
+}
+
+gfx::Rect Emf::GetBounds() const {
+ DCHECK(emf_ && !hdc_);
+ ENHMETAHEADER header;
+ if (GetEnhMetaFileHeader(emf_, sizeof(header), &header) != sizeof(header)) {
+ NOTREACHED();
+ return gfx::Rect();
+ }
+ if (header.rclBounds.left == 0 &&
+ header.rclBounds.top == 0 &&
+ header.rclBounds.right == -1 &&
+ header.rclBounds.bottom == -1) {
+ // A freshly created EMF buffer that has no drawing operation has invalid
+ // bounds. Instead of having an (0,0) size, it has a (-1,-1) size. Detect
+ // this special case and returns an empty Rect instead of an invalid one.
+ return gfx::Rect();
+ }
+ return gfx::Rect(header.rclBounds.left,
+ header.rclBounds.top,
+ header.rclBounds.right - header.rclBounds.left,
+ header.rclBounds.bottom - header.rclBounds.top);
+}
+
+unsigned Emf::GetDataSize() const {
+ DCHECK(emf_ && !hdc_);
+ return GetEnhMetaFileBits(emf_, 0, NULL);
+}
+
+bool Emf::GetData(void* buffer, size_t size) const {
+ DCHECK(emf_ && !hdc_);
+ DCHECK(buffer && size);
+ unsigned size2 = GetEnhMetaFileBits(emf_, static_cast<unsigned>(size),
+ reinterpret_cast<BYTE*>(buffer));
+ DCHECK(size2 == size);
+ return size2 == size && size2 != 0;
+}
+
+bool Emf::GetData(std::vector<uint8>* buffer) const {
+ unsigned size = GetDataSize();
+ if (!size)
+ return false;
+
+ buffer->resize(size);
+ if (!GetData(&buffer->front(), size))
+ return false;
+ return true;
+}
+
+bool Emf::SaveTo(const std::wstring& filename) const {
+ HANDLE file = CreateFile(filename.c_str(), GENERIC_WRITE,
+ FILE_SHARE_READ | FILE_SHARE_WRITE, NULL,
+ CREATE_ALWAYS, 0, NULL);
+ if (file == INVALID_HANDLE_VALUE)
+ return false;
+
+ bool success = false;
+ std::vector<uint8> buffer;
+ if (GetData(&buffer)) {
+ DWORD written = 0;
+ if (WriteFile(file, &*buffer.begin(), static_cast<DWORD>(buffer.size()),
+ &written, NULL) &&
+ written == buffer.size()) {
+ success = true;
+ }
+ }
+ CloseHandle(file);
+ return success;
+}
+
+int CALLBACK Emf::SafePlaybackProc(HDC hdc,
+ HANDLETABLE* handle_table,
+ const ENHMETARECORD* record,
+ int objects_count,
+ LPARAM param) {
+ const XFORM* base_matrix = reinterpret_cast<const XFORM*>(param);
+ EnumerationContext context;
+ context.handle_table = handle_table;
+ context.objects_count = objects_count;
+ context.hdc = hdc;
+ Record record_instance(&context, record);
+ bool success = record_instance.SafePlayback(base_matrix);
+ DCHECK(success);
+ return 1;
+}
+
+Emf::Record::Record() {
+}
+
+Emf::Record::Record(const EnumerationContext* context,
+ const ENHMETARECORD* record)
+ : record_(record),
+ context_(context) {
+ DCHECK(record_);
+}
+
+bool Emf::Record::Play() const {
+ return 0 != PlayEnhMetaFileRecord(context_->hdc,
+ context_->handle_table,
+ record_,
+ context_->objects_count);
+}
+
+bool Emf::Record::SafePlayback(const XFORM* base_matrix) const {
+ // For EMF field description, see [MS-EMF] Enhanced Metafile Format
+ // Specification.
+ //
+ // This is the second major EMF breakage I get; the first one being
+ // SetDCBrushColor/SetDCPenColor/DC_PEN/DC_BRUSH being silently ignored.
+ //
+ // This function is the guts of the fix for bug 1186598. Some printer drivers
+ // somehow choke on certain EMF records, but calling the corresponding
+ // function directly on the printer HDC is fine. Still, playing the EMF record
+ // fails. Go figure.
+ //
+ // The main issue is that SetLayout is totally unsupported on these printers
+ // (HP 4500/4700). I used to call SetLayout and I stopped. I found out this is
+ // not sufficient because GDI32!PlayEnhMetaFile internally calls SetLayout(!)
+ // Damn.
+ //
+ // So I resorted to manually parse the EMF records and play them one by one.
+ // The issue with this method compared to using PlayEnhMetaFile to play back
+ // an EMF buffer is that the later silently fixes the matrix to take in
+ // account the matrix currently loaded at the time of the call.
+ // The matrix magic is done transparently when using PlayEnhMetaFile but since
+ // I'm processing one field at a time, I need to do the fixup myself. Note
+ // that PlayEnhMetaFileRecord doesn't fix the matrix correctly even when
+ // called inside an EnumEnhMetaFile loop. Go figure (bis).
+ //
+ // So when I see a EMR_SETWORLDTRANSFORM and EMR_MODIFYWORLDTRANSFORM, I need
+ // to fix the matrix according to the matrix previously loaded before playing
+ // back the buffer. Otherwise, the previously loaded matrix would be ignored
+ // and the EMF buffer would always be played back at its native resolution.
+ // Duh.
+ //
+ // I also use this opportunity to skip over eventual EMR_SETLAYOUT record that
+ // could remain.
+ //
+ // Note: I should probably care about view ports and clipping, eventually.
+ bool res;
+ switch (record()->iType) {
+ case EMR_SETWORLDTRANSFORM: {
+ DCHECK_EQ(record()->nSize, sizeof(DWORD) * 2 + sizeof(XFORM));
+ const XFORM* xform = reinterpret_cast<const XFORM*>(record()->dParm);
+ HDC hdc = context_->hdc;
+ if (base_matrix) {
+ res = 0 != SetWorldTransform(hdc, base_matrix) &&
+ ModifyWorldTransform(hdc, xform, MWT_LEFTMULTIPLY);
+ } else {
+ res = 0 != SetWorldTransform(hdc, xform);
+ }
+ break;
+ }
+ case EMR_MODIFYWORLDTRANSFORM: {
+ DCHECK_EQ(record()->nSize,
+ sizeof(DWORD) * 2 + sizeof(XFORM) + sizeof(DWORD));
+ const XFORM* xform = reinterpret_cast<const XFORM*>(record()->dParm);
+ const DWORD* option = reinterpret_cast<const DWORD*>(xform + 1);
+ HDC hdc = context_->hdc;
+ switch (*option) {
+ case MWT_IDENTITY:
+ if (base_matrix) {
+ res = 0 != SetWorldTransform(hdc, base_matrix);
+ } else {
+ res = 0 != ModifyWorldTransform(hdc, xform, MWT_IDENTITY);
+ }
+ break;
+ case MWT_LEFTMULTIPLY:
+ case MWT_RIGHTMULTIPLY:
+ res = 0 != ModifyWorldTransform(hdc, xform, *option);
+ break;
+ case 4: // MWT_SET
+ if (base_matrix) {
+ res = 0 != SetWorldTransform(hdc, base_matrix) &&
+ ModifyWorldTransform(hdc, xform, MWT_LEFTMULTIPLY);
+ } else {
+ res = 0 != SetWorldTransform(hdc, xform);
+ }
+ break;
+ default:
+ res = false;
+ break;
+ }
+ break;
+ }
+ case EMR_SETLAYOUT:
+ // Ignore it.
+ res = true;
+ break;
+ default: {
+ res = Play();
+ break;
+ }
+ }
+ return res;
+}
+
+Emf::Enumerator::Enumerator(const Emf& emf, HDC context, const RECT* rect) {
+ context_.handle_table = NULL;
+ context_.objects_count = 0;
+ context_.hdc = NULL;
+ items_.clear();
+ if (!EnumEnhMetaFile(context,
+ emf.emf(),
+ &Emf::Enumerator::EnhMetaFileProc,
+ reinterpret_cast<void*>(this),
+ rect)) {
+ NOTREACHED();
+ items_.clear();
+ }
+ DCHECK_EQ(context_.hdc, context);
+}
+
+Emf::Enumerator::const_iterator Emf::Enumerator::begin() const {
+ return items_.begin();
+}
+
+Emf::Enumerator::const_iterator Emf::Enumerator::end() const {
+ return items_.end();
+}
+
+int CALLBACK Emf::Enumerator::EnhMetaFileProc(HDC hdc,
+ HANDLETABLE* handle_table,
+ const ENHMETARECORD* record,
+ int objects_count,
+ LPARAM param) {
+ Enumerator& emf = *reinterpret_cast<Enumerator*>(param);
+ if (!emf.context_.handle_table) {
+ DCHECK(!emf.context_.handle_table);
+ DCHECK(!emf.context_.objects_count);
+ emf.context_.handle_table = handle_table;
+ emf.context_.objects_count = objects_count;
+ emf.context_.hdc = hdc;
+ } else {
+ DCHECK_EQ(emf.context_.handle_table, handle_table);
+ DCHECK_EQ(emf.context_.objects_count, objects_count);
+ DCHECK_EQ(emf.context_.hdc, hdc);
+ }
+ emf.items_.push_back(Record(&emf.context_, record));
+ return 1;
+}
+
+} // namespace printing
diff --git a/printing/emf_win.h b/printing/emf_win.h
new file mode 100644
index 0000000..7be747a
--- /dev/null
+++ b/printing/emf_win.h
@@ -0,0 +1,181 @@
+// Copyright (c) 2006-2008 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_EMF_WIN_H__
+#define PRINTING_EMF_WIN_H__
+
+#include <windows.h>
+#include <vector>
+
+#include "base/basictypes.h"
+
+namespace gfx {
+class Rect;
+}
+
+namespace printing {
+
+// Simple wrapper class that manage an EMF data stream and its virtual HDC.
+class Emf {
+ public:
+ class Record;
+ class Enumerator;
+ struct EnumerationContext;
+
+ Emf();
+ ~Emf();
+
+ // Generates a virtual HDC that will record every GDI commands and compile it
+ // in a EMF data stream.
+ // hdc is used to setup the default DPI and color settings. hdc is optional.
+ // rect specifies the dimensions (in .01-millimeter units) of the EMF. rect is
+ // optional.
+ bool CreateDc(HDC sibling, const RECT* rect);
+
+ // Load a EMF data stream. buffer contains EMF data.
+ bool CreateFromData(const void* buffer, size_t size);
+
+ // TODO(maruel): CreateFromFile(). If ever used. Maybe users would like to
+ // have the ability to save web pages to an EMF file? Afterward, it is easy to
+ // convert to PDF or PS.
+
+ // Closes the HDC created by CreateDc() and generates the compiled EMF
+ // data.
+ bool CloseDc();
+
+ // Closes the EMF data handle when it is not needed anymore.
+ void CloseEmf();
+
+ // "Plays" the EMF buffer in a HDC. It is the same effect as calling the
+ // original GDI function that were called when recording the EMF. |rect| is in
+ // "logical units" and is optional. If |rect| is NULL, the natural EMF bounds
+ // are used.
+ // Note: Windows has been known to have stack buffer overflow in its GDI
+ // functions, whether used directly or indirectly through precompiled EMF
+ // data. We have to accept the risk here. Since it is used only for printing,
+ // it requires user intervention.
+ bool Playback(HDC hdc, const RECT* rect) const;
+
+ // The slow version of Playback(). It enumerates all the records and play them
+ // back in the HDC. The trick is that it skip over the records known to have
+ // issue with some printers. See Emf::Record::SafePlayback implementation for
+ // details.
+ bool SafePlayback(HDC hdc) const;
+
+ // Retrieves the bounds of the painted area by this EMF buffer. This value
+ // should be passed to Playback to keep the exact same size.
+ gfx::Rect GetBounds() const;
+
+ // Retrieves the EMF stream size.
+ unsigned GetDataSize() const;
+
+ // Retrieves the EMF stream.
+ bool GetData(void* buffer, size_t size) const;
+
+ // Retrieves the EMF stream. It is an helper function.
+ bool GetData(std::vector<uint8>* buffer) const;
+
+ HENHMETAFILE emf() const {
+ return emf_;
+ }
+
+ HDC hdc() const {
+ return hdc_;
+ }
+
+ // Saves the EMF data to a file as-is. It is recommended to use the .emf file
+ // extension but it is not enforced. This function synchronously writes to the
+ // file. For testing only.
+ bool SaveTo(const std::wstring& filename) const;
+
+ private:
+ // Playbacks safely one EMF record.
+ static int CALLBACK SafePlaybackProc(HDC hdc,
+ HANDLETABLE* handle_table,
+ const ENHMETARECORD* record,
+ int objects_count,
+ LPARAM param);
+
+ // Compiled EMF data handle.
+ HENHMETAFILE emf_;
+
+ // Valid when generating EMF data through a virtual HDC.
+ HDC hdc_;
+
+ DISALLOW_EVIL_CONSTRUCTORS(Emf);
+};
+
+struct Emf::EnumerationContext {
+ HANDLETABLE* handle_table;
+ int objects_count;
+ HDC hdc;
+};
+
+// One EMF record. It keeps pointers to the EMF buffer held by Emf::emf_.
+// The entries become invalid once Emf::CloseEmf() is called.
+class Emf::Record {
+ public:
+ Record();
+
+ // Plays the record.
+ bool Play() const;
+
+ // Plays the record working around quirks with SetLayout,
+ // SetWorldTransform and ModifyWorldTransform. See implementation for details.
+ bool SafePlayback(const XFORM* base_matrix) const;
+
+ // Access the underlying EMF record.
+ const ENHMETARECORD* record() const { return record_; }
+
+ protected:
+ Record(const EnumerationContext* context,
+ const ENHMETARECORD* record);
+
+ private:
+ friend class Emf;
+ friend class Enumerator;
+ const ENHMETARECORD* record_;
+ const EnumerationContext* context_;
+};
+
+// Retrieves individual records out of a Emf buffer. The main use is to skip
+// over records that are unsupported on a specific printer or to play back
+// only a part of an EMF buffer.
+class Emf::Enumerator {
+ public:
+ // Iterator type used for iterating the records.
+ typedef std::vector<Record>::const_iterator const_iterator;
+
+ // Enumerates the records at construction time. |hdc| and |rect| are
+ // both optional at the same time or must both be valid.
+ // Warning: |emf| must be kept valid for the time this object is alive.
+ Enumerator(const Emf& emf, HDC hdc, const RECT* rect);
+
+ // Retrieves the first Record.
+ const_iterator begin() const;
+
+ // Retrieves the end of the array.
+ const_iterator end() const;
+
+ private:
+ // Processes one EMF record and saves it in the items_ array.
+ static int CALLBACK EnhMetaFileProc(HDC hdc,
+ HANDLETABLE* handle_table,
+ const ENHMETARECORD* record,
+ int objects_count,
+ LPARAM param);
+
+ // The collection of every EMF records in the currently loaded EMF buffer.
+ // Initialized by Enumerate(). It keeps pointers to the EMF buffer held by
+ // Emf::emf_. The entries become invalid once Emf::CloseEmf() is called.
+ std::vector<Record> items_;
+
+ EnumerationContext context_;
+
+ DISALLOW_EVIL_CONSTRUCTORS(Enumerator);
+};
+
+} // namespace printing
+
+#endif // PRINTING_EMF_WIN_H__
diff --git a/printing/emf_win_unittest.cc b/printing/emf_win_unittest.cc
new file mode 100644
index 0000000..ab817db
--- /dev/null
+++ b/printing/emf_win_unittest.cc
@@ -0,0 +1,117 @@
+// Copyright (c) 2006-2008 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/emf_win.h"
+
+// For quick access.
+#include <wingdi.h>
+
+#include "base/basictypes.h"
+#include "base/file_util.h"
+#include "base/path_service.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace {
+
+// This test is automatically disabled if no printer named "UnitTest Printer" is
+// available.
+class EmfPrintingTest : public testing::Test {
+ public:
+ typedef testing::Test Parent;
+ static bool IsTestCaseDisabled() {
+ // It is assumed this printer is a HP Color LaserJet 4550 PCL or 4700.
+ HDC hdc = CreateDC(L"WINSPOOL", L"UnitTest Printer", NULL, NULL);
+ if (!hdc)
+ return true;
+ DeleteDC(hdc);
+ return false;
+ }
+};
+
+} // namespace
+
+TEST(EmfTest, DC) {
+ static const int EMF_HEADER_SIZE = 128;
+
+ // Simplest use case.
+ printing::Emf emf;
+ RECT rect = {100, 100, 200, 200};
+ HDC hdc = CreateCompatibleDC(NULL);
+ EXPECT_TRUE(hdc != NULL);
+ EXPECT_TRUE(emf.CreateDc(hdc, &rect));
+ EXPECT_TRUE(emf.hdc() != NULL);
+ // In theory, you'd use the HDC with GDI functions here.
+ EXPECT_TRUE(emf.CloseDc());
+ unsigned size = emf.GetDataSize();
+ EXPECT_EQ(size, EMF_HEADER_SIZE);
+ std::vector<BYTE> data;
+ EXPECT_TRUE(emf.GetData(&data));
+ EXPECT_EQ(data.size(), size);
+ emf.CloseEmf();
+ EXPECT_TRUE(DeleteDC(hdc));
+
+ // Playback the data.
+ hdc = CreateCompatibleDC(NULL);
+ EXPECT_TRUE(hdc);
+ EXPECT_TRUE(emf.CreateFromData(&data.front(), size));
+ RECT output_rect = {0, 0, 10, 10};
+ EXPECT_TRUE(emf.Playback(hdc, &output_rect));
+ EXPECT_TRUE(DeleteDC(hdc));
+}
+
+// TODO(sverrir): Re-enable after win_printing_context has been moved here.
+/*
+#include "chrome/browser/printing/win_printing_context.h"
+#include "chrome/common/chrome_paths.h"
+
+// Disabled if no "UnitTest printer" exist. Useful to reproduce bug 1186598.
+TEST_F(EmfPrintingTest, Enumerate) {
+ if (IsTestCaseDisabled())
+ return;
+
+ printing::PrintSettings settings;
+
+ // My test case is a HP Color LaserJet 4550 PCL.
+ settings.set_device_name(L"UnitTest Printer");
+
+ // Initialize it.
+ printing::PrintingContext context;
+ EXPECT_EQ(context.InitWithSettings(settings), printing::PrintingContext::OK);
+
+ std::wstring test_file;
+ PathService::Get(chrome::DIR_TEST_DATA, &test_file);
+
+ // Load any EMF with an image.
+ printing::Emf emf;
+ file_util::AppendToPath(&test_file, L"printing");
+ file_util::AppendToPath(&test_file, L"test4.emf");
+ std::string emf_data;
+ file_util::ReadFileToString(test_file, &emf_data);
+ ASSERT_TRUE(emf_data.size());
+ EXPECT_TRUE(emf.CreateFromData(&emf_data[0], emf_data.size()));
+
+ // This will print to file. The reason is that when running inside a
+ // unit_test, printing::PrintingContext automatically dumps its files to the
+ // current directory.
+ // TODO(maruel): Clean the .PRN file generated in current directory.
+ context.NewDocument(L"EmfTest.Enumerate");
+ context.NewPage();
+ // Process one at a time.
+ printing::Emf::Enumerator emf_enum(emf, context.context(),
+ &emf.GetBounds().ToRECT());
+ for (printing::Emf::Enumerator::const_iterator itr = emf_enum.begin();
+ itr != emf_enum.end();
+ ++itr) {
+ // To help debugging.
+ ptrdiff_t index = itr - emf_enum.begin();
+ // If you get this assert, you need to lookup iType in wingdi.h. It starts
+ // with EMR_HEADER.
+ EMR_HEADER;
+ EXPECT_TRUE(itr->SafePlayback(NULL)) <<
+ " index: " << index << " type: " << itr->record()->iType;
+ }
+ context.PageDone();
+ context.DocumentDone();
+}
+*/
diff --git a/printing/native_metafile.h b/printing/native_metafile.h
new file mode 100644
index 0000000..6963089
--- /dev/null
+++ b/printing/native_metafile.h
@@ -0,0 +1,36 @@
+// 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_NATIVE_METAFILE_H__
+#define PRINTING_NATIVE_METAFILE_H__
+
+// Define a metafile format for the current platform. We use this platform
+// independent define so we can define interfaces in platform agnostic manner.
+// It is still an outstanding design issue whether we create classes on all
+// platforms that have the same interface as Emf or if we change Emf to support
+// multiple platforms (and rename to NativeMetafile).
+
+
+#if defined(OS_WIN)
+
+#include "printing/emf_win.h"
+
+namespace printing {
+
+typedef Emf NativeMetafile;
+
+} // namespace printing
+
+#elif defined(OS_MACOSX)
+
+// TODO(port): Printing using PDF?
+
+#elif defined(OS_LINUX)
+
+// TODO(port): Printing using PostScript?
+
+#endif
+
+
+#endif // PRINTING_NATIVE_METAFILE_H__
diff --git a/printing/printing.gyp b/printing/printing.gyp
index 1980417..899bded 100644
--- a/printing/printing.gyp
+++ b/printing/printing.gyp
@@ -15,12 +15,17 @@
'type': '<(library)',
'dependencies': [
'../base/base.gyp:base',
+ '../base/base.gyp:base_gfx',
+
],
'msvs_guid': '9E5416B9-B91B-4029-93F4-102C1AD5CAF4',
'include_dirs': [
'..',
],
'sources': [
+ 'emf_win.cc',
+ 'emf_win.h',
+ 'native_metafile.h',
'units.cc',
'units.h',
],
@@ -49,8 +54,18 @@
'../testing/gtest.gyp:gtestmain',
],
'sources': [
+ 'emf_win_unittest.cc',
'units_unittest.cc',
],
+ 'conditions': [
+ ['OS!="linux"', {'sources/': [['exclude', '_linux_unittest\\.cc$']]}],
+ ['OS!="mac"', {'sources/': [['exclude', '_mac_unittest\\.(cc|mm?)$']]}],
+ ['OS!="win"', {
+ 'sources/': [['exclude', '_win_unittest\\.cc$']]
+ }, { # else: OS=="win"
+ 'sources/': [['exclude', '_posix_unittest\\.cc$']]
+ }],
+ ],
},
],
}