0

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
This commit is contained in:
jhawkins@chromium.org
2010-10-06 22:21:17 +00:00
parent c27a5ed3f2
commit 51e8d9357b
15 changed files with 421 additions and 263 deletions

@ -44,8 +44,8 @@ class TestOwner : public printing::PrintJobWorkerOwner {
// 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() {

@ -52,6 +52,8 @@ PrintJobWorker::PrintJobWorker(PrintJobWorkerOwner* owner)
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 @@ void PrintJobWorker::GetSettings(bool ask_user_for_settings,
// 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 @@ void PrintJobWorker::GetSettings(bool ask_user_for_settings,
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 @@ void PrintJobWorker::GetSettingsDone(PrintingContext::Result result) {
owner_->message_loop()->PostTask(FROM_HERE, NewRunnableMethod(
owner_,
&PrintJobWorkerOwner::GetSettingsDone,
printing_context_.settings(),
printing_context_->settings(),
result));
}
@ -118,7 +120,7 @@ void PrintJobWorker::GetSettingsWithUI(gfx::NativeView parent_view,
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 @@ void PrintJobWorker::StartPrinting(PrintedDocument* new_document) {
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 @@ void PrintJobWorker::StartPrinting(PrintedDocument* new_document) {
}
PrintingContext::Result result =
printing_context_.NewDocument(document_->name());
printing_context_->NewDocument(document_->name());
if (result != PrintingContext::OK) {
OnFailure();
return;
@ -163,7 +165,7 @@ void PrintJobWorker::OnDocumentChanged(PrintedDocument* new_document) {
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::OnNewPage() {
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 @@ void PrintJobWorker::OnDocumentDone() {
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 @@ void PrintJobWorker::SpoolPage(PrintedPage& page) {
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;
}

@ -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 @@ class PrintJobWorker : public base::Thread {
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 @@ class PrintJobWorker : public base::Thread {
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_;

@ -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 @@ TEST_F(EmfPrintingTest, Enumerate) {
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 @@ TEST_F(EmfPrintingTest, Enumerate) {
// 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 @@ TEST_F(EmfPrintingTest, Enumerate) {
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.

@ -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',

@ -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

@ -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 @@ class PrintingContext {
FAILED,
};
PrintingContext();
~PrintingContext();
virtual ~PrintingContext();
// Callback of AskUserForSettings, used to notify the PrintJobWorker when
// print settings are available.
@ -59,42 +39,17 @@ class PrintingContext {
// 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 @@ class PrintingContext {
// 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_;

@ -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 @@ void PrintingContext::AskUserForSettings(
callback->Run(OK);
}
PrintingContext::Result PrintingContext::UseDefaultSettings() {
PrintingContext::Result PrintingContextCairo::UseDefaultSettings() {
DCHECK(!in_print_job_);
ResetSettings();
@ -52,7 +53,7 @@ PrintingContext::Result PrintingContext::UseDefaultSettings() {
return OK;
}
PrintingContext::Result PrintingContext::InitWithSettings(
PrintingContext::Result PrintingContextCairo::InitWithSettings(
const PrintSettings& settings) {
DCHECK(!in_print_job_);
settings_ = settings;
@ -62,13 +63,7 @@ PrintingContext::Result PrintingContext::InitWithSettings(
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 @@ PrintingContext::Result PrintingContext::NewDocument(
return FAILED;
}
PrintingContext::Result PrintingContext::NewPage() {
PrintingContext::Result PrintingContextCairo::NewPage() {
if (abort_printing_)
return CANCEL;
DCHECK(in_print_job_);
@ -87,7 +82,7 @@ PrintingContext::Result PrintingContext::NewPage() {
return FAILED;
}
PrintingContext::Result PrintingContext::PageDone() {
PrintingContext::Result PrintingContextCairo::PageDone() {
if (abort_printing_)
return CANCEL;
DCHECK(in_print_job_);
@ -97,7 +92,7 @@ PrintingContext::Result PrintingContext::PageDone() {
return FAILED;
}
PrintingContext::Result PrintingContext::DocumentDone() {
PrintingContext::Result PrintingContextCairo::DocumentDone() {
if (abort_printing_)
return CANCEL;
DCHECK(in_print_job_);
@ -108,20 +103,23 @@ PrintingContext::Result PrintingContext::DocumentDone() {
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

@ -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_

@ -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_

@ -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 @@ void PrintingContext::AskUserForSettings(gfx::NativeView parent_view,
}
}
PrintingContext::Result PrintingContext::UseDefaultSettings() {
PrintingContext::Result PrintingContextMac::UseDefaultSettings() {
DCHECK(!in_print_job_);
ParsePrintInfo([NSPrintInfo sharedPrintInfo]);
@ -76,7 +79,7 @@ PrintingContext::Result PrintingContext::UseDefaultSettings() {
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 @@ void PrintingContext::ParsePrintInfo(NSPrintInfo* print_info) {
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 @@ PrintingContext::Result PrintingContext::InitWithSettings(
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 @@ PrintingContext::Result PrintingContext::NewDocument(
return OK;
}
PrintingContext::Result PrintingContext::NewPage() {
PrintingContext::Result PrintingContextMac::NewPage() {
if (abort_printing_)
return CANCEL;
DCHECK(in_print_job_);
@ -164,7 +157,7 @@ PrintingContext::Result PrintingContext::NewPage() {
return OK;
}
PrintingContext::Result PrintingContext::PageDone() {
PrintingContext::Result PrintingContextMac::PageDone() {
if (abort_printing_)
return CANCEL;
DCHECK(in_print_job_);
@ -180,7 +173,7 @@ PrintingContext::Result PrintingContext::PageDone() {
return OK;
}
PrintingContext::Result PrintingContext::DocumentDone() {
PrintingContext::Result PrintingContextMac::DocumentDone() {
if (abort_printing_)
return CANCEL;
DCHECK(in_print_job_);
@ -195,7 +188,7 @@ PrintingContext::Result PrintingContext::DocumentDone() {
return OK;
}
void PrintingContext::Cancel() {
void PrintingContextMac::Cancel() {
abort_printing_ = true;
in_print_job_ = false;
context_ = NULL;
@ -205,13 +198,20 @@ void PrintingContext::Cancel() {
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

@ -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 @@ using base::Time;
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 @@ class PrintingContext::CallbackHandler : public IPrintDialogCallback,
}
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 @@ void PrintingContext::AskUserForSettings(HWND view,
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 @@ PrintingContext::Result PrintingContext::UseDefaultSettings() {
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 @@ PrintingContext::Result PrintingContext::InitWithSettings(
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 @@ PrintingContext::Result PrintingContext::NewDocument(
return OK;
}
PrintingContext::Result PrintingContext::NewPage() {
PrintingContext::Result PrintingContextWin::NewPage() {
if (abort_printing_)
return CANCEL;
@ -303,7 +297,7 @@ PrintingContext::Result PrintingContext::NewPage() {
return OK;
}
PrintingContext::Result PrintingContext::PageDone() {
PrintingContext::Result PrintingContextWin::PageDone() {
if (abort_printing_)
return CANCEL;
DCHECK(in_print_job_);
@ -313,7 +307,7 @@ PrintingContext::Result PrintingContext::PageDone() {
return OK;
}
PrintingContext::Result PrintingContext::DocumentDone() {
PrintingContext::Result PrintingContextWin::DocumentDone() {
if (abort_printing_)
return CANCEL;
DCHECK(in_print_job_);
@ -327,7 +321,7 @@ PrintingContext::Result PrintingContext::DocumentDone() {
return OK;
}
void PrintingContext::Cancel() {
void PrintingContextWin::Cancel() {
abort_printing_ = true;
in_print_job_ = false;
if (context_)
@ -335,21 +329,26 @@ void PrintingContext::Cancel() {
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 @@ BOOL PrintingContext::AbortProc(HDC hdc, int nCode) {
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 @@ bool PrintingContext::InitializeSettings(const DEVMODE& dev_mode,
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 @@ bool PrintingContext::GetPrinterSettings(HANDLE printer,
}
// 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::ParseDialogResultEx(
}
}
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 @@ PrintingContext::Result PrintingContext::ParseDialogResult(
}
// 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) {

@ -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_

@ -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 @@ HRESULT WINAPI PrintDlgExMock(LPPRINTDLGEX lppd) {
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 @@ HRESULT WINAPI PrintDlgExMock(LPPRINTDLGEX lppd) {
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 @@ TEST_F(PrintingContextTest, Base) {
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,

@ -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.