print_preview_message_handler.cc 6.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205
  1. // Copyright (c) 2018 GitHub, Inc.
  2. // Use of this source code is governed by the MIT license that can be
  3. // found in the LICENSE file.
  4. #include "shell/browser/printing/print_preview_message_handler.h"
  5. #include <memory>
  6. #include <utility>
  7. #include "base/bind.h"
  8. #include "base/memory/read_only_shared_memory_region.h"
  9. #include "base/memory/ref_counted.h"
  10. #include "base/memory/ref_counted_memory.h"
  11. #include "base/task/post_task.h"
  12. #include "chrome/browser/browser_process.h"
  13. #include "chrome/browser/printing/print_job_manager.h"
  14. #include "chrome/browser/printing/printer_query.h"
  15. #include "components/printing/browser/print_composite_client.h"
  16. #include "components/printing/browser/print_manager_utils.h"
  17. #include "components/printing/common/print_messages.h"
  18. #include "components/services/print_compositor/public/cpp/print_service_mojo_types.h"
  19. #include "content/public/browser/browser_task_traits.h"
  20. #include "content/public/browser/browser_thread.h"
  21. #include "content/public/browser/render_frame_host.h"
  22. #include "content/public/browser/web_contents.h"
  23. #include "shell/common/gin_helper/locker.h"
  24. #include "third_party/blink/public/common/associated_interfaces/associated_interface_provider.h"
  25. #include "shell/common/node_includes.h"
  26. using content::BrowserThread;
  27. namespace electron {
  28. namespace {
  29. void StopWorker(int document_cookie) {
  30. if (document_cookie <= 0)
  31. return;
  32. scoped_refptr<printing::PrintQueriesQueue> queue =
  33. g_browser_process->print_job_manager()->queue();
  34. std::unique_ptr<printing::PrinterQuery> printer_query =
  35. queue->PopPrinterQuery(document_cookie);
  36. if (printer_query.get()) {
  37. base::PostTask(FROM_HERE, {BrowserThread::IO},
  38. base::BindOnce(&printing::PrinterQuery::StopWorker,
  39. std::move(printer_query)));
  40. }
  41. }
  42. } // namespace
  43. PrintPreviewMessageHandler::PrintPreviewMessageHandler(
  44. content::WebContents* web_contents)
  45. : content::WebContentsObserver(web_contents), weak_ptr_factory_(this) {
  46. DCHECK(web_contents);
  47. }
  48. PrintPreviewMessageHandler::~PrintPreviewMessageHandler() = default;
  49. bool PrintPreviewMessageHandler::OnMessageReceived(
  50. const IPC::Message& message,
  51. content::RenderFrameHost* render_frame_host) {
  52. bool handled = true;
  53. IPC_BEGIN_MESSAGE_MAP_WITH_PARAM(PrintPreviewMessageHandler, message,
  54. render_frame_host)
  55. IPC_MESSAGE_HANDLER(PrintHostMsg_MetafileReadyForPrinting,
  56. OnMetafileReadyForPrinting)
  57. IPC_MESSAGE_UNHANDLED(handled = false)
  58. IPC_END_MESSAGE_MAP()
  59. if (handled)
  60. return true;
  61. handled = true;
  62. IPC_BEGIN_MESSAGE_MAP(PrintPreviewMessageHandler, message)
  63. IPC_MESSAGE_HANDLER(PrintHostMsg_PrintPreviewFailed, OnPrintPreviewFailed)
  64. IPC_MESSAGE_HANDLER(PrintHostMsg_PrintPreviewCancelled,
  65. OnPrintPreviewCancelled)
  66. IPC_MESSAGE_UNHANDLED(handled = false)
  67. IPC_END_MESSAGE_MAP()
  68. return handled;
  69. }
  70. void PrintPreviewMessageHandler::OnMetafileReadyForPrinting(
  71. content::RenderFrameHost* render_frame_host,
  72. const PrintHostMsg_DidPreviewDocument_Params& params,
  73. const PrintHostMsg_PreviewIds& ids) {
  74. // Always try to stop the worker.
  75. StopWorker(params.document_cookie);
  76. const PrintHostMsg_DidPrintContent_Params& content = params.content;
  77. if (!content.metafile_data_region.IsValid() ||
  78. params.expected_pages_count <= 0) {
  79. RejectPromise(ids.request_id);
  80. return;
  81. }
  82. if (printing::IsOopifEnabled()) {
  83. auto* client =
  84. printing::PrintCompositeClient::FromWebContents(web_contents());
  85. DCHECK(client);
  86. client->DoCompositeDocumentToPdf(
  87. params.document_cookie, render_frame_host, content,
  88. base::BindOnce(&PrintPreviewMessageHandler::OnCompositePdfDocumentDone,
  89. weak_ptr_factory_.GetWeakPtr(), ids));
  90. } else {
  91. ResolvePromise(ids.request_id,
  92. base::RefCountedSharedMemoryMapping::CreateFromWholeRegion(
  93. content.metafile_data_region));
  94. }
  95. }
  96. void PrintPreviewMessageHandler::OnCompositePdfDocumentDone(
  97. const PrintHostMsg_PreviewIds& ids,
  98. printing::mojom::PrintCompositor::Status status,
  99. base::ReadOnlySharedMemoryRegion region) {
  100. DCHECK_CURRENTLY_ON(BrowserThread::UI);
  101. if (status != printing::mojom::PrintCompositor::Status::kSuccess) {
  102. DLOG(ERROR) << "Compositing pdf failed with error " << status;
  103. RejectPromise(ids.request_id);
  104. return;
  105. }
  106. ResolvePromise(
  107. ids.request_id,
  108. base::RefCountedSharedMemoryMapping::CreateFromWholeRegion(region));
  109. }
  110. void PrintPreviewMessageHandler::OnPrintPreviewFailed(
  111. int document_cookie,
  112. const PrintHostMsg_PreviewIds& ids) {
  113. StopWorker(document_cookie);
  114. RejectPromise(ids.request_id);
  115. }
  116. void PrintPreviewMessageHandler::OnPrintPreviewCancelled(
  117. int document_cookie,
  118. const PrintHostMsg_PreviewIds& ids) {
  119. StopWorker(document_cookie);
  120. RejectPromise(ids.request_id);
  121. }
  122. void PrintPreviewMessageHandler::PrintToPDF(
  123. base::DictionaryValue options,
  124. gin_helper::Promise<v8::Local<v8::Value>> promise) {
  125. int request_id;
  126. options.GetInteger(printing::kPreviewRequestID, &request_id);
  127. promise_map_.emplace(request_id, std::move(promise));
  128. auto* focused_frame = web_contents()->GetFocusedFrame();
  129. auto* rfh = focused_frame && focused_frame->HasSelection()
  130. ? focused_frame
  131. : web_contents()->GetMainFrame();
  132. if (!print_render_frame_.is_bound())
  133. rfh->GetRemoteAssociatedInterfaces()->GetInterface(&print_render_frame_);
  134. print_render_frame_->PrintPreview(options.Clone());
  135. }
  136. gin_helper::Promise<v8::Local<v8::Value>>
  137. PrintPreviewMessageHandler::GetPromise(int request_id) {
  138. auto it = promise_map_.find(request_id);
  139. DCHECK(it != promise_map_.end());
  140. gin_helper::Promise<v8::Local<v8::Value>> promise = std::move(it->second);
  141. promise_map_.erase(it);
  142. return promise;
  143. }
  144. void PrintPreviewMessageHandler::ResolvePromise(
  145. int request_id,
  146. scoped_refptr<base::RefCountedMemory> data_bytes) {
  147. DCHECK_CURRENTLY_ON(BrowserThread::UI);
  148. gin_helper::Promise<v8::Local<v8::Value>> promise = GetPromise(request_id);
  149. v8::Isolate* isolate = promise.isolate();
  150. gin_helper::Locker locker(isolate);
  151. v8::HandleScope handle_scope(isolate);
  152. v8::Context::Scope context_scope(
  153. v8::Local<v8::Context>::New(isolate, promise.GetContext()));
  154. v8::Local<v8::Value> buffer =
  155. node::Buffer::Copy(isolate,
  156. reinterpret_cast<const char*>(data_bytes->front()),
  157. data_bytes->size())
  158. .ToLocalChecked();
  159. promise.Resolve(buffer);
  160. }
  161. void PrintPreviewMessageHandler::RejectPromise(int request_id) {
  162. DCHECK_CURRENTLY_ON(BrowserThread::UI);
  163. gin_helper::Promise<v8::Local<v8::Value>> promise = GetPromise(request_id);
  164. promise.RejectWithErrorMessage("Failed to generate PDF");
  165. }
  166. WEB_CONTENTS_USER_DATA_KEY_IMPL(PrintPreviewMessageHandler)
  167. } // namespace electron