[go: nahoru, domu]

Printing: Convert PrintingContext into an interface implemented by the separate
platforms.

BUG=none
TEST=none

Review URL: http://codereview.chromium.org/3610013

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@61714 0039d316-1c4b-4281-b951-d872f2087c98
diff --git a/chrome/browser/printing/print_job_unittest.cc b/chrome/browser/printing/print_job_unittest.cc
index fb737bc..757d6c8 100644
--- a/chrome/browser/printing/print_job_unittest.cc
+++ b/chrome/browser/printing/print_job_unittest.cc
@@ -44,8 +44,8 @@
     // That's fine for testing. It is actually simulating PrinterQuery behavior.
     TestPrintJobWorker* worker(new TestPrintJobWorker(new_owner));
     EXPECT_TRUE(worker->Start());
-    worker->printing_context().UseDefaultSettings();
-    settings_ = worker->printing_context().settings();
+    worker->printing_context()->UseDefaultSettings();
+    settings_ = worker->printing_context()->settings();
     return worker;
   }
   virtual MessageLoop* message_loop() {
diff --git a/chrome/browser/printing/print_job_worker.cc b/chrome/browser/printing/print_job_worker.cc
index 20e51ea3..af20db2 100644
--- a/chrome/browser/printing/print_job_worker.cc
+++ b/chrome/browser/printing/print_job_worker.cc
@@ -52,6 +52,8 @@
       owner_(owner) {
   // The object is created in the IO thread.
   DCHECK_EQ(owner_->message_loop(), MessageLoop::current());
+
+  printing_context_.reset(PrintingContext::Create());
 }
 
 PrintJobWorker::~PrintJobWorker() {
@@ -75,7 +77,7 @@
   // Recursive task processing is needed for the dialog in case it needs to be
   // destroyed by a task.
   MessageLoop::current()->SetNestableTasksAllowed(true);
-  printing_context_.SetUseOverlays(use_overlays);
+  printing_context_->set_use_overlays(use_overlays);
 
   if (ask_user_for_settings) {
 #if defined(OS_MACOSX) || defined(USE_X11)
@@ -85,14 +87,14 @@
                           parent_view, document_page_count,
                           has_selection));
 #else
-    printing_context_.AskUserForSettings(
+    printing_context_->AskUserForSettings(
         parent_view,
         document_page_count,
         has_selection,
         NewCallback(this, &PrintJobWorker::GetSettingsDone));
 #endif  // defined(OS_MACOSX) || defined(USE_X11)
   } else {
-    PrintingContext::Result result = printing_context_.UseDefaultSettings();
+    PrintingContext::Result result = printing_context_->UseDefaultSettings();
     GetSettingsDone(result);
   }
 }
@@ -108,7 +110,7 @@
   owner_->message_loop()->PostTask(FROM_HERE, NewRunnableMethod(
       owner_,
       &PrintJobWorkerOwner::GetSettingsDone,
-      printing_context_.settings(),
+      printing_context_->settings(),
       result));
 }
 
