diff options
author | stuartmorgan@chromium.org <stuartmorgan@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2009-10-13 22:54:12 +0000 |
---|---|---|
committer | stuartmorgan@chromium.org <stuartmorgan@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2009-10-13 22:54:12 +0000 |
commit | b23aee0f939e07a9531935e7f0daa8a346912708 (patch) | |
tree | 6d10b5cde48ef5b3b1cf42831bded0960c40f7a6 /chrome | |
parent | 7ede31fe8ed08ff9c3e016a021a40d831e5e3587 (diff) | |
download | chromium_src-b23aee0f939e07a9531935e7f0daa8a346912708.zip chromium_src-b23aee0f939e07a9531935e7f0daa8a346912708.tar.gz chromium_src-b23aee0f939e07a9531935e7f0daa8a346912708.tar.bz2 |
Wire up printing on the Mac
Get the printing support class stack building and hooked up on the Mac.
Add support for creating NativeMetafile objects with PDF print data on the renderer side, and passing them to the browser via the existing printing IPC system.
Flip on the simpler printing unit tests (those that don't require PDF -> bitmap conversion).
BUG=13158
TEST=Print on the Mac--it should work!
Review URL: http://codereview.chromium.org/276004
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@28907 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chrome')
-rw-r--r-- | chrome/browser/browser.cc | 4 | ||||
-rw-r--r-- | chrome/browser/browser_process_impl.cc | 4 | ||||
-rw-r--r-- | chrome/browser/printing/print_job.cc | 7 | ||||
-rw-r--r-- | chrome/browser/printing/print_job_worker.cc | 50 | ||||
-rw-r--r-- | chrome/browser/printing/print_job_worker.h | 14 | ||||
-rw-r--r-- | chrome/browser/printing/print_view_manager.cc | 8 | ||||
-rw-r--r-- | chrome/browser/printing/printer_query.cc | 6 | ||||
-rw-r--r-- | chrome/browser/printing/printer_query.h | 3 | ||||
-rw-r--r-- | chrome/browser/renderer_host/resource_message_filter.cc | 38 | ||||
-rw-r--r-- | chrome/browser/renderer_host/resource_message_filter.h | 8 | ||||
-rw-r--r-- | chrome/browser/tab_contents/tab_contents.h | 4 | ||||
-rwxr-xr-x | chrome/chrome.gyp | 11 | ||||
-rw-r--r-- | chrome/common/render_messages_internal.h | 12 | ||||
-rw-r--r-- | chrome/common/temp_scaffolding_stubs.h | 2 | ||||
-rw-r--r-- | chrome/renderer/mock_render_thread.cc | 25 | ||||
-rw-r--r-- | chrome/renderer/mock_render_thread.h | 7 | ||||
-rw-r--r-- | chrome/renderer/print_web_view_helper_mac.cc | 28 | ||||
-rw-r--r-- | chrome/renderer/print_web_view_helper_mac.mm | 238 | ||||
-rw-r--r-- | chrome/renderer/render_view_unittest.cc | 4 |
19 files changed, 406 insertions, 67 deletions
diff --git a/chrome/browser/browser.cc b/chrome/browser/browser.cc index f1ece51..cb8feee 100644 --- a/chrome/browser/browser.cc +++ b/chrome/browser/browser.cc @@ -960,11 +960,7 @@ void Browser::ClosePopups() { void Browser::Print() { UserMetrics::RecordAction(L"PrintPreview", profile_); -#if defined(OS_WIN) || defined(OS_LINUX) GetSelectedTabContents()->PrintPreview(); -#else - NOTIMPLEMENTED(); -#endif } void Browser::ToggleEncodingAutoDetect() { diff --git a/chrome/browser/browser_process_impl.cc b/chrome/browser/browser_process_impl.cc index fca8950..1102d4a 100644 --- a/chrome/browser/browser_process_impl.cc +++ b/chrome/browser/browser_process_impl.cc @@ -38,7 +38,9 @@ #include "chrome/browser/automation/automation_provider_list.h" #include "chrome/browser/printing/print_job_manager.h" #include "views/focus/view_storage.h" -#elif defined(OS_POSIX) +#elif defined(OS_MACOSX) +#include "chrome/browser/printing/print_job_manager.h" +#elif defined(OS_LINUX) // TODO(port): Remove the temporary scaffolding as we port the above headers. #include "chrome/common/temp_scaffolding_stubs.h" #endif diff --git a/chrome/browser/printing/print_job.cc b/chrome/browser/printing/print_job.cc index d65b7bf..8a1a5e2 100644 --- a/chrome/browser/printing/print_job.cc +++ b/chrome/browser/printing/print_job.cc @@ -21,8 +21,8 @@ namespace printing { PrintJob::PrintJob() : ui_message_loop_(MessageLoop::current()), - worker_(), source_(NULL), + worker_(), settings_(), is_job_pending_(false), is_print_dialog_box_shown_(false), @@ -284,6 +284,10 @@ void PrintJob::OnDocumentDone() { void PrintJob::ControlledWorkerShutdown() { DCHECK_EQ(ui_message_loop_, MessageLoop::current()); + + // The deadlock this code works around is specific to window messaging on + // Windows, so we aren't likely to need it on any other platforms. +#if defined(OS_WIN) // We could easily get into a deadlock case if worker_->Stop() is used; the // printer driver created a window as a child of the browser window. By // canceling the job, the printer driver initiated dialog box is destroyed, @@ -323,6 +327,7 @@ void PrintJob::ControlledWorkerShutdown() { break; } } +#endif // Now make sure the thread object is cleaned up. worker_->Stop(); diff --git a/chrome/browser/printing/print_job_worker.cc b/chrome/browser/printing/print_job_worker.cc index 375c2407..27a553d 100644 --- a/chrome/browser/printing/print_job_worker.cc +++ b/chrome/browser/printing/print_job_worker.cc @@ -5,6 +5,7 @@ #include "chrome/browser/printing/print_job_worker.h" #include "base/message_loop.h" +#include "chrome/browser/chrome_thread.h" #include "chrome/browser/printing/print_job.h" #include "chrome/common/notification_service.h" #include "printing/printed_document.h" @@ -64,7 +65,7 @@ void PrintJobWorker::SetNewOwner(PrintJobWorkerOwner* new_owner) { } void PrintJobWorker::GetSettings(bool ask_user_for_settings, - HWND parent_window, + gfx::NativeWindow parent_window, int document_page_count, bool has_selection) { DCHECK_EQ(message_loop(), MessageLoop::current()); @@ -74,15 +75,24 @@ void PrintJobWorker::GetSettings(bool ask_user_for_settings, // destroyed by a task. MessageLoop::current()->SetNestableTasksAllowed(true); - PrintingContext::Result result; if (ask_user_for_settings) { - result = printing_context_.AskUserForSettings(parent_window, - document_page_count, - has_selection); +#if defined(OS_MACOSX) + ChromeThread::GetMessageLoop(ChromeThread::UI)->PostTask( + FROM_HERE, NewRunnableMethod(this, &PrintJobWorker::GetSettingsWithUI, + parent_window, document_page_count, + has_selection)); +#else + PrintingContext::Result result = printing_context_.AskUserForSettings( + parent_window, document_page_count, has_selection); + GetSettingsDone(result); +#endif } else { - result = printing_context_.UseDefaultSettings(); + PrintingContext::Result result = printing_context_.UseDefaultSettings(); + GetSettingsDone(result); } +} +void PrintJobWorker::GetSettingsDone(PrintingContext::Result result) { // Most PrintingContext functions may start a message loop and process // message recursively, so disable recursive task processing. MessageLoop::current()->SetNestableTasksAllowed(false); @@ -97,13 +107,29 @@ void PrintJobWorker::GetSettings(bool ask_user_for_settings, result)); } +#if defined(OS_MACOSX) +void PrintJobWorker::GetSettingsWithUI(gfx::NativeWindow parent_window, + int document_page_count, + bool has_selection) { + DCHECK_EQ(ChromeThread::GetMessageLoop(ChromeThread::UI), + MessageLoop::current()); + + PrintingContext::Result result = printing_context_.AskUserForSettings( + parent_window, document_page_count, has_selection); + message_loop()->PostTask(FROM_HERE, NewRunnableMethod( + this, &PrintJobWorker::GetSettingsDone, result)); +} +#endif + void PrintJobWorker::StartPrinting(PrintedDocument* new_document) { DCHECK_EQ(message_loop(), MessageLoop::current()); DCHECK_EQ(page_number_, PageNumber::npos()); DCHECK_EQ(document_, new_document); DCHECK(document_.get()); DCHECK(new_document->settings().Equals(printing_context_.settings())); +#if !defined(OS_MACOSX) DCHECK(printing_context_.context()); +#endif if (!document_.get() || page_number_ != PageNumber::npos() || document_ != new_document) { return; @@ -130,7 +156,9 @@ void PrintJobWorker::OnDocumentChanged(PrintedDocument* new_document) { DCHECK_EQ(page_number_, PageNumber::npos()); DCHECK(!new_document || new_document->settings().Equals(printing_context_.settings())); +#if !defined(OS_MACOSX) DCHECK(printing_context_.context()); +#endif if (page_number_ != PageNumber::npos()) return; @@ -144,9 +172,11 @@ void PrintJobWorker::OnNewPage() { } // message_loop() could return NULL when the print job is cancelled. DCHECK_EQ(message_loop(), MessageLoop::current()); +#if !defined(OS_MACOSX) DCHECK(printing_context_.context()); if (!printing_context_.context()) return; +#endif if (page_number_ == PageNumber::npos()) { // Find first page to print. @@ -199,7 +229,9 @@ void PrintJobWorker::OnDocumentDone() { DCHECK_EQ(message_loop(), MessageLoop::current()); DCHECK_EQ(page_number_, PageNumber::npos()); DCHECK(document_.get()); +#if !defined(OS_MACOSX) DCHECK(printing_context_.context()); +#endif if (printing_context_.DocumentDone() != PrintingContext::OK) { OnFailure(); @@ -221,7 +253,9 @@ void PrintJobWorker::OnDocumentDone() { void PrintJobWorker::SpoolPage(PrintedPage& page) { DCHECK_EQ(message_loop(), MessageLoop::current()); DCHECK_NE(page_number_, PageNumber::npos()); +#if !defined(OS_MACOSX) DCHECK(printing_context_.context()); +#endif // Signal everyone that the page is about to be printed. NotificationTask* task = new NotificationTask(); task->Init(owner_, @@ -236,6 +270,10 @@ void PrintJobWorker::SpoolPage(PrintedPage& page) { return; } +#if defined(OS_MACOSX) + // Context is only valid between NewPage and PageDone, so we only check here. + DCHECK(printing_context_.context()); +#endif // Actual printing. document_->RenderPrintedPage(page, printing_context_.context()); diff --git a/chrome/browser/printing/print_job_worker.h b/chrome/browser/printing/print_job_worker.h index fce8912..56e7893 100644 --- a/chrome/browser/printing/print_job_worker.h +++ b/chrome/browser/printing/print_job_worker.h @@ -5,6 +5,7 @@ #ifndef CHROME_BROWSER_PRINTING_PRINT_JOB_WORKER_H__ #define CHROME_BROWSER_PRINTING_PRINT_JOB_WORKER_H__ +#include "app/gfx/native_widget_types.h" #include "base/task.h" #include "base/thread.h" #include "printing/page_number.h" @@ -33,7 +34,7 @@ class PrintJobWorker : public base::Thread { // Initializes the print settings. If |ask_user_for_settings| is true, a // Print... dialog box will be shown to ask the user his preference. void GetSettings(bool ask_user_for_settings, - HWND parent_window, + gfx::NativeWindow parent_window, int document_page_count, bool has_selection); @@ -78,6 +79,17 @@ class PrintJobWorker : public base::Thread { // context. void OnFailure(); +#if defined(OS_MACOSX) + // Asks the user for print settings. Must be called on the UI thread. + // Mac-only since Windows can display UI from non-main threads. + void GetSettingsWithUI(gfx::NativeWindow parent_window, + int document_page_count, + bool has_selection); +#endif + + // Reports settings back to owner_. + void GetSettingsDone(PrintingContext::Result result); + // Information about the printer setting. PrintingContext printing_context_; diff --git a/chrome/browser/printing/print_view_manager.cc b/chrome/browser/printing/print_view_manager.cc index 22f3abe..4f6e73a 100644 --- a/chrome/browser/printing/print_view_manager.cc +++ b/chrome/browser/printing/print_view_manager.cc @@ -24,10 +24,10 @@ using base::TimeDelta; namespace printing { PrintViewManager::PrintViewManager(TabContents& owner) - : owner_(owner), - waiting_to_print_(false), + : waiting_to_print_(false), printing_succeeded_(false), - inside_inner_message_loop_(false) { + inside_inner_message_loop_(false), + owner_(owner) { } PrintViewManager::~PrintViewManager() { @@ -101,6 +101,7 @@ void PrintViewManager::DidPrintPage( return; } +#if defined(OS_WIN) // http://msdn2.microsoft.com/en-us/library/ms535522.aspx // Windows 2000/XP: When a page in a spooled file exceeds approximately 350 // MB, it can fail to print and not send an error message. @@ -110,6 +111,7 @@ void PrintViewManager::DidPrintPage( owner_.Stop(); return; } +#endif base::SharedMemory shared_buf(params.metafile_data_handle, true); if (!shared_buf.Map(params.data_size)) { diff --git a/chrome/browser/printing/printer_query.cc b/chrome/browser/printing/printer_query.cc index 3bcee7a..4fdadbe 100644 --- a/chrome/browser/printing/printer_query.cc +++ b/chrome/browser/printing/printer_query.cc @@ -17,8 +17,8 @@ PrinterQuery::PrinterQuery() : ui_message_loop_(MessageLoop::current()), worker_(new PrintJobWorker(this)), is_print_dialog_box_shown_(false), - last_status_(PrintingContext::FAILED), - cookie_(PrintSettings::NewCookie()) { + cookie_(PrintSettings::NewCookie()), + last_status_(PrintingContext::FAILED) { } PrinterQuery::~PrinterQuery() { @@ -62,7 +62,7 @@ PrintJobWorker* PrinterQuery::DetachWorker(PrintJobWorkerOwner* new_owner) { } void PrinterQuery::GetSettings(GetSettingsAskParam ask_user_for_settings, - HWND parent_window, + gfx::NativeWindow parent_window, int expected_page_count, bool has_selection, CancelableTask* callback) { diff --git a/chrome/browser/printing/printer_query.h b/chrome/browser/printing/printer_query.h index b0502c8..b4826ec 100644 --- a/chrome/browser/printing/printer_query.h +++ b/chrome/browser/printing/printer_query.h @@ -5,6 +5,7 @@ #ifndef CHROME_BROWSER_PRINTING_PRINTER_QUERY_H_ #define CHROME_BROWSER_PRINTING_PRINTER_QUERY_H_ +#include "app/gfx/native_widget_types.h" #include "base/scoped_ptr.h" #include "chrome/browser/printing/print_job_worker_owner.h" @@ -47,7 +48,7 @@ class PrinterQuery : public PrintJobWorkerOwner { // owner of the print setting dialog box. It is unused when // |ask_for_user_settings| is DEFAULTS. void GetSettings(GetSettingsAskParam ask_user_for_settings, - HWND parent_window, + gfx::NativeWindow parent_window, int expected_page_count, bool has_selection, CancelableTask* callback); diff --git a/chrome/browser/renderer_host/resource_message_filter.cc b/chrome/browser/renderer_host/resource_message_filter.cc index 5912750..cecdeaf 100644 --- a/chrome/browser/renderer_host/resource_message_filter.cc +++ b/chrome/browser/renderer_host/resource_message_filter.cc @@ -55,10 +55,10 @@ #include "webkit/glue/webkit_glue.h" #include "webkit/glue/webplugin.h" -#if defined(OS_WIN) +#if defined(OS_WIN) || defined(OS_MACOSX) #include "chrome/browser/printing/print_job_manager.h" #include "chrome/browser/printing/printer_query.h" -#elif defined(OS_MACOSX) || defined(OS_LINUX) || defined(OS_FREEBSD) +#elif defined(OS_LINUX) || defined(OS_FREEBSD) // TODO(port) remove this. #include "chrome/common/temp_scaffolding_stubs.h" #endif @@ -118,7 +118,7 @@ class WriteClipboardTask : public Task { void RenderParamsFromPrintSettings(const printing::PrintSettings& settings, ViewMsg_Print_Params* params) { DCHECK(params); -#if defined(OS_WIN) +#if defined(OS_WIN) || defined(OS_MACOSX) params->printable_size.SetSize( settings.page_setup_pixels().content_area().width(), settings.page_setup_pixels().content_area().height()); @@ -358,11 +358,15 @@ bool ResourceMessageFilter::OnMessageReceived(const IPC::Message& msg) { IPC_MESSAGE_HANDLER(ViewHostMsg_TempFileForPrintingWritten, OnTempFileForPrintingWritten) #endif +#if defined(OS_MACOSX) + IPC_MESSAGE_HANDLER(ViewHostMsg_AllocatePDFTransport, + OnAllocatePDFTransport) +#endif IPC_MESSAGE_HANDLER(ViewHostMsg_ResourceTypeStats, OnResourceTypeStats) IPC_MESSAGE_HANDLER_DELAY_REPLY(ViewHostMsg_ResolveProxy, OnResolveProxy) IPC_MESSAGE_HANDLER_DELAY_REPLY(ViewHostMsg_GetDefaultPrintSettings, OnGetDefaultPrintSettings) -#if defined(OS_WIN) +#if defined(OS_WIN) || defined(OS_MACOSX) IPC_MESSAGE_HANDLER_DELAY_REPLY(ViewHostMsg_ScriptedPrint, OnScriptedPrint) #endif @@ -738,6 +742,21 @@ void ResourceMessageFilter::OnDuplicateSection( } #endif +#if defined(OS_MACOSX) +void ResourceMessageFilter::OnAllocatePDFTransport( + size_t buffer_size, + base::SharedMemoryHandle* handle) { + base::SharedMemory shared_buf; + shared_buf.Create(L"", false, false, buffer_size); + if (!shared_buf.Map(buffer_size)) { + *handle = base::SharedMemory::NULLHandle(); + NOTREACHED() << "Cannot map PDF transport buffer"; + return; + } + shared_buf.GiveToProcess(base::GetCurrentProcessHandle(), handle); +} +#endif + void ResourceMessageFilter::OnResourceTypeStats( const WebCache::ResourceTypeStats& stats) { HISTOGRAM_COUNTS("WebCoreCache.ImagesSizeKB", @@ -820,12 +839,17 @@ void ResourceMessageFilter::OnGetDefaultPrintSettingsReply( } } -#if defined(OS_WIN) +#if defined(OS_WIN) || defined(OS_MACOSX) void ResourceMessageFilter::OnScriptedPrint( const ViewHostMsg_ScriptedPrint_Params& params, IPC::Message* reply_msg) { +#if defined(OS_WIN) HWND host_window = gfx::NativeViewFromId(params.host_window_id); +#elif defined(OS_MACOSX) + gfx::NativeWindow host_window = NULL; + // TODO: Get an actual window ref here, to allow a sheet-based print dialog. +#endif scoped_refptr<printing::PrinterQuery> printer_query; print_job_manager_->PopPrinterQuery(params.cookie, &printer_query); @@ -839,6 +863,7 @@ void ResourceMessageFilter::OnScriptedPrint( printer_query, params.routing_id, reply_msg); +#if defined(OS_WIN) // Shows the Print... dialog box. This is asynchronous, only the IPC message // sender will hang until the Print dialog is dismissed. if (!host_window || !IsWindow(host_window)) { @@ -848,6 +873,7 @@ void ResourceMessageFilter::OnScriptedPrint( host_window = GetAncestor(host_window, GA_ROOTOWNER); } DCHECK(host_window); +#endif printer_query->GetSettings(printing::PrinterQuery::ASK_USER, host_window, @@ -879,7 +905,7 @@ void ResourceMessageFilter::OnScriptedPrintReply( } } -#endif // OS_WIN +#endif // OS_WIN || OS_MACOSX // static Clipboard* ResourceMessageFilter::GetClipboard() { diff --git a/chrome/browser/renderer_host/resource_message_filter.h b/chrome/browser/renderer_host/resource_message_filter.h index 8821ac6..6a12d14 100644 --- a/chrome/browser/renderer_host/resource_message_filter.h +++ b/chrome/browser/renderer_host/resource_message_filter.h @@ -219,6 +219,12 @@ class ResourceMessageFilter : public IPC::ChannelProxy::MessageFilter, void OnAllocateTempFileForPrinting(IPC::Message* reply_msg); void OnTempFileForPrintingWritten(int fd_in_browser); #endif +#if defined(OS_MACOSX) + // Used to ask the browser to allocate a block of shared memory for the + // renderer to send PDF across in. + void OnAllocatePDFTransport(size_t buffer_size, + base::SharedMemoryHandle* handle); +#endif void OnResourceTypeStats(const WebKit::WebCache::ResourceTypeStats& stats); static void OnResourceTypeStatsOnUIThread(WebKit::WebCache::ResourceTypeStats, @@ -238,7 +244,7 @@ class ResourceMessageFilter : public IPC::ChannelProxy::MessageFilter, void OnGetDefaultPrintSettingsReply( scoped_refptr<printing::PrinterQuery> printer_query, IPC::Message* reply_msg); -#if defined(OS_WIN) +#if defined(OS_WIN) || defined(OS_MACOSX) // A javascript code requested to print the current page. The renderer host // have to show to the user the print dialog and returns the selected print // settings. diff --git a/chrome/browser/tab_contents/tab_contents.h b/chrome/browser/tab_contents/tab_contents.h index b90d68b..6e8c8d0 100644 --- a/chrome/browser/tab_contents/tab_contents.h +++ b/chrome/browser/tab_contents/tab_contents.h @@ -40,10 +40,10 @@ #include "webkit/glue/password_form.h" #include "webkit/glue/webpreferences.h" -#if defined(OS_MACOSX) || defined(OS_LINUX) +#if defined(OS_LINUX) // Remove when we've finished porting the supporting classes. #include "chrome/common/temp_scaffolding_stubs.h" -#elif defined(OS_WIN) +#elif defined(OS_WIN) || defined(OS_MACOSX) #include "chrome/browser/printing/print_view_manager.h" #endif diff --git a/chrome/chrome.gyp b/chrome/chrome.gyp index 43588d5..a34abd7 100755 --- a/chrome/chrome.gyp +++ b/chrome/chrome.gyp @@ -2393,6 +2393,11 @@ 'sources': [ 'browser/net/ssl_config_service_manager_pref.cc', ], + 'sources/': [ + # Exclude most of printing. + ['exclude', '^browser/printing/'], + ['include', '^browser/printing/page_(number|range|setup)\\.cc$'], + ], 'conditions': [ ['linux_breakpad==1', { 'sources': [ @@ -2602,10 +2607,6 @@ # Exclude parts of password_manager. ['exclude', '^browser/password_manager/ie7_password\\.cc$'], - # Exclude most of printing. - ['exclude', '^browser/printing/'], - ['include', '^browser/printing/page_(number|range|setup)\\.cc$'], - # Exclude all of rlz. ['exclude', '^browser/rlz/'], @@ -3144,7 +3145,7 @@ 'renderer/print_web_view_helper.cc', 'renderer/print_web_view_helper.h', 'renderer/print_web_view_helper_linux.cc', - 'renderer/print_web_view_helper_mac.cc', + 'renderer/print_web_view_helper_mac.mm', 'renderer/print_web_view_helper_win.cc', 'renderer/render_process.cc', 'renderer/render_process.h', diff --git a/chrome/common/render_messages_internal.h b/chrome/common/render_messages_internal.h index d29d41d..8a48182 100644 --- a/chrome/common/render_messages_internal.h +++ b/chrome/common/render_messages_internal.h @@ -1341,7 +1341,7 @@ IPC_BEGIN_MESSAGES(ViewHost) IPC_SYNC_MESSAGE_ROUTED0_1(ViewHostMsg_GetDefaultPrintSettings, ViewMsg_Print_Params /* default_settings */) -#if defined(OS_WIN) +#if defined(OS_WIN) || defined(OS_MACOSX) // It's the renderer that controls the printing process when it is generated // by javascript. This step is about showing UI to the user to select the // final print settings. The output parameter is the same as @@ -1350,7 +1350,7 @@ IPC_BEGIN_MESSAGES(ViewHost) ViewHostMsg_ScriptedPrint_Params, ViewMsg_PrintPages_Params /* settings choosen by the user*/) -#endif // defined(OS_WIN) +#endif // defined(OS_WIN) || defined(OS_MACOSX) // WebKit and JavaScript error messages to log to the console // or debugger UI. @@ -1526,6 +1526,14 @@ IPC_BEGIN_MESSAGES(ViewHost) int /* fd in browser */) #endif +#if defined(OS_MACOSX) + // Asks the browser create a block of shared memory for the renderer to pass + // NativeMetafile data to the browser. + IPC_SYNC_MESSAGE_ROUTED1_1(ViewHostMsg_AllocatePDFTransport, + size_t /* buffer size */, + base::SharedMemoryHandle /* browser handle */) +#endif + // Provide the browser process with information about the WebCore resource // cache. IPC_MESSAGE_CONTROL1(ViewHostMsg_ResourceTypeStats, diff --git a/chrome/common/temp_scaffolding_stubs.h b/chrome/common/temp_scaffolding_stubs.h index 2971ddd..d4097b8 100644 --- a/chrome/common/temp_scaffolding_stubs.h +++ b/chrome/common/temp_scaffolding_stubs.h @@ -46,6 +46,7 @@ void InstallJankometer(const CommandLine&); //--------------------------------------------------------------------------- // These stubs are for BrowserProcessImpl +#if !defined(OS_MACOSX) class ViewMsg_Print_Params; // Printing is all (obviously) not implemented. @@ -117,6 +118,7 @@ class PrintJobManager { }; } // namespace printing +#endif // !OS_MACOSX //--------------------------------------------------------------------------- // These stubs are for Browser diff --git a/chrome/renderer/mock_render_thread.cc b/chrome/renderer/mock_render_thread.cc index 6445dce..bcb1517 100644 --- a/chrome/renderer/mock_render_thread.cc +++ b/chrome/renderer/mock_render_thread.cc @@ -4,6 +4,7 @@ #include "chrome/renderer/mock_render_thread.h" +#include "base/process_util.h" #include "chrome/common/render_messages.h" #include "ipc/ipc_message_utils.h" #include "testing/gtest/include/gtest/gtest.h" @@ -74,7 +75,7 @@ void MockRenderThread::OnMessageReceived(const IPC::Message& msg) { IPC_MESSAGE_HANDLER(ViewHostMsg_CreateWidget, OnMsgCreateWidget); IPC_MESSAGE_HANDLER(ViewHostMsg_OpenChannelToExtension, OnMsgOpenChannelToExtension); -#if defined(OS_WIN) +#if defined(OS_WIN) || defined(OS_MACOSX) IPC_MESSAGE_HANDLER(ViewHostMsg_GetDefaultPrintSettings, OnGetDefaultPrintSettings); IPC_MESSAGE_HANDLER(ViewHostMsg_ScriptedPrint, @@ -82,8 +83,14 @@ void MockRenderThread::OnMessageReceived(const IPC::Message& msg) { IPC_MESSAGE_HANDLER(ViewHostMsg_DidGetPrintedPagesCount, OnDidGetPrintedPagesCount) IPC_MESSAGE_HANDLER(ViewHostMsg_DidPrintPage, OnDidPrintPage) +#endif +#if defined(OS_WIN) IPC_MESSAGE_HANDLER(ViewHostMsg_DuplicateSection, OnDuplicateSection) #endif +#if defined(OS_MACOSX) + IPC_MESSAGE_HANDLER(ViewHostMsg_AllocatePDFTransport, + OnAllocatePDFTransport) +#endif IPC_MESSAGE_UNHANDLED(handled = false) IPC_END_MESSAGE_MAP_EX() } @@ -103,6 +110,7 @@ void MockRenderThread::OnMsgOpenChannelToExtension( *port_id = 0; } +#if defined(OS_WIN) void MockRenderThread::OnDuplicateSection( base::SharedMemoryHandle renderer_handle, base::SharedMemoryHandle* browser_handle) { @@ -110,6 +118,21 @@ void MockRenderThread::OnDuplicateSection( // separate a browser process from a renderer process. *browser_handle = renderer_handle; } +#endif + +#if defined(OS_MACOSX) +void MockRenderThread::OnAllocatePDFTransport( + size_t buffer_size, base::SharedMemoryHandle* handle) { + base::SharedMemory shared_buf; + shared_buf.Create(L"", false, false, buffer_size); + if (!shared_buf.Map(buffer_size)) { + *handle = base::SharedMemory::NULLHandle(); + NOTREACHED() << "Cannot map PDF transport buffer"; + return; + } + shared_buf.GiveToProcess(base::GetCurrentProcessHandle(), handle); +} +#endif void MockRenderThread::OnGetDefaultPrintSettings(ViewMsg_Print_Params* params) { if (printer_.get()) diff --git a/chrome/renderer/mock_render_thread.h b/chrome/renderer/mock_render_thread.h index eb1a458..d4ed9f7 100644 --- a/chrome/renderer/mock_render_thread.h +++ b/chrome/renderer/mock_render_thread.h @@ -87,8 +87,15 @@ class MockRenderThread : public RenderThreadBase { const std::string& source_extension_id, const std::string& target_extension_id, int* port_id); +#if defined(OS_WIN) void OnDuplicateSection(base::SharedMemoryHandle renderer_handle, base::SharedMemoryHandle* browser_handle); +#endif + +#if defined(OS_MACOSX) + void OnAllocatePDFTransport(size_t buffer_size, + base::SharedMemoryHandle* handle); +#endif // The RenderView expects default print settings. void OnGetDefaultPrintSettings(ViewMsg_Print_Params* setting); diff --git a/chrome/renderer/print_web_view_helper_mac.cc b/chrome/renderer/print_web_view_helper_mac.cc deleted file mode 100644 index fdb61419e..0000000 --- a/chrome/renderer/print_web_view_helper_mac.cc +++ /dev/null @@ -1,28 +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 "chrome/renderer/print_web_view_helper.h" - -#include "base/logging.h" - -using WebKit::WebFrame; - -void PrintWebViewHelper::Print(WebFrame* frame, bool script_initiated) { - // TODO(port): print not implemented - NOTIMPLEMENTED(); -} - -void PrintWebViewHelper::PrintPages(const ViewMsg_PrintPages_Params& params, - WebKit::WebFrame* frame) { - // TODO(port) implement printing - NOTIMPLEMENTED(); -} - -void PrintWebViewHelper::PrintPage(const ViewMsg_PrintPage_Params& params, - const gfx::Size& canvas_size, - WebFrame* frame) { - // TODO(port) implement printing - NOTIMPLEMENTED(); -} - diff --git a/chrome/renderer/print_web_view_helper_mac.mm b/chrome/renderer/print_web_view_helper_mac.mm new file mode 100644 index 0000000..4ac3a47 --- /dev/null +++ b/chrome/renderer/print_web_view_helper_mac.mm @@ -0,0 +1,238 @@ +// 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 "chrome/renderer/print_web_view_helper.h" + +#import <AppKit/AppKit.h> + +#include "app/l10n_util.h" +#include "base/logging.h" +#include "base/process_util.h" +#include "base/scoped_cftyperef.h" +#include "chrome/common/render_messages.h" +#include "chrome/renderer/render_view.h" +#include "grit/generated_resources.h" +#include "printing/native_metafile.h" +#include "webkit/api/public/WebFrame.h" +#include "webkit/api/public/WebCanvas.h" +#include "webkit/api/public/WebConsoleMessage.h" + +using WebKit::WebFrame; +using WebKit::WebCanvas; +using WebKit::WebConsoleMessage; +using WebKit::WebString; + +// TODO(stuartmorgan): There's a fair amount of code here that is duplicated +// from _win that should instead be shared. Once Linux has a real print settings +// implementation, it's likely that this whole method can just be moved to the +// cross-platform file, and the slight divergences resolved/ifdef'd. +void PrintWebViewHelper::Print(WebFrame* frame, bool script_initiated) { + const int kMinSecondsToIgnoreJavascriptInitiatedPrint = 2; + const int kMaxSecondsToIgnoreJavascriptInitiatedPrint = 2 * 60; // 2 Minutes. + + // If still not finished with earlier print request simply ignore. + if (IsPrinting()) + return; + + // TODO(maruel): Move this out of platform specific code. + // Check if there is script repeatedly trying to print and ignore it if too + // frequent. We use exponential wait time so for a page that calls print() in + // a loop the user will need to cancel the print dialog after 2 seconds, 4 + // seconds, 8, ... up to the maximum of 2 minutes. + // This gives the user time to navigate from the page. + if (script_initiated && (user_cancelled_scripted_print_count_ > 0)) { + base::TimeDelta diff = base::Time::Now() - last_cancelled_script_print_; + int min_wait_seconds = std::min( + kMinSecondsToIgnoreJavascriptInitiatedPrint << + (user_cancelled_scripted_print_count_ - 1), + kMaxSecondsToIgnoreJavascriptInitiatedPrint); + if (diff.InSeconds() < min_wait_seconds) { + WebString message(WebString::fromUTF8( + "Ignoring too frequent calls to print().")); + frame->addMessageToConsole(WebConsoleMessage( + WebConsoleMessage::LevelWarning, + message)); + return; + } + } + + // Retrieve the default print settings to calculate the expected number of + // pages. + ViewMsg_Print_Params default_settings; + bool user_cancelled_print = false; + + IPC::SyncMessage* msg = + new ViewHostMsg_GetDefaultPrintSettings(routing_id(), &default_settings); + if (Send(msg)) { + msg = NULL; + if (default_settings.IsEmpty()) { + NOTREACHED() << "Couldn't get default print settings"; + return; + } + + // Continue only if the settings are valid. + if (default_settings.dpi && default_settings.document_cookie) { + int expected_pages_count = 0; + + // Prepare once to calculate the estimated page count. This must be in + // a scope for itself (see comments on PrepareFrameAndViewForPrint). + { + PrepareFrameAndViewForPrint prep_frame_view(default_settings, + frame, + frame->view()); + expected_pages_count = prep_frame_view.GetExpectedPageCount(); + DCHECK(expected_pages_count); + } + + // Ask the browser to show UI to retrieve the final print settings. + ViewMsg_PrintPages_Params print_settings; + + ViewHostMsg_ScriptedPrint_Params params; + + // The routing id is sent across as it is needed to look up the + // corresponding RenderViewHost instance to signal and reset the + // pump messages event. + params.routing_id = routing_id(); + // host_window_ may be NULL at this point if the current window is a popup + // and the print() command has been issued from the parent. The receiver + // of this message has to deal with this. + params.host_window_id = render_view_->host_window(); + params.cookie = default_settings.document_cookie; + params.has_selection = frame->hasSelection(); + params.expected_pages_count = expected_pages_count; + + msg = new ViewHostMsg_ScriptedPrint(params, &print_settings); + // TODO(stuartmorgan): This should use SendAndRunNestedMessageLoop, as on + // Windows, to prevent getting a "hung renderer" dialog, but if we do we + // never actually break out of the nested loop and continue with printing. + // Once that's fixed, switch back to SendAndRunNestedMessageLoop. + //if (render_view_->SendAndRunNestedMessageLoop(msg)) { + if (render_view_->Send(msg)) { + msg = NULL; + + // If the settings are invalid, early quit. + if (print_settings.params.dpi && + print_settings.params.document_cookie) { + if (print_settings.params.selection_only) { + CopyAndPrint(print_settings, frame); + } else { + // TODO: Always copy before printing. + PrintPages(print_settings, frame); + } + + // Reset cancel counter on first successful print. + user_cancelled_scripted_print_count_ = 0; + return; // All went well. + } else { + user_cancelled_print = true; + } + } else { + // Send() failed. + NOTREACHED(); + } + } else { + // Failed to get default settings. + NOTREACHED(); + } + } else { + // Send() failed. + NOTREACHED(); + } + if (script_initiated && user_cancelled_print) { + ++user_cancelled_scripted_print_count_; + last_cancelled_script_print_ = base::Time::Now(); + } + // When |user_cancelled_print| is true, we treat it as success so that + // DidFinishPrinting() won't show any error alert. + // If |user_cancelled_print| is false and we reach here, there must be + // something wrong and hence is not success, DidFinishPrinting() should show + // an error alert. + // In both cases, we have to call DidFinishPrinting() here to release + // printing resources, since we don't need them anymore. + DidFinishPrinting(user_cancelled_print); +} + +void PrintWebViewHelper::PrintPages(const ViewMsg_PrintPages_Params& params, + WebKit::WebFrame* frame) { + PrepareFrameAndViewForPrint prep_frame_view(params.params, + frame, + frame->view()); + int page_count = prep_frame_view.GetExpectedPageCount(); + + Send(new ViewHostMsg_DidGetPrintedPagesCount(routing_id(), + params.params.document_cookie, + page_count)); + if (!page_count) + return; + + const gfx::Size& canvas_size = prep_frame_view.GetPrintCanvasSize(); + ViewMsg_PrintPage_Params page_params; + page_params.params = params.params; + if (params.pages.empty()) { + for (int i = 0; i < page_count; ++i) { + page_params.page_number = i; + PrintPage(page_params, canvas_size, frame); + } + } else { + for (size_t i = 0; i < params.pages.size(); ++i) { + if (params.pages[i] >= page_count) + break; + page_params.page_number = params.pages[i]; + PrintPage(page_params, canvas_size, frame); + } + } +} + +void PrintWebViewHelper::PrintPage(const ViewMsg_PrintPage_Params& params, + const gfx::Size& canvas_size, + WebFrame* frame) { + printing::NativeMetafile metafile; + CGContextRef context = metafile.Init(); + + float scale_factor = frame->getPrintPageShrink(params.page_number); + metafile.StartPage(canvas_size.width(), canvas_size.height(), scale_factor); + + // printPage can create autoreleased references to |canvas|. PDF contexts + // don't write all their data until they are destroyed, so we need to make + // certain that there are no lingering references. + NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; + frame->printPage(params.page_number, context); + [pool release]; + + metafile.FinishPage(); + metafile.Close(); + + // Get the size of the compiled metafile. + ViewHostMsg_DidPrintPage_Params page_params; + page_params.data_size = 0; + page_params.page_number = params.page_number; + page_params.document_cookie = params.params.document_cookie; + page_params.actual_shrink = scale_factor; + base::SharedMemory shared_buf; + + // Ask the browser to create the shared memory for us. + unsigned int buf_size = metafile.GetDataSize(); + base::SharedMemoryHandle shared_mem_handle; + if (Send(new ViewHostMsg_AllocatePDFTransport(routing_id(), buf_size, + &shared_mem_handle))) { + if (base::SharedMemory::IsHandleValid(shared_mem_handle)) { + base::SharedMemory shared_buf(shared_mem_handle, false); + if (shared_buf.Map(buf_size)) { + metafile.GetData(shared_buf.memory(), buf_size); + page_params.data_size = buf_size; + shared_buf.GiveToProcess(base::GetCurrentProcessHandle(), + &(page_params.metafile_data_handle)); + } else { + NOTREACHED() << "Map failed"; + } + } else { + NOTREACHED() << "Browser failed to allocate shared memory"; + } + } else { + NOTREACHED() << "Browser allocation request message failed"; + } + + Send(new ViewHostMsg_DidPrintPage(routing_id(), page_params)); +} + diff --git a/chrome/renderer/render_view_unittest.cc b/chrome/renderer/render_view_unittest.cc index 3bdb362..980ba38 100644 --- a/chrome/renderer/render_view_unittest.cc +++ b/chrome/renderer/render_view_unittest.cc @@ -310,7 +310,7 @@ TEST_F(RenderViewTest, OnSetTextDirection) { // Tests that printing pages work and sending and receiving messages through // that channel all works. TEST_F(RenderViewTest, OnPrintPages) { -#if defined(OS_WIN) +#if defined(OS_WIN) || defined(OS_MACOSX) // Lets simulate a print pages with Hello world. LoadHTML("<body><p>Hello World!</p></body>"); view_->OnPrintPages(); @@ -342,7 +342,7 @@ TEST_F(RenderViewTest, OnPrintPages) { // Duplicate of OnPrintPagesTest only using javascript to print. TEST_F(RenderViewTest, PrintWithJavascript) { -#if defined(OS_WIN) +#if defined(OS_WIN) || defined(OS_MACOSX) // HTML contains a call to window.print() LoadHTML("<body>Hello<script>window.print()</script>World</body>"); |