diff --git a/shell/browser/api/electron_api_web_contents.cc b/shell/browser/api/electron_api_web_contents.cc index 007f19677a..8aaa4f9e3a 100644 --- a/shell/browser/api/electron_api_web_contents.cc +++ b/shell/browser/api/electron_api_web_contents.cc @@ -422,8 +422,11 @@ bool IsDeviceNameValid(const base::string16& device_name) { } base::string16 GetDefaultPrinterAsync() { - base::ScopedBlockingCall scoped_blocking_call(FROM_HERE, - base::BlockingType::MAY_BLOCK); +#if defined(OS_WIN) + // Blocking is needed here because Windows printer drivers are oftentimes + // not thread-safe and have to be accessed on the UI thread. + base::ThreadRestrictions::ScopedAllowIO allow_io; +#endif scoped_refptr print_backend = printing::PrintBackend::CreateInstance( @@ -441,6 +444,29 @@ base::string16 GetDefaultPrinterAsync() { } return base::UTF8ToUTF16(printer_name); } + +// Copied from +// chrome/browser/ui/webui/print_preview/local_printer_handler_default.cc:L36-L54 +scoped_refptr CreatePrinterHandlerTaskRunner() { + // USER_VISIBLE because the result is displayed in the print preview dialog. +#if !defined(OS_WIN) + static constexpr base::TaskTraits kTraits = { + base::MayBlock(), base::TaskPriority::USER_VISIBLE}; +#endif + +#if defined(USE_CUPS) + // CUPS is thread safe. + return base::ThreadPool::CreateTaskRunner(kTraits); +#elif defined(OS_WIN) + // Windows drivers are likely not thread-safe and need to be accessed on the + // UI thread. + return content::GetUIThreadTaskRunner( + {base::MayBlock(), base::TaskPriority::USER_VISIBLE}); +#else + // Be conservative on unsupported platforms. + return base::ThreadPool::CreateSingleThreadTaskRunner(kTraits); +#endif +} #endif struct UserDataLink : public base::SupportsUserData::Data { @@ -591,6 +617,7 @@ WebContents::WebContents(v8::Isolate* isolate, devtools_file_system_indexer_(new DevToolsFileSystemIndexer), file_task_runner_( base::ThreadPool::CreateSequencedTaskRunner({base::MayBlock()})), + print_task_runner_(CreatePrinterHandlerTaskRunner()), weak_factory_(this) { #if BUILDFLAG(ENABLE_ELECTRON_EXTENSIONS) // WebContents created by extension host will have valid ViewType set. @@ -624,6 +651,7 @@ WebContents::WebContents(v8::Isolate* isolate, devtools_file_system_indexer_(new DevToolsFileSystemIndexer), file_task_runner_( base::ThreadPool::CreateSequencedTaskRunner({base::MayBlock()})), + print_task_runner_(CreatePrinterHandlerTaskRunner()), weak_factory_(this) { DCHECK(type != Type::kRemote) << "Can't take ownership of a remote WebContents"; @@ -639,6 +667,7 @@ WebContents::WebContents(v8::Isolate* isolate, devtools_file_system_indexer_(new DevToolsFileSystemIndexer), file_task_runner_( base::ThreadPool::CreateSequencedTaskRunner({base::MayBlock()})), + print_task_runner_(CreatePrinterHandlerTaskRunner()), weak_factory_(this) { // Read options. options.Get("backgroundThrottling", &background_throttling_); @@ -2521,9 +2550,8 @@ void WebContents::Print(gin::Arguments* args) { settings.SetIntKey(printing::kSettingDpiVertical, dpi); } - base::ThreadPool::PostTaskAndReplyWithResult( - FROM_HERE, {base::MayBlock(), base::TaskPriority::USER_BLOCKING}, - base::BindOnce(&GetDefaultPrinterAsync), + print_task_runner_->PostTaskAndReplyWithResult( + FROM_HERE, base::BindOnce(&GetDefaultPrinterAsync), base::BindOnce(&WebContents::OnGetDefaultPrinter, weak_factory_.GetWeakPtr(), std::move(settings), std::move(callback), device_name, silent)); diff --git a/shell/browser/api/electron_api_web_contents.h b/shell/browser/api/electron_api_web_contents.h index 25d0ee354e..da87e5d389 100644 --- a/shell/browser/api/electron_api_web_contents.h +++ b/shell/browser/api/electron_api_web_contents.h @@ -783,6 +783,7 @@ class WebContents : public gin::Wrappable, DevToolsIndexingJobsMap devtools_indexing_jobs_; scoped_refptr file_task_runner_; + scoped_refptr print_task_runner_; // Stores the frame thats currently in fullscreen, nullptr if there is none. content::RenderFrameHost* fullscreen_frame_ = nullptr;