diff options
-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>"); |