summaryrefslogtreecommitdiffstats
path: root/printing
diff options
context:
space:
mode:
authorstuartmorgan@chromium.org <stuartmorgan@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2009-10-13 18:46:21 +0000
committerstuartmorgan@chromium.org <stuartmorgan@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2009-10-13 18:46:21 +0000
commitb75dca87f3ff3ee3ab003960276ec7bb49d4c734 (patch)
tree8026f1f38f82a5d7c922ba5245e38a5ecf3a61d8 /printing
parent7ff3f63b8c66408a382adc88458a6e70038cad8d (diff)
downloadchromium_src-b75dca87f3ff3ee3ab003960276ec7bb49d4c734.zip
chromium_src-b75dca87f3ff3ee3ab003960276ec7bb49d4c734.tar.gz
chromium_src-b75dca87f3ff3ee3ab003960276ec7bb49d4c734.tar.bz2
Implement the basic OS-level printing mechanics on Mac
Part two of printing implementation on the Mac. This adds a Mac implementation of PrintSettings to get page setup and printer information, basic PDF->context rendering in PrintedDocument, and most of PrintingContext to allow getting print settings (both default and interactive). Reworks the message flow a bit when asking for print settings on the Mac, since it can only be done from the UI thread. Uses a modal dialog for now, but will later be modified further to allow for a sheet. BUG=13158 TEST=None; no user-visible effect yet. Review URL: http://codereview.chromium.org/268036 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@28857 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'printing')
-rw-r--r--printing/print_settings.cc46
-rw-r--r--printing/print_settings.h8
-rw-r--r--printing/printed_document.cc129
-rw-r--r--printing/printed_document.h9
-rw-r--r--printing/printed_document_linux.cc28
-rw-r--r--printing/printed_document_mac.cc53
-rw-r--r--printing/printed_document_win.cc142
-rw-r--r--printing/printing.gyp5
-rw-r--r--printing/printing_context.h46
-rw-r--r--printing/printing_context_mac.cc117
-rw-r--r--printing/printing_context_mac.mm206
-rw-r--r--printing/printing_context_win.cc68
12 files changed, 567 insertions, 290 deletions
diff --git a/printing/print_settings.cc b/printing/print_settings.cc
index 4df0483..4764952 100644
--- a/printing/print_settings.cc
+++ b/printing/print_settings.cc
@@ -6,6 +6,7 @@
#include "base/atomic_sequence_num.h"
#include "base/logging.h"
+#include "base/sys_string_conversions.h"
#include "printing/units.h"
namespace printing {
@@ -68,6 +69,51 @@ void PrintSettings::Init(HDC hdc,
SetPrinterPrintableArea(physical_size_pixels, printable_area_pixels);
}
+#elif defined(OS_MACOSX)
+void PrintSettings::Init(PMPrinter printer, PMPageFormat page_format,
+ const PageRanges& new_ranges,
+ bool print_selection_only) {
+ printer_name_ = base::SysCFStringRefToWide(PMPrinterGetName(printer));
+ device_name_ = base::SysCFStringRefToWide(PMPrinterGetID(printer));
+ ranges = new_ranges;
+ PMOrientation orientation = kPMPortrait;
+ PMGetOrientation(page_format, &orientation);
+ landscape_ = orientation == kPMLandscape;
+ selection_only = print_selection_only;
+
+ UInt32 resolution_count = 0;
+ PMResolution best_resolution = { 72.0, 72.0 };
+ OSStatus status = PMPrinterGetPrinterResolutionCount(printer,
+ &resolution_count);
+ if (status == noErr) {
+ // Resolution indexes are 1-based.
+ for (uint32 i = 1; i <= resolution_count; ++i) {
+ PMResolution resolution;
+ PMPrinterGetIndexedPrinterResolution(printer, i, &resolution);
+ if (best_resolution.hRes > resolution.hRes)
+ best_resolution = resolution;
+ }
+ }
+ dpi_ = best_resolution.hRes;
+ // See comment in the Windows code above.
+ DCHECK_EQ(dpi_, best_resolution.vRes);
+
+ // Get printable area and paper rects (in points)
+ PMRect page_rect, paper_rect;
+ PMGetAdjustedPageRect(page_format, &page_rect);
+ PMGetAdjustedPaperRect(page_format, &paper_rect);
+ const double pixels_per_point = dpi_ / 72.0;
+ gfx::Size physical_size_pixels(
+ (paper_rect.right - paper_rect.left) * pixels_per_point,
+ (paper_rect.bottom - paper_rect.top) * pixels_per_point);
+ gfx::Rect printable_area_pixels(
+ (page_rect.left - paper_rect.left) * pixels_per_point,
+ (page_rect.top - paper_rect.top) * pixels_per_point,
+ (page_rect.right - page_rect.left) * pixels_per_point,
+ (page_rect.bottom - page_rect.top) * pixels_per_point);
+
+ SetPrinterPrintableArea(physical_size_pixels, printable_area_pixels);
+}
#endif
void PrintSettings::SetPrinterPrintableArea(
diff --git a/printing/print_settings.h b/printing/print_settings.h
index d1929c3..dd90007f 100644
--- a/printing/print_settings.h
+++ b/printing/print_settings.h
@@ -10,6 +10,10 @@
#include "printing/page_range.h"
#include "printing/page_setup.h"
+#if defined(OS_MACOSX)
+#import <ApplicationServices/ApplicationServices.h>
+#endif
+
typedef struct HDC__* HDC;
typedef struct _devicemodeW DEVMODE;
@@ -31,6 +35,10 @@ class PrintSettings {
const PageRanges& new_ranges,
const std::wstring& new_device_name,
bool selection_only);
+#elif defined(OS_MACOSX)
+ // Reads the settings from the given PMPrinter and PMPageFormat.
+ void Init(PMPrinter printer, PMPageFormat page_format,
+ const PageRanges& new_ranges, bool print_selection_only);
#endif
// Set printer printable area in in pixels.
diff --git a/printing/printed_document.cc b/printing/printed_document.cc
index e847fe5..aa9ab5b 100644
--- a/printing/printed_document.cc
+++ b/printing/printed_document.cc
@@ -41,24 +41,6 @@ struct PrintDebugDumpPath {
Singleton<PrintDebugDumpPath> g_debug_dump_info;
-#if defined(OS_WIN)
-void SimpleModifyWorldTransform(HDC context,
- int offset_x,
- int offset_y,
- double shrink_factor) {
- XFORM xform = { 0 };
- xform.eDx = static_cast<float>(offset_x);
- xform.eDy = static_cast<float>(offset_y);
- xform.eM11 = xform.eM22 = static_cast<float>(1. / shrink_factor);
- BOOL res = ModifyWorldTransform(context, &xform, MWT_LEFTMULTIPLY);
- DCHECK_NE(res, 0);
-}
-
-void DrawRect(HDC context, gfx::Rect rect) {
- Rectangle(context, rect.x(), rect.y(), rect.right(), rect.bottom());
-}
-#endif // OS_WIN
-
} // namespace
namespace printing {
@@ -115,111 +97,8 @@ bool PrintedDocument::GetPage(int page_number,
return false;
}
-void PrintedDocument::RenderPrintedPage(const PrintedPage& page,
- HDC context) const {
-#ifndef NDEBUG
- {
- // Make sure the page is from our list.
- AutoLock lock(lock_);
- DCHECK(&page == mutable_.pages_.find(page.page_number() - 1)->second.get());
- }
-#endif
-
-#if defined(OS_WIN)
- const printing::PageSetup& page_setup(
- immutable_.settings_.page_setup_pixels());
-
- // Save the state to make sure the context this function call does not modify
- // the device context.
- int saved_state = SaveDC(context);
- DCHECK_NE(saved_state, 0);
- skia::PlatformDevice::InitializeDC(context);
- {
- // Save the state (again) to apply the necessary world transformation.
- int saved_state = SaveDC(context);
- DCHECK_NE(saved_state, 0);
-
-#if 0
- // Debug code to visually verify margins (leaks GDI handles).
- XFORM debug_xform = { 0 };
- ModifyWorldTransform(context, &debug_xform, MWT_IDENTITY);
- // Printable area:
- SelectObject(context, CreatePen(PS_SOLID, 1, RGB(0, 0, 0)));
- SelectObject(context, CreateSolidBrush(RGB(0x90, 0x90, 0x90)));
- Rectangle(context,
- 0,
- 0,
- page_setup.printable_area().width(),
- page_setup.printable_area().height());
- // Overlay area:
- gfx::Rect debug_overlay_area(page_setup.overlay_area());
- debug_overlay_area.Offset(-page_setup.printable_area().x(),
- -page_setup.printable_area().y());
- SelectObject(context, CreateSolidBrush(RGB(0xb0, 0xb0, 0xb0)));
- DrawRect(context, debug_overlay_area);
- // Content area:
- gfx::Rect debug_content_area(page_setup.content_area());
- debug_content_area.Offset(-page_setup.printable_area().x(),
- -page_setup.printable_area().y());
- SelectObject(context, CreateSolidBrush(RGB(0xd0, 0xd0, 0xd0)));
- DrawRect(context, debug_content_area);
-#endif
-
- // Setup the matrix to translate and scale to the right place. Take in
- // account the actual shrinking factor.
- // Note that the printing output is relative to printable area of the page.
- // That is 0,0 is offset by PHYSICALOFFSETX/Y from the page.
- SimpleModifyWorldTransform(
- context,
- page_setup.content_area().x() - page_setup.printable_area().x(),
- page_setup.content_area().y() - page_setup.printable_area().y(),
- mutable_.shrink_factor);
-
- if (!page.native_metafile()->SafePlayback(context)) {
- NOTREACHED();
- }
-
- BOOL res = RestoreDC(context, saved_state);
- DCHECK_NE(res, 0);
- }
-
- // Print the header and footer. Offset by printable area offset (see comment
- // above).
- SimpleModifyWorldTransform(
- context,
- -page_setup.printable_area().x(),
- -page_setup.printable_area().y(),
- 1);
- int base_font_size = gfx::Font().height();
- int new_font_size = ConvertUnit(10,
- immutable_.settings_.desired_dpi,
- immutable_.settings_.dpi());
- DCHECK_GT(new_font_size, base_font_size);
- gfx::Font font(gfx::Font().DeriveFont(new_font_size - base_font_size));
- HGDIOBJ old_font = SelectObject(context, font.hfont());
- DCHECK(old_font != NULL);
- // We don't want a white square around the text ever if overflowing.
- SetBkMode(context, TRANSPARENT);
- PrintHeaderFooter(context, page, PageOverlays::LEFT, PageOverlays::TOP,
- font);
- PrintHeaderFooter(context, page, PageOverlays::CENTER, PageOverlays::TOP,
- font);
- PrintHeaderFooter(context, page, PageOverlays::RIGHT, PageOverlays::TOP,
- font);
- PrintHeaderFooter(context, page, PageOverlays::LEFT, PageOverlays::BOTTOM,
- font);
- PrintHeaderFooter(context, page, PageOverlays::CENTER, PageOverlays::BOTTOM,
- font);
- PrintHeaderFooter(context, page, PageOverlays::RIGHT, PageOverlays::BOTTOM,
- font);
- int res = RestoreDC(context, saved_state);
- DCHECK_NE(res, 0);
-#else // OS_WIN
- NOTIMPLEMENTED();
-#endif // OS_WIN
-}
-
-bool PrintedDocument::RenderPrintedPageNumber(int page_number, HDC context) {
+bool PrintedDocument::RenderPrintedPageNumber(
+ int page_number, gfx::NativeDrawingContext context) {
scoped_refptr<PrintedPage> page;
if (!GetPage(page_number, &page))
return false;
@@ -291,7 +170,7 @@ int PrintedDocument::expected_page_count() const {
return mutable_.expected_page_count_;
}
-void PrintedDocument::PrintHeaderFooter(HDC context,
+void PrintedDocument::PrintHeaderFooter(gfx::NativeDrawingContext context,
const PrintedPage& page,
PageOverlays::HorizontalPosition x,
PageOverlays::VerticalPosition y,
@@ -350,6 +229,8 @@ void PrintedDocument::PrintHeaderFooter(HDC context,
}
}
+ // TODO(stuartmorgan): Factor out this platform-specific part into another
+ // method that can be moved into the platform files.
#if defined(OS_WIN)
// Save the state (again) for the clipping region.
int saved_state = SaveDC(context);
diff --git a/printing/printed_document.h b/printing/printed_document.h
index cedaddd..6e20d33 100644
--- a/printing/printed_document.h
+++ b/printing/printed_document.h
@@ -7,6 +7,7 @@
#include <map>
+#include "app/gfx/native_widget_types.h"
#include "base/lock.h"
#include "base/ref_counted.h"
#include "base/scoped_ptr.h"
@@ -51,12 +52,14 @@ class PrintedDocument : public base::RefCountedThreadSafe<PrintedDocument> {
// Draws the page in the context.
// Note: locks for a short amount of time in debug only.
- void RenderPrintedPage(const PrintedPage& page, HDC context) const;
+ void RenderPrintedPage(const PrintedPage& page,
+ gfx::NativeDrawingContext context) const;
// Draws the page in the context. If the page is not available right now, it
// requests to have this page be rendered and returns false.
// Note: locks for a short amount of time.
- bool RenderPrintedPageNumber(int page_number, HDC context);
+ bool RenderPrintedPageNumber(int page_number,
+ gfx::NativeDrawingContext context);
// Returns true if all the necessary pages for the settings are already
// rendered.
@@ -166,7 +169,7 @@ class PrintedDocument : public base::RefCountedThreadSafe<PrintedDocument> {
// Prints the headers and footers for one page in the specified context
// according to the current settings.
- void PrintHeaderFooter(HDC context,
+ void PrintHeaderFooter(gfx::NativeDrawingContext context,
const PrintedPage& page,
PageOverlays::HorizontalPosition x,
PageOverlays::VerticalPosition y,
diff --git a/printing/printed_document_linux.cc b/printing/printed_document_linux.cc
new file mode 100644
index 0000000..8386914
--- /dev/null
+++ b/printing/printed_document_linux.cc
@@ -0,0 +1,28 @@
+// Copyright (c) 2009 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "printing/printed_document.h"
+
+#include "base/file_util.h"
+#include "base/logging.h"
+#include "base/message_loop.h"
+#include "printing/page_number.h"
+#include "printing/printed_page.h"
+
+namespace printing {
+
+void PrintedDocument::RenderPrintedPage(
+ const PrintedPage& page, gfx::NativeDrawingContext context) const {
+#ifndef NDEBUG
+ {
+ // Make sure the page is from our list.
+ AutoLock lock(lock_);
+ DCHECK(&page == mutable_.pages_.find(page.page_number() - 1)->second.get());
+ }
+#endif
+
+ NOTIMPLEMENTED();
+}
+
+} // namespace printing
diff --git a/printing/printed_document_mac.cc b/printing/printed_document_mac.cc
new file mode 100644
index 0000000..ace57f3
--- /dev/null
+++ b/printing/printed_document_mac.cc
@@ -0,0 +1,53 @@
+// Copyright (c) 2009 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "printing/printed_document.h"
+
+#import <ApplicationServices/ApplicationServices.h>
+#import <CoreFoundation/CoreFoundation.h>
+
+#include "base/logging.h"
+#include "base/scoped_cftyperef.h"
+#include "printing/page_number.h"
+#include "printing/printed_page.h"
+
+namespace printing {
+
+void PrintedDocument::RenderPrintedPage(
+ const PrintedPage& page, gfx::NativeDrawingContext context) const {
+#ifndef NDEBUG
+ {
+ // Make sure the page is from our list.
+ AutoLock lock(lock_);
+ DCHECK(&page == mutable_.pages_.find(page.page_number() - 1)->second.get());
+ }
+#endif
+
+ const printing::NativeMetafile* metafile = page.native_metafile();
+ unsigned int data_length = metafile->GetDataSize();
+ scoped_cftyperef<CFMutableDataRef> pdf_data(
+ CFDataCreateMutable(kCFAllocatorDefault, data_length));
+ CFDataIncreaseLength(pdf_data, data_length);
+ metafile->GetData(CFDataGetMutableBytePtr(pdf_data), data_length);
+ scoped_cftyperef<CGDataProviderRef> pdf_data_provider(
+ CGDataProviderCreateWithCFData(pdf_data));
+ scoped_cftyperef<CGPDFDocumentRef> pdf_doc(
+ CGPDFDocumentCreateWithProvider(pdf_data_provider));
+ if (!pdf_doc.get()) {
+ NOTREACHED() << "Unable to create PDF document from print data";
+ return;
+ }
+
+ const printing::PageSetup& page_setup(
+ immutable_.settings_.page_setup_pixels());
+ CGRect target_rect = page_setup.content_area().ToCGRect();
+
+ // Each NativeMetafile is a one-page PDF.
+ const int page_number = 1;
+ CGContextDrawPDFDocument(context, target_rect, pdf_doc, page_number);
+
+ // TODO(stuartmorgan): Print the header and footer.
+}
+
+} // namespace printing
diff --git a/printing/printed_document_win.cc b/printing/printed_document_win.cc
new file mode 100644
index 0000000..12d5a1a
--- /dev/null
+++ b/printing/printed_document_win.cc
@@ -0,0 +1,142 @@
+// Copyright (c) 2009 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "printing/printed_document.h"
+
+#include "app/win_util.h"
+#include "app/gfx/font.h"
+#include "base/logging.h"
+#include "base/string_util.h"
+#include "printing/page_number.h"
+#include "printing/page_overlays.h"
+#include "printing/printed_pages_source.h"
+#include "printing/printed_page.h"
+#include "printing/units.h"
+#include "skia/ext/platform_device.h"
+
+#if defined(OS_WIN)
+namespace {
+
+void SimpleModifyWorldTransform(HDC context,
+ int offset_x,
+ int offset_y,
+ double shrink_factor) {
+ XFORM xform = { 0 };
+ xform.eDx = static_cast<float>(offset_x);
+ xform.eDy = static_cast<float>(offset_y);
+ xform.eM11 = xform.eM22 = static_cast<float>(1. / shrink_factor);
+ BOOL res = ModifyWorldTransform(context, &xform, MWT_LEFTMULTIPLY);
+ DCHECK_NE(res, 0);
+}
+
+void DrawRect(HDC context, gfx::Rect rect) {
+ Rectangle(context, rect.x(), rect.y(), rect.right(), rect.bottom());
+}
+
+} // namespace
+#endif // OS_WIN
+
+namespace printing {
+
+void PrintedDocument::RenderPrintedPage(
+ const PrintedPage& page, gfx::NativeDrawingContext context) const {
+#ifndef NDEBUG
+ {
+ // Make sure the page is from our list.
+ AutoLock lock(lock_);
+ DCHECK(&page == mutable_.pages_.find(page.page_number() - 1)->second.get());
+ }
+#endif
+
+ const printing::PageSetup& page_setup(
+ immutable_.settings_.page_setup_pixels());
+
+ // Save the state to make sure the context this function call does not modify
+ // the device context.
+ int saved_state = SaveDC(context);
+ DCHECK_NE(saved_state, 0);
+ skia::PlatformDevice::InitializeDC(context);
+ {
+ // Save the state (again) to apply the necessary world transformation.
+ int saved_state = SaveDC(context);
+ DCHECK_NE(saved_state, 0);
+
+#if 0
+ // Debug code to visually verify margins (leaks GDI handles).
+ XFORM debug_xform = { 0 };
+ ModifyWorldTransform(context, &debug_xform, MWT_IDENTITY);
+ // Printable area:
+ SelectObject(context, CreatePen(PS_SOLID, 1, RGB(0, 0, 0)));
+ SelectObject(context, CreateSolidBrush(RGB(0x90, 0x90, 0x90)));
+ Rectangle(context,
+ 0,
+ 0,
+ page_setup.printable_area().width(),
+ page_setup.printable_area().height());
+ // Overlay area:
+ gfx::Rect debug_overlay_area(page_setup.overlay_area());
+ debug_overlay_area.Offset(-page_setup.printable_area().x(),
+ -page_setup.printable_area().y());
+ SelectObject(context, CreateSolidBrush(RGB(0xb0, 0xb0, 0xb0)));
+ DrawRect(context, debug_overlay_area);
+ // Content area:
+ gfx::Rect debug_content_area(page_setup.content_area());
+ debug_content_area.Offset(-page_setup.printable_area().x(),
+ -page_setup.printable_area().y());
+ SelectObject(context, CreateSolidBrush(RGB(0xd0, 0xd0, 0xd0)));
+ DrawRect(context, debug_content_area);
+#endif
+
+ // Setup the matrix to translate and scale to the right place. Take in
+ // account the actual shrinking factor.
+ // Note that the printing output is relative to printable area of the page.
+ // That is 0,0 is offset by PHYSICALOFFSETX/Y from the page.
+ SimpleModifyWorldTransform(
+ context,
+ page_setup.content_area().x() - page_setup.printable_area().x(),
+ page_setup.content_area().y() - page_setup.printable_area().y(),
+ mutable_.shrink_factor);
+
+ if (!page.native_metafile()->SafePlayback(context)) {
+ NOTREACHED();
+ }
+
+ BOOL res = RestoreDC(context, saved_state);
+ DCHECK_NE(res, 0);
+ }
+
+ // Print the header and footer. Offset by printable area offset (see comment
+ // above).
+ SimpleModifyWorldTransform(
+ context,
+ -page_setup.printable_area().x(),
+ -page_setup.printable_area().y(),
+ 1);
+ int base_font_size = gfx::Font().height();
+ int new_font_size = ConvertUnit(10,
+ immutable_.settings_.desired_dpi,
+ immutable_.settings_.dpi());
+ DCHECK_GT(new_font_size, base_font_size);
+ gfx::Font font(gfx::Font().DeriveFont(new_font_size - base_font_size));
+ HGDIOBJ old_font = SelectObject(context, font.hfont());
+ DCHECK(old_font != NULL);
+ // We don't want a white square around the text ever if overflowing.
+ SetBkMode(context, TRANSPARENT);
+ PrintHeaderFooter(context, page, PageOverlays::LEFT, PageOverlays::TOP,
+ font);
+ PrintHeaderFooter(context, page, PageOverlays::CENTER, PageOverlays::TOP,
+ font);
+ PrintHeaderFooter(context, page, PageOverlays::RIGHT, PageOverlays::TOP,
+ font);
+ PrintHeaderFooter(context, page, PageOverlays::LEFT, PageOverlays::BOTTOM,
+ font);
+ PrintHeaderFooter(context, page, PageOverlays::CENTER, PageOverlays::BOTTOM,
+ font);
+ PrintHeaderFooter(context, page, PageOverlays::RIGHT, PageOverlays::BOTTOM,
+ font);
+ int res = RestoreDC(context, saved_state);
+ DCHECK_NE(res, 0);
+}
+
+} // namespace printing
diff --git a/printing/printing.gyp b/printing/printing.gyp
index 84545a8..1076b4f 100644
--- a/printing/printing.gyp
+++ b/printing/printing.gyp
@@ -44,13 +44,16 @@
'print_settings.cc',
'print_settings.h',
'printed_document.cc',
+ 'printed_document_linux.cc',
+ 'printed_document_mac.cc',
+ 'printed_document_win.cc',
'printed_document.h',
'printed_page.cc',
'printed_page.h',
'printed_pages_source.h',
'printing_context.h',
'printing_context_linux.cc',
- 'printing_context_mac.cc',
+ 'printing_context_mac.mm',
'printing_context_win.cc',
'units.cc',
'units.h',
diff --git a/printing/printing_context.h b/printing/printing_context.h
index 06ad9af..d1bfca7 100644
--- a/printing/printing_context.h
+++ b/printing/printing_context.h
@@ -14,9 +14,20 @@
#include <string>
+#include "app/gfx/native_widget_types.h"
#include "base/basictypes.h"
+#include "base/logging.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
@@ -34,11 +45,10 @@ class PrintingContext {
PrintingContext();
~PrintingContext();
-#if defined(OS_WIN)
// Asks the user what printer and format should be used to print. Updates the
// context with the select device settings.
- Result AskUserForSettings(HWND window, int max_pages, bool has_selection);
-#endif
+ Result AskUserForSettings(gfx::NativeWindow window, int max_pages,
+ bool has_selection);
// Selects the user's default printer and format. Updates the context with the
// default device settings.
@@ -75,11 +85,14 @@ class PrintingContext {
// Dismiss the Print... dialog box if shown.
void DismissDialog();
-#if defined(OS_WIN)
- HDC context() {
- return hdc_;
- }
+ gfx::NativeDrawingContext context() {
+#if defined(OS_WIN) || defined(OS_MACOSX)
+ return context_;
+#else
+ NOTIMPLEMENTED();
+ return NULL;
#endif
+ }
const PrintSettings& settings() const {
return settings_;
@@ -105,8 +118,8 @@ class PrintingContext {
int number_ranges,
bool selection_only);
- // Retrieves the printer's default low-level settings. hdc_ is allocated with
- // this call.
+ // 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);
@@ -118,8 +131,19 @@ class PrintingContext {
Result ParseDialogResultEx(const PRINTDLGEX& dialog_options);
Result ParseDialogResult(const PRINTDLG& dialog_options);
- // The selected printer context.
- HDC hdc_;
+#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.
diff --git a/printing/printing_context_mac.cc b/printing/printing_context_mac.cc
deleted file mode 100644
index fcc51f7..0000000
--- a/printing/printing_context_mac.cc
+++ /dev/null
@@ -1,117 +0,0 @@
-// Copyright (c) 2009 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "printing/printing_context.h"
-
-#include "base/logging.h"
-
-namespace printing {
-
-PrintingContext::PrintingContext()
- :
-#ifndef NDEBUG
- page_number_(-1),
-#endif
- dialog_box_dismissed_(false),
- in_print_job_(false),
- abort_printing_(false) {
-}
-
-PrintingContext::~PrintingContext() {
- ResetSettings();
-}
-
-
-PrintingContext::Result PrintingContext::UseDefaultSettings() {
- DCHECK(!in_print_job_);
-
- NOTIMPLEMENTED();
-
- return FAILED;
-}
-
-PrintingContext::Result PrintingContext::InitWithSettings(
- const PrintSettings& settings) {
- DCHECK(!in_print_job_);
- settings_ = settings;
-
- NOTIMPLEMENTED();
-
- return FAILED;
-}
-
-void PrintingContext::ResetSettings() {
-#ifndef NDEBUG
- page_number_ = -1;
-#endif
- dialog_box_dismissed_ = false;
- abort_printing_ = false;
- in_print_job_ = false;
-}
-
-PrintingContext::Result PrintingContext::NewDocument(
- const std::wstring& document_name) {
- DCHECK(!in_print_job_);
-
- NOTIMPLEMENTED();
-
-#ifndef NDEBUG
- page_number_ = 0;
-#endif
-
- return FAILED;
-}
-
-PrintingContext::Result PrintingContext::NewPage() {
- if (abort_printing_)
- return CANCEL;
- DCHECK(in_print_job_);
-
- NOTIMPLEMENTED();
-
-#ifndef NDEBUG
- ++page_number_;
-#endif
-
- return FAILED;
-}
-
-PrintingContext::Result PrintingContext::PageDone() {
- if (abort_printing_)
- return CANCEL;
- DCHECK(in_print_job_);
-
- NOTIMPLEMENTED();
-
- return FAILED;
-}
-
-PrintingContext::Result PrintingContext::DocumentDone() {
- if (abort_printing_)
- return CANCEL;
- DCHECK(in_print_job_);
-
- NOTIMPLEMENTED();
-
- ResetSettings();
- return FAILED;
-}
-
-void PrintingContext::Cancel() {
- abort_printing_ = true;
- in_print_job_ = false;
-
- NOTIMPLEMENTED();
-}
-
-void PrintingContext::DismissDialog() {
- NOTIMPLEMENTED();
-}
-
-PrintingContext::Result PrintingContext::OnError() {
- ResetSettings();
- return abort_printing_ ? CANCEL : FAILED;
-}
-
-} // namespace printing
diff --git a/printing/printing_context_mac.mm b/printing/printing_context_mac.mm
new file mode 100644
index 0000000..a933f74
--- /dev/null
+++ b/printing/printing_context_mac.mm
@@ -0,0 +1,206 @@
+// Copyright (c) 2009 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "printing/printing_context.h"
+
+#import <ApplicationServices/ApplicationServices.h>
+#import <AppKit/AppKit.h>
+
+#include "base/logging.h"
+
+namespace printing {
+
+PrintingContext::PrintingContext()
+ : context_(NULL),
+ print_info_(nil),
+#ifndef NDEBUG
+ page_number_(-1),
+#endif
+ dialog_box_dismissed_(false),
+ in_print_job_(false),
+ abort_printing_(false) {
+}
+
+PrintingContext::~PrintingContext() {
+ ResetSettings();
+}
+
+
+PrintingContext::Result PrintingContext::AskUserForSettings(
+ gfx::NativeWindow window, int max_pages, bool has_selection) {
+ DCHECK([NSThread isMainThread]);
+
+ // We deliberately don't feed max_pages into the dialog, because setting
+ // NSPrintLastPage makes the print dialog pre-select the option to only print
+ // a range.
+
+ // TODO(stuartmorgan): implement 'print selection only' (probably requires
+ // adding a new custom view to the panel on 10.5; 10.6 has
+ // NSPrintPanelShowsPrintSelection).
+ NSPrintPanel* panel = [NSPrintPanel printPanel];
+ // TODO(stuartmorgan): We really want a tab sheet here, not a modal window.
+ // Will require restructuring the PrintingContext API to use a callback.
+ NSInteger selection =
+ [panel runModalWithPrintInfo:[NSPrintInfo sharedPrintInfo]];
+ if (selection != NSOKButton) {
+ return CANCEL;
+ }
+
+ ParsePrintInfo([panel printInfo]);
+ return OK;
+}
+
+PrintingContext::Result PrintingContext::UseDefaultSettings() {
+ DCHECK(!in_print_job_);
+
+ ParsePrintInfo([NSPrintInfo sharedPrintInfo]);
+
+ return OK;
+}
+
+void PrintingContext::ParsePrintInfo(NSPrintInfo* print_info) {
+ ResetSettings();
+ print_info_ = [print_info retain];
+ PageRanges page_ranges;
+ NSDictionary* print_info_dict = [print_info_ dictionary];
+ if (![[print_info_dict objectForKey:NSPrintAllPages] boolValue]) {
+ PageRange range;
+ range.from = [[print_info_dict objectForKey:NSPrintFirstPage] intValue] - 1;
+ range.to = [[print_info_dict objectForKey:NSPrintLastPage] intValue] - 1;
+ page_ranges.push_back(range);
+ }
+ PMPrintSession print_session =
+ static_cast<PMPrintSession>([print_info_ PMPrintSession]);
+ PMPageFormat page_format =
+ static_cast<PMPageFormat>([print_info_ PMPageFormat]);
+ PMPrinter printer;
+ PMSessionGetCurrentPrinter(print_session, &printer);
+
+ settings_.Init(printer, page_format, page_ranges, false);
+}
+
+PrintingContext::Result PrintingContext::InitWithSettings(
+ const PrintSettings& settings) {
+ DCHECK(!in_print_job_);
+ settings_ = settings;
+
+ NOTIMPLEMENTED();
+
+ return FAILED;
+}
+
+void PrintingContext::ResetSettings() {
+ [print_info_ autorelease];
+ print_info_ = nil;
+ settings_.Clear();
+#ifndef NDEBUG
+ page_number_ = -1;
+#endif
+ dialog_box_dismissed_ = false;
+ abort_printing_ = false;
+ in_print_job_ = false;
+ context_ = NULL;
+}
+
+PrintingContext::Result PrintingContext::NewDocument(
+ const std::wstring& document_name) {
+ DCHECK(!in_print_job_);
+
+ in_print_job_ = true;
+
+ PMPrintSession print_session =
+ static_cast<PMPrintSession>([print_info_ PMPrintSession]);
+ PMPrintSettings print_settings =
+ static_cast<PMPrintSettings>([print_info_ PMPrintSettings]);
+ PMPageFormat page_format =
+ static_cast<PMPageFormat>([print_info_ PMPageFormat]);
+ OSStatus status = PMSessionBeginCGDocumentNoDialog(print_session,
+ print_settings,
+ page_format);
+ if (status != noErr)
+ return OnError();
+
+#ifndef NDEBUG
+ page_number_ = 0;
+#endif
+
+ return OK;
+}
+
+PrintingContext::Result PrintingContext::NewPage() {
+ if (abort_printing_)
+ return CANCEL;
+ DCHECK(in_print_job_);
+ DCHECK(!context_);
+
+ PMPrintSession print_session =
+ static_cast<PMPrintSession>([print_info_ PMPrintSession]);
+ PMPageFormat page_format =
+ static_cast<PMPageFormat>([print_info_ PMPageFormat]);
+ OSStatus status;
+ status = PMSessionBeginPageNoDialog(print_session, page_format, NULL);
+ if (status != noErr)
+ return OnError();
+ status = PMSessionGetCGGraphicsContext(print_session, &context_);
+ if (status != noErr)
+ return OnError();
+
+#ifndef NDEBUG
+ ++page_number_;
+#endif
+
+ return OK;
+}
+
+PrintingContext::Result PrintingContext::PageDone() {
+ if (abort_printing_)
+ return CANCEL;
+ DCHECK(in_print_job_);
+ DCHECK(context_);
+
+ PMPrintSession print_session =
+ static_cast<PMPrintSession>([print_info_ PMPrintSession]);
+ OSStatus status = PMSessionEndPageNoDialog(print_session);
+ if (status != noErr)
+ OnError();
+ context_ = NULL;
+
+ return OK;
+}
+
+PrintingContext::Result PrintingContext::DocumentDone() {
+ if (abort_printing_)
+ return CANCEL;
+ DCHECK(in_print_job_);
+
+ PMPrintSession print_session =
+ static_cast<PMPrintSession>([print_info_ PMPrintSession]);
+ OSStatus status = PMSessionEndDocumentNoDialog(print_session);
+ if (status != noErr)
+ OnError();
+
+ ResetSettings();
+ return OK;
+}
+
+void PrintingContext::Cancel() {
+ abort_printing_ = true;
+ in_print_job_ = false;
+ context_ = NULL;
+
+ PMPrintSession print_session =
+ static_cast<PMPrintSession>([print_info_ PMPrintSession]);
+ PMSessionEndPageNoDialog(print_session);
+}
+
+void PrintingContext::DismissDialog() {
+ NOTIMPLEMENTED();
+}
+
+PrintingContext::Result PrintingContext::OnError() {
+ ResetSettings();
+ return abort_printing_ ? CANCEL : FAILED;
+}
+
+} // namespace printing
diff --git a/printing/printing_context_win.cc b/printing/printing_context_win.cc
index 8fa50fe..99232a9 100644
--- a/printing/printing_context_win.cc
+++ b/printing/printing_context_win.cc
@@ -138,7 +138,7 @@ class PrintingContext::CallbackHandler
};
PrintingContext::PrintingContext()
- : hdc_(NULL),
+ : context_(NULL),
#ifndef NDEBUG
page_number_(-1),
#endif
@@ -241,9 +241,9 @@ PrintingContext::Result PrintingContext::InitWithSettings(
}
void PrintingContext::ResetSettings() {
- if (hdc_ != NULL) {
- DeleteDC(hdc_);
- hdc_ = NULL;
+ if (context_ != NULL) {
+ DeleteDC(context_);
+ context_ = NULL;
}
settings_.Clear();
in_print_job_ = false;
@@ -256,7 +256,7 @@ void PrintingContext::ResetSettings() {
PrintingContext::Result PrintingContext::NewDocument(
const std::wstring& document_name) {
DCHECK(!in_print_job_);
- if (!hdc_)
+ if (!context_)
return OnError();
// Set the flag used by the AbortPrintJob dialog procedure.
@@ -265,7 +265,7 @@ PrintingContext::Result PrintingContext::NewDocument(
in_print_job_ = true;
// Register the application's AbortProc function with GDI.
- if (SP_ERROR == SetAbortProc(hdc_, &AbortProc))
+ if (SP_ERROR == SetAbortProc(context_, &AbortProc))
return OnError();
DOCINFO di = { sizeof(DOCINFO) };
@@ -296,7 +296,7 @@ PrintingContext::Result PrintingContext::NewDocument(
// Begin a print job by calling the StartDoc function.
// NOTE: StartDoc() starts a message loop. That causes a lot of problems with
// IPC. Make sure recursive task processing is disabled.
- if (StartDoc(hdc_, &di) <= 0)
+ if (StartDoc(context_, &di) <= 0)
return OnError();
#ifndef NDEBUG
@@ -311,7 +311,7 @@ PrintingContext::Result PrintingContext::NewPage() {
DCHECK(in_print_job_);
// Inform the driver that the application is about to begin sending data.
- if (StartPage(hdc_) <= 0)
+ if (StartPage(context_) <= 0)
return OnError();
#ifndef NDEBUG
@@ -326,7 +326,7 @@ PrintingContext::Result PrintingContext::PageDone() {
return CANCEL;
DCHECK(in_print_job_);
- if (EndPage(hdc_) <= 0)
+ if (EndPage(context_) <= 0)
return OnError();
return OK;
}
@@ -337,7 +337,7 @@ PrintingContext::Result PrintingContext::DocumentDone() {
DCHECK(in_print_job_);
// Inform the driver that document has ended.
- if (EndDoc(hdc_) <= 0)
+ if (EndDoc(context_) <= 0)
return OnError();
ResetSettings();
@@ -347,8 +347,8 @@ PrintingContext::Result PrintingContext::DocumentDone() {
void PrintingContext::Cancel() {
abort_printing_ = true;
in_print_job_ = false;
- if (hdc_)
- CancelDC(hdc_);
+ if (context_)
+ CancelDC(context_);
DismissDialog();
}
@@ -360,7 +360,7 @@ void PrintingContext::DismissDialog() {
}
PrintingContext::Result PrintingContext::OnError() {
- // This will close hdc_ and clear settings_.
+ // This will close context_ and clear settings_.
ResetSettings();
return abort_printing_ ? CANCEL : FAILED;
}
@@ -380,25 +380,25 @@ bool PrintingContext::InitializeSettings(const DEVMODE& dev_mode,
const PRINTPAGERANGE* ranges,
int number_ranges,
bool selection_only) {
- skia::PlatformDevice::InitializeDC(hdc_);
- DCHECK(GetDeviceCaps(hdc_, CLIPCAPS));
- DCHECK(GetDeviceCaps(hdc_, RASTERCAPS) & RC_STRETCHDIB);
- DCHECK(GetDeviceCaps(hdc_, RASTERCAPS) & RC_BITMAP64);
+ skia::PlatformDevice::InitializeDC(context_);
+ DCHECK(GetDeviceCaps(context_, CLIPCAPS));
+ DCHECK(GetDeviceCaps(context_, RASTERCAPS) & RC_STRETCHDIB);
+ DCHECK(GetDeviceCaps(context_, RASTERCAPS) & RC_BITMAP64);
// Some printers don't advertise these.
- // DCHECK(GetDeviceCaps(hdc_, RASTERCAPS) & RC_SCALING);
- // DCHECK(GetDeviceCaps(hdc_, SHADEBLENDCAPS) & SB_CONST_ALPHA);
- // DCHECK(GetDeviceCaps(hdc_, SHADEBLENDCAPS) & SB_PIXEL_ALPHA);
+ // DCHECK(GetDeviceCaps(context_, RASTERCAPS) & RC_SCALING);
+ // DCHECK(GetDeviceCaps(context_, SHADEBLENDCAPS) & SB_CONST_ALPHA);
+ // DCHECK(GetDeviceCaps(context_, SHADEBLENDCAPS) & SB_PIXEL_ALPHA);
// StretchDIBits() support is needed for printing.
- if (!(GetDeviceCaps(hdc_, RASTERCAPS) & RC_STRETCHDIB) ||
- !(GetDeviceCaps(hdc_, RASTERCAPS) & RC_BITMAP64)) {
+ if (!(GetDeviceCaps(context_, RASTERCAPS) & RC_STRETCHDIB) ||
+ !(GetDeviceCaps(context_, RASTERCAPS) & RC_BITMAP64)) {
NOTREACHED();
ResetSettings();
return false;
}
DCHECK(!in_print_job_);
- DCHECK(hdc_);
+ DCHECK(context_);
PageRanges ranges_vector;
if (!selection_only) {
// Convert the PRINTPAGERANGE array to a PrintSettings::PageRanges vector.
@@ -411,7 +411,7 @@ bool PrintingContext::InitializeSettings(const DEVMODE& dev_mode,
ranges_vector.push_back(range);
}
}
- settings_.Init(hdc_,
+ settings_.Init(context_,
dev_mode,
ranges_vector,
new_device_name,
@@ -474,9 +474,9 @@ bool PrintingContext::GetPrinterSettings(HANDLE printer,
bool PrintingContext::AllocateContext(const std::wstring& printer_name,
const DEVMODE* dev_mode) {
- hdc_ = CreateDC(L"WINSPOOL", printer_name.c_str(), NULL, dev_mode);
- DCHECK(hdc_);
- return hdc_ != NULL;
+ context_ = CreateDC(L"WINSPOOL", printer_name.c_str(), NULL, dev_mode);
+ DCHECK(context_);
+ return context_ != NULL;
}
PrintingContext::Result PrintingContext::ParseDialogResultEx(
@@ -509,7 +509,7 @@ PrintingContext::Result PrintingContext::ParseDialogResultEx(
bool success = false;
if (dev_mode && !device_name.empty()) {
- hdc_ = dialog_options.hDC;
+ context_ = dialog_options.hDC;
PRINTPAGERANGE* page_ranges = NULL;
DWORD num_page_ranges = 0;
bool print_selection_only = false;
@@ -529,7 +529,7 @@ PrintingContext::Result PrintingContext::ParseDialogResultEx(
if (!success && dialog_options.hDC) {
DeleteDC(dialog_options.hDC);
- hdc_ = NULL;
+ context_ = NULL;
}
if (dev_mode) {
@@ -548,9 +548,9 @@ PrintingContext::Result PrintingContext::ParseDialogResultEx(
switch (dialog_options.dwResultAction) {
case PD_RESULT_PRINT:
- return hdc_ ? OK : FAILED;
+ return context_ ? OK : FAILED;
case PD_RESULT_APPLY:
- return hdc_ ? CANCEL : FAILED;
+ return context_ ? CANCEL : FAILED;
case PD_RESULT_CANCEL:
return CANCEL;
default:
@@ -587,13 +587,13 @@ PrintingContext::Result PrintingContext::ParseDialogResult(
bool success = false;
if (dev_mode && !device_name.empty()) {
- hdc_ = dialog_options.hDC;
+ context_ = dialog_options.hDC;
success = InitializeSettings(*dev_mode, device_name, NULL, 0, false);
}
if (!success && dialog_options.hDC) {
DeleteDC(dialog_options.hDC);
- hdc_ = NULL;
+ context_ = NULL;
}
if (dev_mode) {
@@ -605,7 +605,7 @@ PrintingContext::Result PrintingContext::ParseDialogResult(
if (dialog_options.hDevNames != NULL)
GlobalFree(dialog_options.hDevNames);
- return hdc_ ? OK : FAILED;
+ return context_ ? OK : FAILED;
}
} // namespace printing