@@ -118,7 +120,7 @@
                                        bool has_selection) {
   DCHECK(ChromeThread::CurrentlyOn(ChromeThread::UI));
 
-  printing_context_.AskUserForSettings(
+  printing_context_->AskUserForSettings(
       parent_view,
       document_page_count,
       has_selection,
@@ -136,7 +138,7 @@
   DCHECK_EQ(page_number_, PageNumber::npos());
   DCHECK_EQ(document_, new_document);
   DCHECK(document_.get());
-  DCHECK(new_document->settings().Equals(printing_context_.settings()));
+  DCHECK(new_document->settings().Equals(printing_context_->settings()));
 
   if (!document_.get() || page_number_ != PageNumber::npos() ||
       document_ != new_document) {
@@ -144,7 +146,7 @@
   }
 
   PrintingContext::Result result =
-      printing_context_.NewDocument(document_->name());
+      printing_context_->NewDocument(document_->name());
   if (result != PrintingContext::OK) {
     OnFailure();
     return;
@@ -163,7 +165,7 @@
   DCHECK_EQ(message_loop(), MessageLoop::current());
   DCHECK_EQ(page_number_, PageNumber::npos());
   DCHECK(!new_document ||
-         new_document->settings().Equals(printing_context_.settings()));
+         new_document->settings().Equals(printing_context_->settings()));
 
   if (page_number_ != PageNumber::npos())
     return;
@@ -217,13 +219,13 @@
 
 void PrintJobWorker::Cancel() {
   // This is the only function that can be called from any thread.
-  printing_context_.Cancel();
+  printing_context_->Cancel();
   // Cannot touch any member variable since we don't know in which thread
   // context we run.
 }
 
 void PrintJobWorker::DismissDialog() {
-  printing_context_.DismissDialog();
+  printing_context_->DismissDialog();
 }
 
 void PrintJobWorker::OnDocumentDone() {
@@ -231,7 +233,7 @@
   DCHECK_EQ(page_number_, PageNumber::npos());
   DCHECK(document_.get());
 
-  if (printing_context_.DocumentDone() != PrintingContext::OK) {
+  if (printing_context_->DocumentDone() != PrintingContext::OK) {
     OnFailure();
     return;
   }
@@ -261,16 +263,16 @@
   owner_->message_loop()->PostTask(FROM_HERE, task);
 
   // Preprocess.
-  if (printing_context_.NewPage() != PrintingContext::OK) {
+  if (printing_context_->NewPage() != PrintingContext::OK) {
     OnFailure();
     return;
   }
 
   // Actual printing.
-  document_->RenderPrintedPage(page, printing_context_.context());
+  document_->RenderPrintedPage(page, printing_context_->context());
 
   // Postprocess.
-  if (printing_context_.PageDone() != PrintingContext::OK) {
+  if (printing_context_->PageDone() != PrintingContext::OK) {
     OnFailure();
     return;
   }
diff --git a/chrome/browser/printing/print_job_worker.h b/chrome/browser/printing/print_job_worker.h
index 69b35e4..a74cb065 100644
--- a/chrome/browser/printing/print_job_worker.h
+++ b/chrome/browser/printing/print_job_worker.h
@@ -6,6 +6,8 @@
 #define CHROME_BROWSER_PRINTING_PRINT_JOB_WORKER_H__
 #pragma once
 
+#include "base/ref_counted.h"
+#include "base/scoped_ptr.h"
 #include "base/task.h"
 #include "base/thread.h"
 #include "gfx/native_widget_types.h"
@@ -60,7 +62,7 @@
 
  protected:
   // Retrieves the context for testing only.
-  PrintingContext& printing_context() { return printing_context_; }
+  PrintingContext* printing_context() { return printing_context_.get(); }
 
  private:
   // The shared NotificationService service can only be accessed from the UI
@@ -98,7 +100,7 @@
   void GetSettingsDone(PrintingContext::Result result);
 
   // Information about the printer setting.
-  PrintingContext printing_context_;
+  scoped_ptr<PrintingContext> printing_context_;
 
   // The printed document. Only has read-only access.
   scoped_refptr<PrintedDocument> document_;
diff --git a/printing/emf_win_unittest.cc b/printing/emf_win_unittest.cc
index 4c1247b..bfd56b8 100644
--- a/printing/emf_win_unittest.cc
+++ b/printing/emf_win_unittest.cc
@@ -13,6 +13,7 @@
 #include "base/file_util.h"
 #include "base/path_service.h"
 #include "base/scoped_handle_win.h"
+#include "base/scoped_ptr.h"
 #include "printing/printing_context.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
@@ -75,8 +76,9 @@
   settings.set_device_name(L"UnitTest Printer");
 
   // Initialize it.
-  printing::PrintingContext context;
-  EXPECT_EQ(context.InitWithSettings(settings), printing::PrintingContext::OK);
+  scoped_ptr<printing::PrintingContext> context(
+      printing::PrintingContext::Create());
+  EXPECT_EQ(context->InitWithSettings(settings), printing::PrintingContext::OK);
 
   FilePath emf_file;
   EXPECT_TRUE(PathService::Get(base::DIR_SOURCE_ROOT, &emf_file));
@@ -95,10 +97,10 @@
   // 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();
+  context->NewDocument(L"EmfTest.Enumerate");
+  context->NewPage();
   // Process one at a time.
-  printing::Emf::Enumerator emf_enum(emf, context.context(),
+  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();
@@ -111,8 +113,8 @@
     EXPECT_TRUE(itr->SafePlayback(NULL)) <<
         " index: " << index << " type: " << itr->record()->iType;
   }
-  context.PageDone();
-  context.DocumentDone();
+  context->PageDone();
+  context->DocumentDone();
 }
 
 // Disabled if no "UnitTest printer" exists.
diff --git a/printing/printing.gyp b/printing/printing.gyp
index 050f830..be84caf 100644
--- a/printing/printing.gyp
+++ b/printing/printing.gyp
@@ -52,8 +52,12 @@
         'printed_page.h',
         'printed_pages_source.h',
         'printing_context.h',
+        'printing_context.cc',
+        'printing_context_cairo.h',
         'printing_context_cairo.cc',
+        'printing_context_mac.h',
         'printing_context_mac.mm',
+        'printing_context_win.h',
         'printing_context_win.cc',
         'units.cc',
         'units.h',
diff --git a/printing/printing_context.cc b/printing/printing_context.cc
new file mode 100644
index 0000000..933906d4
--- /dev/null
+++ b/printing/printing_context.cc
@@ -0,0 +1,31 @@
+// Copyright (c) 2010 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/printing_context.h"
+
+namespace printing {
+
+PrintingContext::PrintingContext()
+    : dialog_box_dismissed_(false),
+      in_print_job_(false),
+      abort_printing_(false) {
+}
+
+PrintingContext::~PrintingContext() {
+}
+
+void PrintingContext::ResetSettings() {
+  ReleaseContext();
+  settings_.Clear();
+  in_print_job_ = false;
+  dialog_box_dismissed_ = false;
+  abort_printing_ = false;
+}
+
+PrintingContext::Result PrintingContext::OnError() {
+  ResetSettings();
+  return abort_printing_ ? CANCEL : FAILED;
+}
+
+}  // namespace printing
diff --git a/printing/printing_context.h b/printing/printing_context.h
index 39e118c..6c9daaa4 100644
--- a/printing/printing_context.h
+++ b/printing/printing_context.h
@@ -5,40 +5,21 @@
 #ifndef PRINTING_PRINTING_CONTEXT_H_
 #define PRINTING_PRINTING_CONTEXT_H_
 
-#include "build/build_config.h"
-
-#if defined(OS_WIN)
-#include <ocidl.h>
-#include <commdlg.h>
-#endif
-
 #include <string>
 
 #include "base/basictypes.h"
 #include "base/callback.h"
-#if !(defined(OS_WIN) || defined(OS_MACOSX))
-// TODO(port) Remove after implementing PrintingContext::context()
-#include "base/logging.h"
-#endif
 #include "base/scoped_ptr.h"
 #include "base/string16.h"
 #include "gfx/native_widget_types.h"
 #include "printing/print_settings.h"
 
-#if defined(OS_MACOSX)
-#include "base/scoped_cftyperef.h"
-#ifdef __OBJC__
-@class NSPrintInfo;
-#else
-class NSPrintInfo;
-#endif  // __OBJC__
-#endif  // OS_MACOSX
-
 namespace printing {
 
-// Describe the user selected printing context for Windows. This includes the
-// OS-dependent UI to ask the user about the print settings. This class directly
-// talk to the printer and manages the document and pages breaks.
+// An abstraction of a printer context, implemented by objects that describe the
+// user selected printing context. This includes the OS-dependent UI to ask the
+// user about the print settings. Concrete implementations directly talk to the
+// printer and manage the document and page breaks.
 class PrintingContext {
  public:
   // Tri-state result for user behavior-dependent functions.
@@ -48,8 +29,7 @@
     FAILED,
   };
 
-  PrintingContext();
-  ~PrintingContext();
+  virtual ~PrintingContext();
 
   // Callback of AskUserForSettings, used to notify the PrintJobWorker when
   // print settings are available.
@@ -59,42 +39,17 @@
   // context with the select device settings. The result of the call is returned
   // in the callback. This is necessary for Linux, which only has an
   // asynchronous printing API.
-  void AskUserForSettings(gfx::NativeView parent_view,
-                          int max_pages,
-                          bool has_selection,
-                          PrintSettingsCallback* callback);
-
-#if defined(OS_WIN) && defined(UNIT_TEST)
-  // Sets a fake PrintDlgEx function pointer in tests.
-  void SetPrintDialog(HRESULT (__stdcall *print_dialog_func)(LPPRINTDLGEX)) {
-    print_dialog_func_ = print_dialog_func;
-  }
-#endif
-
-#if defined(OS_WIN)
-  // Allocates the HDC for a specific DEVMODE.
-  static bool AllocateContext(const std::wstring& printer_name,
-                              const DEVMODE* dev_mode,
-                              gfx::NativeDrawingContext* context);
-
-  // Retrieves the content of a GetPrinter call.
-  static void GetPrinterHelper(HANDLE printer, int level,
-                               scoped_array<uint8>* buffer);
-#endif
+  virtual void AskUserForSettings(gfx::NativeView parent_view,
+                                  int max_pages,
+                                  bool has_selection,
+                                  PrintSettingsCallback* callback) = 0;
 
   // Selects the user's default printer and format. Updates the context with the
   // default device settings.
-  Result UseDefaultSettings();
-
-  void SetUseOverlays(bool use_overlays) {
-    settings_.use_overlays = use_overlays;
-  }
+  virtual Result UseDefaultSettings() = 0;
 
   // Initializes with predefined settings.
-  Result InitWithSettings(const PrintSettings& settings);
-
-  // Reinitializes the settings to uninitialized for object reuse.
-  void ResetSettings();
+  virtual Result InitWithSettings(const PrintSettings& settings) = 0;
 
   // Does platform specific setup of the printer before the printing. Signal the
   // printer that a document is about to be spooled.
@@ -102,93 +57,56 @@
   // like IPC message processing! Some printers have side-effects on this call
   // like virtual printers that ask the user for the path of the saved document;
   // for example a PDF printer.
-  Result NewDocument(const string16& document_name);
+  virtual Result NewDocument(const string16& document_name) = 0;
 
   // Starts a new page.
-  Result NewPage();
+  virtual Result NewPage() = 0;
 
   // Closes the printed page.
-  Result PageDone();
+  virtual Result PageDone() = 0;
 
   // Closes the printing job. After this call the object is ready to start a new
   // document.
-  Result DocumentDone();
+  virtual Result DocumentDone() = 0;
 
   // Cancels printing. Can be used in a multi-threaded context. Takes effect
   // immediately.
-  void Cancel();
+  virtual void Cancel() = 0;
 
   // Dismiss the Print... dialog box if shown.
-  void DismissDialog();
+  virtual void DismissDialog() = 0;
 
-  gfx::NativeDrawingContext context() {
-#if defined(OS_WIN) || defined(OS_MACOSX)
-    return context_;
-#else
-    NOTIMPLEMENTED();
-    return NULL;
-#endif
+  // Releases the native printing context.
+  virtual void ReleaseContext() = 0;
+
+  // Returns the native context used to print.
+  virtual gfx::NativeDrawingContext context() const = 0;
+
+  // Creates an instance of this object. Implementers of this interface should
+  // implement this method to create an object of their implementation. The
+  // caller owns the returned object.
+  static PrintingContext* Create();
+
+  void set_use_overlays(bool use_overlays) {
+    settings_.use_overlays = use_overlays;
   }
 
   const PrintSettings& settings() const {
     return settings_;
   }
 
- private:
-  // Class that manages the PrintDlgEx() callbacks. This is meant to be a
-  // temporary object used during the Print... dialog display.
-  class CallbackHandler;
+ protected:
+  PrintingContext();
+
+  // Reinitializes the settings for object reuse.
+  void ResetSettings();
 
   // Does bookkeeping when an error occurs.
   PrintingContext::Result OnError();
 
-#if defined(OS_WIN)
-  // Used in response to the user canceling the printing.
-  static BOOL CALLBACK AbortProc(HDC hdc, int nCode);
-
-  // Reads the settings from the selected device context. Updates settings_ and
-  // its margins.
-  bool InitializeSettings(const DEVMODE& dev_mode,
-                          const std::wstring& new_device_name,
-                          const PRINTPAGERANGE* ranges,
-                          int number_ranges,
-                          bool selection_only);
-
-  // Retrieves the printer's default low-level settings. On Windows, context_ is
-  // allocated with this call.
-  bool GetPrinterSettings(HANDLE printer,
-                          const std::wstring& device_name);
-
-  // Parses the result of a PRINTDLGEX result.
-  Result ParseDialogResultEx(const PRINTDLGEX& dialog_options);
-  Result ParseDialogResult(const PRINTDLG& dialog_options);
-#elif defined(OS_MACOSX)
-  // Read the settings from the given NSPrintInfo (and cache it for later use).
-  void ParsePrintInfo(NSPrintInfo* print_info);
-#endif
-
-  // On Windows, the selected printer context.
-  // On Mac, the current page's context; only valid between NewPage and PageDone
-  // call pairs.
-  gfx::NativeDrawingContext context_;
-
-#if defined(OS_MACOSX)
-  // The native print info object.
-  NSPrintInfo* print_info_;
-#endif
-
   // Complete print context settings.
   PrintSettings settings_;
 
-#if defined(OS_WIN)
-  // The dialog box for the time it is shown.
-  volatile HWND dialog_box_;
-
-  // Function pointer that defaults to PrintDlgEx. It can be changed using
-  // SetPrintDialog() in tests.
-  HRESULT (__stdcall *print_dialog_func_)(LPPRINTDLGEX);
-#endif
-
   // The dialog box has been dismissed.
   volatile bool dialog_box_dismissed_;
 
diff --git a/printing/printing_context_cairo.cc b/printing/printing_context_cairo.cc
index 86de49c..0f5a500 100644
--- a/printing/printing_context_cairo.cc
+++ b/printing/printing_context_cairo.cc
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "printing/printing_context.h"
+#include "printing/printing_context_cairo.h"
 
 #include <gtk/gtk.h>
 #include <gtk/gtkprintunixdialog.h>
@@ -11,18 +11,19 @@
 
 namespace printing {
 
-PrintingContext::PrintingContext()
-    :
-      dialog_box_dismissed_(false),
-      in_print_job_(false),
-      abort_printing_(false) {
+// static
+PrintingContext* PrintingContext::Create() {
+  return static_cast<PrintingContext*>(new PrintingContextCairo);
 }
 
-PrintingContext::~PrintingContext() {
-  ResetSettings();
+PrintingContextCairo::PrintingContextCairo() : PrintingContext() {
 }
 
-void PrintingContext::AskUserForSettings(
+PrintingContextCairo::~PrintingContextCairo() {
+  ReleaseContext();
+}
+
+void PrintingContextCairo::AskUserForSettings(
     gfx::NativeView parent_view,
     int max_pages,
     bool has_selection,
@@ -31,7 +32,7 @@
   callback->Run(OK);
 }
 
-PrintingContext::Result PrintingContext::UseDefaultSettings() {
+PrintingContext::Result PrintingContextCairo::UseDefaultSettings() {
   DCHECK(!in_print_job_);
 
   ResetSettings();
@@ -52,7 +53,7 @@
   return OK;
 }
 
-PrintingContext::Result PrintingContext::InitWithSettings(
+PrintingContext::Result PrintingContextCairo::InitWithSettings(
     const PrintSettings& settings) {
   DCHECK(!in_print_job_);
   settings_ = settings;
@@ -62,13 +63,7 @@
   return FAILED;
 }
 
-void PrintingContext::ResetSettings() {
-  dialog_box_dismissed_ = false;
-  abort_printing_ = false;
-  in_print_job_ = false;
-}
-
-PrintingContext::Result PrintingContext::NewDocument(
+PrintingContext::Result PrintingContextCairo::NewDocument(
     const string16& document_name) {
   DCHECK(!in_print_job_);
 
@@ -77,7 +72,7 @@
   return FAILED;
 }
 
-PrintingContext::Result PrintingContext::NewPage() {
+PrintingContext::Result PrintingContextCairo::NewPage() {
   if (abort_printing_)
     return CANCEL;
   DCHECK(in_print_job_);
@@ -87,7 +82,7 @@
   return FAILED;
 }
 
-PrintingContext::Result PrintingContext::PageDone() {
+PrintingContext::Result PrintingContextCairo::PageDone() {
   if (abort_printing_)
     return CANCEL;
   DCHECK(in_print_job_);
@@ -97,7 +92,7 @@
   return FAILED;
 }
 
-PrintingContext::Result PrintingContext::DocumentDone() {
+PrintingContext::Result PrintingContextCairo::DocumentDone() {
   if (abort_printing_)
     return CANCEL;
   DCHECK(in_print_job_);
@@ -108,20 +103,23 @@
   return FAILED;
 }
 
-void PrintingContext::Cancel() {
+void PrintingContextCairo::Cancel() {
   abort_printing_ = true;
   in_print_job_ = false;
 
   NOTIMPLEMENTED();
 }
 
-void PrintingContext::DismissDialog() {
+void PrintingContextCairo::DismissDialog() {
   NOTIMPLEMENTED();
 }
 
-PrintingContext::Result PrintingContext::OnError() {
-  ResetSettings();
-  return abort_printing_ ? CANCEL : FAILED;
+void PrintingContextCairo::ReleaseContext() {
+  // Nothing to do yet.
+}
+
+gfx::NativeDrawingContext PrintingContextCairo::context() const {
+  return NULL;
 }
 
 }  // namespace printing
diff --git a/printing/printing_context_cairo.h b/printing/printing_context_cairo.h
new file mode 100644
index 0000000..d4c98ca
--- /dev/null
+++ b/printing/printing_context_cairo.h
@@ -0,0 +1,39 @@
+// Copyright (c) 2010 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_PRINTING_CONTEXT_CAIRO_H_
+#define PRINTING_PRINTING_CONTEXT_CAIRO_H_
+
+#include "printing/printing_context.h"
+
+namespace printing {
+
+class PrintingContextCairo : public PrintingContext {
+ public:
+  PrintingContextCairo();
+  ~PrintingContextCairo();
+
+  // PrintingContext implementation.
+  virtual void AskUserForSettings(gfx::NativeView parent_view,
+                                  int max_pages,
+                                  bool has_selection,
+                                  PrintSettingsCallback* callback);
+  virtual Result UseDefaultSettings();
+  virtual Result InitWithSettings(const PrintSettings& settings);
+  virtual Result NewDocument(const string16& document_name);
+  virtual Result NewPage();
+  virtual Result PageDone();
+  virtual Result DocumentDone();
+  virtual void Cancel();
+  virtual void DismissDialog();
+  virtual void ReleaseContext();
+  virtual gfx::NativeDrawingContext context() const;
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(PrintingContextCairo);
+};
+
+}  // namespace printing
+
+#endif  // PRINTING_PRINTING_CONTEXT_CAIRO_H_
diff --git a/printing/printing_context_mac.h b/printing/printing_context_mac.h
new file mode 100644
index 0000000..f94fae2
--- /dev/null
+++ b/printing/printing_context_mac.h
@@ -0,0 +1,55 @@
+// Copyright (c) 2010 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_PRINTING_CONTEXT_MAC_H_
+#define PRINTING_PRINTING_CONTEXT_MAC_H_
+
+#include "printing/printing_context.h"
+
+#ifdef __OBJC__
+@class NSPrintInfo;
+#else
+class NSPrintInfo;
+#endif  // __OBJC__
+
+namespace printing {
+
+class PrintingContextMac : public PrintingContext {
+ public:
+  PrintingContextMac();
+  ~PrintingContextMac();
+
+  // PrintingContext implementation.
+  virtual void AskUserForSettings(gfx::NativeView parent_view,
+                                  int max_pages,
+                                  bool has_selection,
+                                  PrintSettingsCallback* callback);
+  virtual Result UseDefaultSettings();
+  virtual Result InitWithSettings(const PrintSettings& settings);
+  virtual Result NewDocument(const string16& document_name);
+  virtual Result NewPage();
+  virtual Result PageDone();
+  virtual Result DocumentDone();
+  virtual void Cancel();
+  virtual void DismissDialog();
+  virtual void ReleaseContext();
+  virtual gfx::NativeDrawingContext context() const;
+
+ private:
+  // Read the settings from the given NSPrintInfo (and cache it for later use).
+  void ParsePrintInfo(NSPrintInfo* print_info);
+
+  // The native print info object.
+  NSPrintInfo* print_info_;
+
+  // The current page's context; only valid between NewPage and PageDone call
+  // pairs.
+  CGContext* context_;
+
+  DISALLOW_COPY_AND_ASSIGN(PrintingContextMac);
+};
+
+}  // namespace printing
+
+#endif  // PRINTING_PRINTING_CONTEXT_MAC_H_
diff --git a/printing/printing_context_mac.mm b/printing/printing_context_mac.mm
index 828a7f4..50431ae6 100644
--- a/printing/printing_context_mac.mm
+++ b/printing/printing_context_mac.mm
@@ -2,33 +2,36 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "printing/printing_context.h"
+#include "printing/printing_context_mac.h"
 
 #import <ApplicationServices/ApplicationServices.h>
 #import <AppKit/AppKit.h>
 
 #include "base/logging.h"
+#include "base/scoped_cftyperef.h"
 #include "base/sys_string_conversions.h"
 
 namespace printing {
 
-PrintingContext::PrintingContext()
-    : context_(NULL),
-      print_info_(nil),
-      dialog_box_dismissed_(false),
-      in_print_job_(false),
-      abort_printing_(false) {
+// static
+PrintingContext* PrintingContext::Create() {
+  return static_cast<PrintingContext*>(new PrintingContextMac);
 }
 
-PrintingContext::~PrintingContext() {
-  ResetSettings();
+PrintingContextMac::PrintingContextMac()
+    : PrintingContext(),
+      print_info_(NULL),
+      context_(NULL) {
 }
 
+PrintingContextMac::~PrintingContextMac() {
+  ReleaseContext();
+}
 
-void PrintingContext::AskUserForSettings(gfx::NativeView parent_view,
-                                         int max_pages,
-                                         bool has_selection,
-                                         PrintSettingsCallback* callback) {
+void PrintingContextMac::AskUserForSettings(gfx::NativeView parent_view,
+                                            int max_pages,
+                                            bool has_selection,
+                                            PrintSettingsCallback* callback) {
   DCHECK([NSThread isMainThread]);
 
   // We deliberately don't feed max_pages into the dialog, because setting
@@ -68,7 +71,7 @@
   }
 }
 
-PrintingContext::Result PrintingContext::UseDefaultSettings() {
+PrintingContext::Result PrintingContextMac::UseDefaultSettings() {
   DCHECK(!in_print_job_);
 
   ParsePrintInfo([NSPrintInfo sharedPrintInfo]);
@@ -76,7 +79,7 @@
   return OK;
 }
 
-void PrintingContext::ParsePrintInfo(NSPrintInfo* print_info) {
+void PrintingContextMac::ParsePrintInfo(NSPrintInfo* print_info) {
   ResetSettings();
   print_info_ = [print_info retain];
   PageRanges page_ranges;
@@ -97,7 +100,7 @@
   settings_.Init(printer, page_format, page_ranges, false);
 }
 
-PrintingContext::Result PrintingContext::InitWithSettings(
+PrintingContext::Result PrintingContextMac::InitWithSettings(
     const PrintSettings& settings) {
   DCHECK(!in_print_job_);
   settings_ = settings;
@@ -107,17 +110,7 @@
   return FAILED;
 }
 
-void PrintingContext::ResetSettings() {
-  [print_info_ autorelease];
-  print_info_ = nil;
-  settings_.Clear();
-  dialog_box_dismissed_ = false;
-  abort_printing_ = false;
-  in_print_job_ = false;
-  context_ = NULL;
-}
-
-PrintingContext::Result PrintingContext::NewDocument(
+PrintingContext::Result PrintingContextMac::NewDocument(
     const string16& document_name) {
   DCHECK(!in_print_job_);
 
@@ -143,7 +136,7 @@
   return OK;
 }
 
-PrintingContext::Result PrintingContext::NewPage() {
+PrintingContext::Result PrintingContextMac::NewPage() {
   if (abort_printing_)
     return CANCEL;
   DCHECK(in_print_job_);
@@ -164,7 +157,7 @@
   return OK;
 }
 
-PrintingContext::Result PrintingContext::PageDone() {
+PrintingContext::Result PrintingContextMac::PageDone() {
   if (abort_printing_)
     return CANCEL;
   DCHECK(in_print_job_);
@@ -180,7 +173,7 @@
   return OK;
 }
 
-PrintingContext::Result PrintingContext::DocumentDone() {
+PrintingContext::Result PrintingContextMac::DocumentDone() {
   if (abort_printing_)
     return CANCEL;
   DCHECK(in_print_job_);
@@ -195,7 +188,7 @@
   return OK;
 }
 
-void PrintingContext::Cancel() {
+void PrintingContextMac::Cancel() {
   abort_printing_ = true;
   in_print_job_ = false;
   context_ = NULL;
@@ -205,13 +198,20 @@
   PMSessionEndPageNoDialog(print_session);
 }
 
-void PrintingContext::DismissDialog() {
+void PrintingContextMac::DismissDialog() {
   NOTIMPLEMENTED();
 }
 
-PrintingContext::Result PrintingContext::OnError() {
-  ResetSettings();
-  return abort_printing_ ? CANCEL : FAILED;
+void PrintingContextMac::ReleaseContext() {
+  if (print_info_) {
+    [print_info_ autorelease];
+    print_info_ = nil;
+    context_ = NULL;
+  }
+}
+
+gfx::NativeDrawingContext PrintingContextMac::context() const {
+  return context_;
 }
 
 }  // namespace printing
diff --git a/printing/printing_context_win.cc b/printing/printing_context_win.cc
index 038f5d3d..9d855cd 100644
--- a/printing/printing_context_win.cc
+++ b/printing/printing_context_win.cc
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "printing/printing_context.h"
+#include "printing/printing_context_win.h"
 
 #include <winspool.h>
 
@@ -19,10 +19,10 @@
 
 namespace printing {
 
-class PrintingContext::CallbackHandler : public IPrintDialogCallback,
-                                         public IObjectWithSite {
+class PrintingContextWin::CallbackHandler : public IPrintDialogCallback,
+                                            public IObjectWithSite {
  public:
-  CallbackHandler(PrintingContext& owner, HWND owner_hwnd)
+  CallbackHandler(PrintingContextWin& owner, HWND owner_hwnd)
       : owner_(owner),
         owner_hwnd_(owner_hwnd),
         services_(NULL) {
@@ -113,30 +113,33 @@
   }
 
  private:
-  PrintingContext& owner_;
+  PrintingContextWin& owner_;
   HWND owner_hwnd_;
   IPrintDialogServices* services_;
 
   DISALLOW_COPY_AND_ASSIGN(CallbackHandler);
 };
 
-PrintingContext::PrintingContext()
-    : context_(NULL),
+// static
+PrintingContext* PrintingContext::Create() {
+  return static_cast<PrintingContext*>(new PrintingContextWin);
+}
+
+PrintingContextWin::PrintingContextWin()
+    : PrintingContext(),
+      context_(NULL),
       dialog_box_(NULL),
-      dialog_box_dismissed_(false),
-      in_print_job_(false),
-      abort_printing_(false),
       print_dialog_func_(&PrintDlgEx) {
 }
 
-PrintingContext::~PrintingContext() {
-  ResetSettings();
+PrintingContextWin::~PrintingContextWin() {
+  ReleaseContext();
 }
 
-void PrintingContext::AskUserForSettings(HWND view,
-                                         int max_pages,
-                                         bool has_selection,
-                                         PrintSettingsCallback* callback) {
+void PrintingContextWin::AskUserForSettings(HWND view,
+                                            int max_pages,
+                                            bool has_selection,
+                                            PrintSettingsCallback* callback) {
   DCHECK(!in_print_job_);
   dialog_box_dismissed_ = false;
 
@@ -194,7 +197,7 @@
   callback->Run(ParseDialogResultEx(dialog_options));
 }
 
-PrintingContext::Result PrintingContext::UseDefaultSettings() {
+PrintingContext::Result PrintingContextWin::UseDefaultSettings() {
   DCHECK(!in_print_job_);
 
   PRINTDLG dialog_options = { sizeof(PRINTDLG) };
@@ -206,7 +209,7 @@
   return ParseDialogResult(dialog_options);
 }
 
-PrintingContext::Result PrintingContext::InitWithSettings(
+PrintingContext::Result PrintingContextWin::InitWithSettings(
     const PrintSettings& settings) {
   DCHECK(!in_print_job_);
   settings_ = settings;
@@ -230,16 +233,7 @@
   return status;
 }
 
-void PrintingContext::ResetSettings() {
-  if (context_ != NULL) {
-    DeleteDC(context_);
-    context_ = NULL;
-  }
-  settings_.Clear();
-  in_print_job_ = false;
-}
-
-PrintingContext::Result PrintingContext::NewDocument(
+PrintingContext::Result PrintingContextWin::NewDocument(
     const string16& document_name) {
   DCHECK(!in_print_job_);
   if (!context_)
@@ -289,7 +283,7 @@
   return OK;
 }
 
-PrintingContext::Result PrintingContext::NewPage() {
+PrintingContext::Result PrintingContextWin::NewPage() {
   if (abort_printing_)
     return CANCEL;
 
@@ -303,7 +297,7 @@
   return OK;
 }
 
-PrintingContext::Result PrintingContext::PageDone() {
+PrintingContext::Result PrintingContextWin::PageDone() {
   if (abort_printing_)
     return CANCEL;
   DCHECK(in_print_job_);
@@ -313,7 +307,7 @@
   return OK;
 }
 
-PrintingContext::Result PrintingContext::DocumentDone() {
+PrintingContext::Result PrintingContextWin::DocumentDone() {
   if (abort_printing_)
     return CANCEL;
   DCHECK(in_print_job_);
@@ -327,7 +321,7 @@
   return OK;
 }
 
-void PrintingContext::Cancel() {
+void PrintingContextWin::Cancel() {
   abort_printing_ = true;
   in_print_job_ = false;
   if (context_)
@@ -335,21 +329,26 @@
   DismissDialog();
 }
 
-void PrintingContext::DismissDialog() {
+void PrintingContextWin::DismissDialog() {
   if (dialog_box_) {
     DestroyWindow(dialog_box_);
     dialog_box_dismissed_ = true;
   }
 }
 
-PrintingContext::Result PrintingContext::OnError() {
-  // This will close context_ and clear settings_.
-  ResetSettings();
-  return abort_printing_ ? CANCEL : FAILED;
+void PrintingContextWin::ReleaseContext() {
+  if (context_) {
+    DeleteDC(context_);
+    context_ = NULL;
+  }
+}
+
+gfx::NativeDrawingContext PrintingContextWin::context() const {
+  return context_;
 }
 
 // static
-BOOL PrintingContext::AbortProc(HDC hdc, int nCode) {
+BOOL PrintingContextWin::AbortProc(HDC hdc, int nCode) {
   if (nCode) {
     // TODO(maruel):  Need a way to find the right instance to set. Should
     // leverage PrintJobManager here?
@@ -358,11 +357,11 @@
   return true;
 }
 
-bool PrintingContext::InitializeSettings(const DEVMODE& dev_mode,
-                                         const std::wstring& new_device_name,
-                                         const PRINTPAGERANGE* ranges,
-                                         int number_ranges,
-                                         bool selection_only) {
+bool PrintingContextWin::InitializeSettings(const DEVMODE& dev_mode,
+                                            const std::wstring& new_device_name,
+                                            const PRINTPAGERANGE* ranges,
+                                            int number_ranges,
+                                            bool selection_only) {
   skia::PlatformDevice::InitializeDC(context_);
   DCHECK(GetDeviceCaps(context_, CLIPCAPS));
   DCHECK(GetDeviceCaps(context_, RASTERCAPS) & RC_STRETCHDIB);
@@ -402,8 +401,8 @@
   return true;
 }
 
-bool PrintingContext::GetPrinterSettings(HANDLE printer,
-                                         const std::wstring& device_name) {
+bool PrintingContextWin::GetPrinterSettings(HANDLE printer,
+                                            const std::wstring& device_name) {
   DCHECK(!in_print_job_);
   scoped_array<uint8> buffer;
 
@@ -456,15 +455,15 @@
 }
 
 // static
-bool PrintingContext::AllocateContext(const std::wstring& printer_name,
-                                      const DEVMODE* dev_mode,
-                                      gfx::NativeDrawingContext* context) {
+bool PrintingContextWin::AllocateContext(const std::wstring& printer_name,
+                                         const DEVMODE* dev_mode,
+                                         gfx::NativeDrawingContext* context) {
   *context = CreateDC(L"WINSPOOL", printer_name.c_str(), NULL, dev_mode);
   DCHECK(*context);
   return *context != NULL;
 }
 
-PrintingContext::Result PrintingContext::ParseDialogResultEx(
+PrintingContext::Result PrintingContextWin::ParseDialogResultEx(
     const PRINTDLGEX& dialog_options) {
   // If the user clicked OK or Apply then Cancel, but not only Cancel.
   if (dialog_options.dwResultAction != PD_RESULT_CANCEL) {
@@ -543,7 +542,7 @@
   }
 }
 
-PrintingContext::Result PrintingContext::ParseDialogResult(
+PrintingContext::Result PrintingContextWin::ParseDialogResult(
     const PRINTDLG& dialog_options) {
   // If the user clicked OK or Apply then Cancel, but not only Cancel.
   // Start fresh.
@@ -594,8 +593,8 @@
 }
 
 // static
-void PrintingContext::GetPrinterHelper(HANDLE printer, int level,
-                                       scoped_array<uint8>* buffer) {
+void PrintingContextWin::GetPrinterHelper(HANDLE printer, int level,
+                                          scoped_array<uint8>* buffer) {
   DWORD buf_size = 0;
   GetPrinter(printer, level, NULL, 0, &buf_size);
   if (buf_size) {
diff --git a/printing/printing_context_win.h b/printing/printing_context_win.h
new file mode 100644
index 0000000..90fc738
--- /dev/null
+++ b/printing/printing_context_win.h
@@ -0,0 +1,97 @@
+// Copyright (c) 2010 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_PRINTING_CONTEXT_WIN_H_
+#define PRINTING_PRINTING_CONTEXT_WIN_H_
+
+#include <ocidl.h>
+#include <commdlg.h>
+
+#include <string>
+
+#include "base/scoped_ptr.h"
+#include "build/build_config.h"
+#include "gfx/native_widget_types.h"
+#include "printing/printing_context.h"
+
+namespace printing {
+
+class PrintingContextWin : public PrintingContext {
+ public:
+  PrintingContextWin();
+  ~PrintingContextWin();
+
+  // PrintingContext implementation.
+  virtual void AskUserForSettings(gfx::NativeView parent_view,
+                                  int max_pages,
+                                  bool has_selection,
+                                  PrintSettingsCallback* callback);
+  virtual Result UseDefaultSettings();
+  virtual Result InitWithSettings(const PrintSettings& settings);
+  virtual Result NewDocument(const string16& document_name);
+  virtual Result NewPage();
+  virtual Result PageDone();
+  virtual Result DocumentDone();
+  virtual void Cancel();
+  virtual void DismissDialog();
+  virtual void ReleaseContext();
+  virtual gfx::NativeDrawingContext context() const;
+
+#if defined(UNIT_TEST)
+  // Sets a fake PrintDlgEx function pointer in tests.
+  void SetPrintDialog(HRESULT (__stdcall *print_dialog_func)(LPPRINTDLGEX)) {
+    print_dialog_func_ = print_dialog_func;
+  }
+#endif  // defined(UNIT_TEST)
+
+  // Allocates the HDC for a specific DEVMODE.
+  static bool AllocateContext(const std::wstring& printer_name,
+                              const DEVMODE* dev_mode,
+                              gfx::NativeDrawingContext* context);
+
+  // Retrieves the content of a GetPrinter call.
+  static void GetPrinterHelper(HANDLE printer, int level,
+                               scoped_array<uint8>* buffer);
+
+ private:
+  // Class that manages the PrintDlgEx() callbacks. This is meant to be a
+  // temporary object used during the Print... dialog display.
+  class CallbackHandler;
+
+  // Used in response to the user canceling the printing.
+  static BOOL CALLBACK AbortProc(HDC hdc, int nCode);
+
+  // Reads the settings from the selected device context. Updates settings_ and
+  // its margins.
+  bool InitializeSettings(const DEVMODE& dev_mode,
+                          const std::wstring& new_device_name,
+                          const PRINTPAGERANGE* ranges,
+                          int number_ranges,
+                          bool selection_only);
+
+  // Retrieves the printer's default low-level settings. On Windows, context_ is
+  // allocated with this call.
+  bool GetPrinterSettings(HANDLE printer,
+                          const std::wstring& device_name);
+
+  // Parses the result of a PRINTDLGEX result.
+  Result ParseDialogResultEx(const PRINTDLGEX& dialog_options);
+  Result ParseDialogResult(const PRINTDLG& dialog_options);
+
+  // The selected printer context.
+  HDC context_;
+
+  // The dialog box for the time it is shown.
+  volatile HWND dialog_box_;
+
+  // Function pointer that defaults to PrintDlgEx. It can be changed using
+  // SetPrintDialog() in tests.
+  HRESULT (__stdcall *print_dialog_func_)(LPPRINTDLGEX);
+
+  DISALLOW_COPY_AND_ASSIGN(PrintingContextWin);
+};
+
+}  // namespace printing
+
+#endif  // PRINTING_PRINTING_CONTEXT_WIN_H_
diff --git a/printing/printing_context_win_unittest.cc b/printing/printing_context_win_unittest.cc
index 625af54..6e194d1a 100644
--- a/printing/printing_context_win_unittest.cc
+++ b/printing/printing_context_win_unittest.cc
@@ -2,9 +2,15 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "printing/printing_context.h"
+#include <ocidl.h>
+#include <commdlg.h>
 
+#include <string>
+
+#include "base/scoped_ptr.h"
 #include "printing/printing_test.h"
+#include "printing/printing_context.h"
+#include "printing/printing_context_win.h"
 #include "printing/print_settings.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
@@ -46,7 +52,7 @@
   DEVMODE* dev_mode = NULL;
   PRINTER_INFO_2* info_2 = NULL;
 
-  printing::PrintingContext::GetPrinterHelper(printer, 2, &buffer);
+  printing::PrintingContextWin::GetPrinterHelper(printer, 2, &buffer);
   if (buffer.get()) {
     info_2 = reinterpret_cast<PRINTER_INFO_2*>(buffer.get());
     if (info_2->pDevMode != NULL)
@@ -55,7 +61,7 @@
   if (!dev_mode)
     return E_FAIL;
 
-  if (!printing::PrintingContext::AllocateContext(printer_name, dev_mode,
+  if (!printing::PrintingContextWin::AllocateContext(printer_name, dev_mode,
       &lppd->hDC)) {
     return E_FAIL;
   }
@@ -102,18 +108,19 @@
 
   settings.set_device_name(GetDefaultPrinter());
   // Initialize it.
-  printing::PrintingContext context;
-  EXPECT_EQ(printing::PrintingContext::OK, context.InitWithSettings(settings));
+  scoped_ptr<printing::PrintingContext> context(
+      printing::PrintingContext::Create());
+  EXPECT_EQ(printing::PrintingContext::OK, context->InitWithSettings(settings));
 
   // The print may lie to use and may not support world transformation.
   // Verify right now.
   XFORM random_matrix = { 1, 0.1f, 0, 1.5f, 0, 1 };
-  EXPECT_TRUE(SetWorldTransform(context.context(), &random_matrix));
-  EXPECT_TRUE(ModifyWorldTransform(context.context(), NULL, MWT_IDENTITY));
+  EXPECT_TRUE(SetWorldTransform(context->context(), &random_matrix));
+  EXPECT_TRUE(ModifyWorldTransform(context->context(), NULL, MWT_IDENTITY));
 }
 
 TEST_F(PrintingContextTest, PrintAll) {
-  printing::PrintingContext context;
+  printing::PrintingContextWin context;
   context.SetPrintDialog(&PrintDlgExMock);
   context.AskUserForSettings(
       NULL,
diff --git a/printing/printing_test.h b/printing/printing_test.h
index 3237813..da5d86dc 100644
--- a/printing/printing_test.h
+++ b/printing/printing_test.h
@@ -8,6 +8,10 @@
 #include <windows.h>
 #include <winspool.h>
 
+#include <string>
+
+#include "base/basictypes.h"
+
 // Disable the whole test case when executing on a computer that has no printer
 // installed.
 // Note: Parent should be testing::Test or UITest.