diff options
author | stuartmorgan@chromium.org <stuartmorgan@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2009-10-13 18:46:21 +0000 |
---|---|---|
committer | stuartmorgan@chromium.org <stuartmorgan@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2009-10-13 18:46:21 +0000 |
commit | b75dca87f3ff3ee3ab003960276ec7bb49d4c734 (patch) | |
tree | 8026f1f38f82a5d7c922ba5245e38a5ecf3a61d8 /printing | |
parent | 7ff3f63b8c66408a382adc88458a6e70038cad8d (diff) | |
download | chromium_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.cc | 46 | ||||
-rw-r--r-- | printing/print_settings.h | 8 | ||||
-rw-r--r-- | printing/printed_document.cc | 129 | ||||
-rw-r--r-- | printing/printed_document.h | 9 | ||||
-rw-r--r-- | printing/printed_document_linux.cc | 28 | ||||
-rw-r--r-- | printing/printed_document_mac.cc | 53 | ||||
-rw-r--r-- | printing/printed_document_win.cc | 142 | ||||
-rw-r--r-- | printing/printing.gyp | 5 | ||||
-rw-r--r-- | printing/printing_context.h | 46 | ||||
-rw-r--r-- | printing/printing_context_mac.cc | 117 | ||||
-rw-r--r-- | printing/printing_context_mac.mm | 206 | ||||
-rw-r--r-- | printing/printing_context_win.cc | 68 |
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 |