mirror of
				https://bitbucket.org/chromiumembedded/cef
				synced 2025-06-05 21:39:12 +02:00 
			
		
		
		
	
		
			
				
	
	
		
			596 lines
		
	
	
		
			20 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			596 lines
		
	
	
		
			20 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
// Copyright 2013 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 "libcef/browser/printing/print_view_manager_base.h"
 | 
						|
 | 
						|
#include <memory>
 | 
						|
#include <utility>
 | 
						|
 | 
						|
#include "base/auto_reset.h"
 | 
						|
#include "base/bind.h"
 | 
						|
#include "base/location.h"
 | 
						|
#include "base/memory/ptr_util.h"
 | 
						|
#include "base/memory/shared_memory.h"
 | 
						|
#include "base/message_loop/message_loop.h"
 | 
						|
#include "base/run_loop.h"
 | 
						|
#include "base/single_thread_task_runner.h"
 | 
						|
#include "base/strings/utf_string_conversions.h"
 | 
						|
#include "base/task_scheduler/post_task.h"
 | 
						|
#include "base/threading/thread_task_runner_handle.h"
 | 
						|
#include "base/timer/timer.h"
 | 
						|
#include "build/build_config.h"
 | 
						|
#include "chrome/browser/browser_process.h"
 | 
						|
#include "chrome/browser/chrome_notification_types.h"
 | 
						|
#include "chrome/browser/printing/print_job.h"
 | 
						|
#include "chrome/browser/printing/print_job_manager.h"
 | 
						|
#include "chrome/browser/printing/printer_query.h"
 | 
						|
#include "chrome/browser/profiles/profile.h"
 | 
						|
#include "chrome/common/pref_names.h"
 | 
						|
#include "chrome/grit/generated_resources.h"
 | 
						|
#include "components/prefs/pref_service.h"
 | 
						|
#include "components/printing/browser/print_composite_client.h"
 | 
						|
#include "components/printing/browser/print_manager_utils.h"
 | 
						|
#include "components/printing/common/print_messages.h"
 | 
						|
#include "components/printing/service/public/cpp/pdf_service_mojo_types.h"
 | 
						|
#include "components/printing/service/public/cpp/pdf_service_mojo_utils.h"
 | 
						|
#include "content/public/browser/browser_thread.h"
 | 
						|
#include "content/public/browser/notification_details.h"
 | 
						|
#include "content/public/browser/notification_service.h"
 | 
						|
#include "content/public/browser/notification_source.h"
 | 
						|
#include "content/public/browser/render_frame_host.h"
 | 
						|
#include "content/public/browser/render_process_host.h"
 | 
						|
#include "content/public/browser/render_view_host.h"
 | 
						|
#include "content/public/browser/web_contents.h"
 | 
						|
#include "mojo/public/cpp/system/buffer.h"
 | 
						|
#include "printing/features/features.h"
 | 
						|
#include "printing/pdf_metafile_skia.h"
 | 
						|
#include "printing/print_settings.h"
 | 
						|
#include "printing/printed_document.h"
 | 
						|
#include "ui/base/l10n/l10n_util.h"
 | 
						|
 | 
						|
#if defined(OS_WIN)
 | 
						|
#include "base/command_line.h"
 | 
						|
#include "chrome/common/chrome_features.h"
 | 
						|
#endif
 | 
						|
 | 
						|
using base::TimeDelta;
 | 
						|
using content::BrowserThread;
 | 
						|
 | 
						|
namespace printing {
 | 
						|
 | 
						|
CefPrintViewManagerBase::CefPrintViewManagerBase(
 | 
						|
    content::WebContents* web_contents)
 | 
						|
    : PrintManager(web_contents),
 | 
						|
      printing_rfh_(nullptr),
 | 
						|
      printing_succeeded_(false),
 | 
						|
      inside_inner_message_loop_(false),
 | 
						|
      queue_(g_browser_process->print_job_manager()->queue()),
 | 
						|
      weak_ptr_factory_(this) {
 | 
						|
  DCHECK(queue_.get());
 | 
						|
  Profile* profile =
 | 
						|
      Profile::FromBrowserContext(web_contents->GetBrowserContext());
 | 
						|
  printing_enabled_.Init(
 | 
						|
      prefs::kPrintingEnabled, profile->GetPrefs(),
 | 
						|
      base::Bind(&CefPrintViewManagerBase::UpdatePrintingEnabled,
 | 
						|
                 weak_ptr_factory_.GetWeakPtr()));
 | 
						|
}
 | 
						|
 | 
						|
CefPrintViewManagerBase::~CefPrintViewManagerBase() {
 | 
						|
  ReleasePrinterQuery();
 | 
						|
  DisconnectFromCurrentPrintJob();
 | 
						|
}
 | 
						|
 | 
						|
#if BUILDFLAG(ENABLE_BASIC_PRINTING)
 | 
						|
bool CefPrintViewManagerBase::PrintNow(content::RenderFrameHost* rfh) {
 | 
						|
  DisconnectFromCurrentPrintJob();
 | 
						|
 | 
						|
  SetPrintingRFH(rfh);
 | 
						|
  int32_t id = rfh->GetRoutingID();
 | 
						|
  return PrintNowInternal(rfh, std::make_unique<PrintMsg_PrintPages>(id));
 | 
						|
}
 | 
						|
#endif
 | 
						|
 | 
						|
void CefPrintViewManagerBase::PrintDocument(
 | 
						|
    PrintedDocument* document,
 | 
						|
    const scoped_refptr<base::RefCountedBytes>& print_data,
 | 
						|
    const gfx::Size& page_size,
 | 
						|
    const gfx::Rect& content_area,
 | 
						|
    const gfx::Point& offsets) {
 | 
						|
#if defined(OS_WIN)
 | 
						|
  if (PrintedDocument::HasDebugDumpPath())
 | 
						|
    document->DebugDumpData(print_data.get(), FILE_PATH_LITERAL(".pdf"));
 | 
						|
 | 
						|
  const auto& settings = document->settings();
 | 
						|
  if (settings.printer_is_textonly()) {
 | 
						|
    print_job_->StartPdfToTextConversion(print_data, page_size);
 | 
						|
  } else if ((settings.printer_is_ps2() || settings.printer_is_ps3()) &&
 | 
						|
             !base::FeatureList::IsEnabled(
 | 
						|
                 features::kDisablePostScriptPrinting)) {
 | 
						|
    print_job_->StartPdfToPostScriptConversion(
 | 
						|
        print_data, content_area, offsets, settings.printer_is_ps2());
 | 
						|
  } else {
 | 
						|
    // TODO(thestig): Figure out why rendering text with GDI results in random
 | 
						|
    // missing characters for some users. https://crbug.com/658606
 | 
						|
    // Update : The missing letters seem to have been caused by the same
 | 
						|
    // problem as https://crbug.com/659604 which was resolved. GDI printing
 | 
						|
    // seems to work with the fix for this bug applied.
 | 
						|
    bool print_text_with_gdi =
 | 
						|
        settings.print_text_with_gdi() && !settings.printer_is_xps() &&
 | 
						|
        base::FeatureList::IsEnabled(features::kGdiTextPrinting);
 | 
						|
    print_job_->StartPdfToEmfConversion(print_data, page_size, content_area,
 | 
						|
                                        print_text_with_gdi);
 | 
						|
  }
 | 
						|
#else
 | 
						|
  std::unique_ptr<PdfMetafileSkia> metafile =
 | 
						|
      std::make_unique<PdfMetafileSkia>();
 | 
						|
  CHECK(metafile->InitFromData(print_data->front(), print_data->size()));
 | 
						|
 | 
						|
  // Update the rendered document. It will send notifications to the listener.
 | 
						|
  document->SetDocument(std::move(metafile), page_size, content_area);
 | 
						|
  ShouldQuitFromInnerMessageLoop();
 | 
						|
#endif
 | 
						|
}
 | 
						|
 | 
						|
void CefPrintViewManagerBase::UpdatePrintingEnabled() {
 | 
						|
  DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
 | 
						|
  // The Unretained() is safe because ForEachFrame() is synchronous.
 | 
						|
  web_contents()->ForEachFrame(base::BindRepeating(
 | 
						|
      &CefPrintViewManagerBase::SendPrintingEnabled, base::Unretained(this),
 | 
						|
      printing_enabled_.GetValue()));
 | 
						|
}
 | 
						|
 | 
						|
void CefPrintViewManagerBase::NavigationStopped() {
 | 
						|
  // Cancel the current job, wait for the worker to finish.
 | 
						|
  TerminatePrintJob(true);
 | 
						|
}
 | 
						|
 | 
						|
base::string16 CefPrintViewManagerBase::RenderSourceName() {
 | 
						|
  base::string16 name(web_contents()->GetTitle());
 | 
						|
  if (name.empty())
 | 
						|
    name = l10n_util::GetStringUTF16(IDS_DEFAULT_PRINT_DOCUMENT_TITLE);
 | 
						|
  return name;
 | 
						|
}
 | 
						|
 | 
						|
void CefPrintViewManagerBase::OnDidGetPrintedPagesCount(int cookie,
 | 
						|
                                                        int number_pages) {
 | 
						|
  PrintManager::OnDidGetPrintedPagesCount(cookie, number_pages);
 | 
						|
  OpportunisticallyCreatePrintJob(cookie);
 | 
						|
}
 | 
						|
 | 
						|
PrintedDocument* CefPrintViewManagerBase::GetDocument(int cookie) {
 | 
						|
  if (!OpportunisticallyCreatePrintJob(cookie))
 | 
						|
    return nullptr;
 | 
						|
 | 
						|
  PrintedDocument* document = print_job_->document();
 | 
						|
  if (!document || cookie != document->cookie()) {
 | 
						|
    // Out of sync. It may happen since we are completely asynchronous. Old
 | 
						|
    // spurious messages can be received if one of the processes is overloaded.
 | 
						|
    return nullptr;
 | 
						|
  }
 | 
						|
  return document;
 | 
						|
}
 | 
						|
 | 
						|
void CefPrintViewManagerBase::OnComposePdfDone(
 | 
						|
    const PrintHostMsg_DidPrintDocument_Params& params,
 | 
						|
    mojom::PdfCompositor::Status status,
 | 
						|
    mojo::ScopedSharedBufferHandle handle) {
 | 
						|
  DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
 | 
						|
  if (status != mojom::PdfCompositor::Status::SUCCESS) {
 | 
						|
    DLOG(ERROR) << "Compositing pdf failed with error " << status;
 | 
						|
    return;
 | 
						|
  }
 | 
						|
 | 
						|
  PrintedDocument* document = print_job_->document();
 | 
						|
  if (!document)
 | 
						|
    return;
 | 
						|
 | 
						|
  std::unique_ptr<base::SharedMemory> shared_buf =
 | 
						|
      GetShmFromMojoHandle(std::move(handle));
 | 
						|
  scoped_refptr<base::RefCountedBytes> bytes =
 | 
						|
      base::MakeRefCounted<base::RefCountedBytes>(
 | 
						|
          reinterpret_cast<const unsigned char*>(shared_buf->memory()),
 | 
						|
          shared_buf->mapped_size());
 | 
						|
  PrintDocument(document, bytes, params.page_size, params.content_area,
 | 
						|
                params.physical_offsets);
 | 
						|
}
 | 
						|
 | 
						|
void CefPrintViewManagerBase::OnDidPrintDocument(
 | 
						|
    content::RenderFrameHost* render_frame_host,
 | 
						|
    const PrintHostMsg_DidPrintDocument_Params& params) {
 | 
						|
  PrintedDocument* document = GetDocument(params.document_cookie);
 | 
						|
  if (!document)
 | 
						|
    return;
 | 
						|
 | 
						|
  const PrintHostMsg_DidPrintContent_Params& content = params.content;
 | 
						|
  if (!base::SharedMemory::IsHandleValid(content.metafile_data_handle)) {
 | 
						|
    NOTREACHED() << "invalid memory handle";
 | 
						|
    web_contents()->Stop();
 | 
						|
    return;
 | 
						|
  }
 | 
						|
 | 
						|
  auto* client = PrintCompositeClient::FromWebContents(web_contents());
 | 
						|
  if (IsOopifEnabled() && !client->for_preview() &&
 | 
						|
      document->settings().is_modifiable()) {
 | 
						|
    client->DoCompositeDocumentToPdf(
 | 
						|
        params.document_cookie, render_frame_host, content.metafile_data_handle,
 | 
						|
        content.data_size, content.subframe_content_info,
 | 
						|
        base::BindOnce(&CefPrintViewManagerBase::OnComposePdfDone,
 | 
						|
                       weak_ptr_factory_.GetWeakPtr(), params));
 | 
						|
    return;
 | 
						|
  }
 | 
						|
 | 
						|
  auto shared_buf =
 | 
						|
      std::make_unique<base::SharedMemory>(content.metafile_data_handle, true);
 | 
						|
  if (!shared_buf->Map(content.data_size)) {
 | 
						|
    NOTREACHED() << "couldn't map";
 | 
						|
    web_contents()->Stop();
 | 
						|
    return;
 | 
						|
  }
 | 
						|
  scoped_refptr<base::RefCountedBytes> bytes =
 | 
						|
      base::MakeRefCounted<base::RefCountedBytes>(
 | 
						|
          reinterpret_cast<const unsigned char*>(shared_buf->memory()),
 | 
						|
          content.data_size);
 | 
						|
  PrintDocument(document, bytes, params.page_size, params.content_area,
 | 
						|
                params.physical_offsets);
 | 
						|
}
 | 
						|
 | 
						|
void CefPrintViewManagerBase::OnPrintingFailed(int cookie) {
 | 
						|
  PrintManager::OnPrintingFailed(cookie);
 | 
						|
 | 
						|
  ReleasePrinterQuery();
 | 
						|
 | 
						|
  content::NotificationService::current()->Notify(
 | 
						|
      chrome::NOTIFICATION_PRINT_JOB_RELEASED,
 | 
						|
      content::Source<content::WebContents>(web_contents()),
 | 
						|
      content::NotificationService::NoDetails());
 | 
						|
}
 | 
						|
 | 
						|
void CefPrintViewManagerBase::OnShowInvalidPrinterSettingsError() {}
 | 
						|
 | 
						|
void CefPrintViewManagerBase::DidStartLoading() {
 | 
						|
  UpdatePrintingEnabled();
 | 
						|
}
 | 
						|
 | 
						|
void CefPrintViewManagerBase::RenderFrameDeleted(
 | 
						|
    content::RenderFrameHost* render_frame_host) {
 | 
						|
  // Terminates or cancels the print job if one was pending.
 | 
						|
  if (render_frame_host != printing_rfh_)
 | 
						|
    return;
 | 
						|
 | 
						|
  printing_rfh_ = nullptr;
 | 
						|
 | 
						|
  PrintManager::PrintingRenderFrameDeleted();
 | 
						|
  ReleasePrinterQuery();
 | 
						|
 | 
						|
  if (!print_job_.get())
 | 
						|
    return;
 | 
						|
 | 
						|
  scoped_refptr<PrintedDocument> document(print_job_->document());
 | 
						|
  if (document.get()) {
 | 
						|
    // If IsComplete() returns false, the document isn't completely rendered.
 | 
						|
    // Since our renderer is gone, there's nothing to do, cancel it. Otherwise,
 | 
						|
    // the print job may finish without problem.
 | 
						|
    TerminatePrintJob(!document->IsComplete());
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
bool CefPrintViewManagerBase::OnMessageReceived(
 | 
						|
    const IPC::Message& message,
 | 
						|
    content::RenderFrameHost* render_frame_host) {
 | 
						|
  bool handled = true;
 | 
						|
  IPC_BEGIN_MESSAGE_MAP_WITH_PARAM(CefPrintViewManagerBase, message,
 | 
						|
                                   render_frame_host)
 | 
						|
    IPC_MESSAGE_HANDLER(PrintHostMsg_DidPrintDocument, OnDidPrintDocument)
 | 
						|
    IPC_MESSAGE_UNHANDLED(handled = false)
 | 
						|
  IPC_END_MESSAGE_MAP()
 | 
						|
  if (handled)
 | 
						|
    return true;
 | 
						|
 | 
						|
  handled = true;
 | 
						|
  IPC_BEGIN_MESSAGE_MAP(CefPrintViewManagerBase, message)
 | 
						|
    IPC_MESSAGE_HANDLER(PrintHostMsg_ShowInvalidPrinterSettingsError,
 | 
						|
                        OnShowInvalidPrinterSettingsError)
 | 
						|
    IPC_MESSAGE_UNHANDLED(handled = false)
 | 
						|
  IPC_END_MESSAGE_MAP()
 | 
						|
  return handled || PrintManager::OnMessageReceived(message, render_frame_host);
 | 
						|
}
 | 
						|
 | 
						|
void CefPrintViewManagerBase::Observe(
 | 
						|
    int type,
 | 
						|
    const content::NotificationSource& source,
 | 
						|
    const content::NotificationDetails& details) {
 | 
						|
  DCHECK_EQ(chrome::NOTIFICATION_PRINT_JOB_EVENT, type);
 | 
						|
  OnNotifyPrintJobEvent(*content::Details<JobEventDetails>(details).ptr());
 | 
						|
}
 | 
						|
 | 
						|
void CefPrintViewManagerBase::OnNotifyPrintJobEvent(
 | 
						|
    const JobEventDetails& event_details) {
 | 
						|
  switch (event_details.type()) {
 | 
						|
    case JobEventDetails::FAILED: {
 | 
						|
      TerminatePrintJob(true);
 | 
						|
 | 
						|
      content::NotificationService::current()->Notify(
 | 
						|
          chrome::NOTIFICATION_PRINT_JOB_RELEASED,
 | 
						|
          content::Source<content::WebContents>(web_contents()),
 | 
						|
          content::NotificationService::NoDetails());
 | 
						|
      break;
 | 
						|
    }
 | 
						|
    case JobEventDetails::USER_INIT_DONE:
 | 
						|
    case JobEventDetails::DEFAULT_INIT_DONE:
 | 
						|
    case JobEventDetails::USER_INIT_CANCELED: {
 | 
						|
      NOTREACHED();
 | 
						|
      break;
 | 
						|
    }
 | 
						|
    case JobEventDetails::ALL_PAGES_REQUESTED: {
 | 
						|
      ShouldQuitFromInnerMessageLoop();
 | 
						|
      break;
 | 
						|
    }
 | 
						|
    case JobEventDetails::NEW_DOC:
 | 
						|
#if defined(OS_WIN)
 | 
						|
    case JobEventDetails::PAGE_DONE:
 | 
						|
#endif
 | 
						|
    case JobEventDetails::DOC_DONE: {
 | 
						|
      // Don't care about the actual printing process.
 | 
						|
      break;
 | 
						|
    }
 | 
						|
    case JobEventDetails::JOB_DONE: {
 | 
						|
      // Printing is done, we don't need it anymore.
 | 
						|
      // print_job_->is_job_pending() may still be true, depending on the order
 | 
						|
      // of object registration.
 | 
						|
      printing_succeeded_ = true;
 | 
						|
      ReleasePrintJob();
 | 
						|
 | 
						|
      content::NotificationService::current()->Notify(
 | 
						|
          chrome::NOTIFICATION_PRINT_JOB_RELEASED,
 | 
						|
          content::Source<content::WebContents>(web_contents()),
 | 
						|
          content::NotificationService::NoDetails());
 | 
						|
      break;
 | 
						|
    }
 | 
						|
    default: {
 | 
						|
      NOTREACHED();
 | 
						|
      break;
 | 
						|
    }
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
bool CefPrintViewManagerBase::RenderAllMissingPagesNow() {
 | 
						|
  if (!print_job_.get() || !print_job_->is_job_pending())
 | 
						|
    return false;
 | 
						|
 | 
						|
  // We can't print if there is no renderer.
 | 
						|
  if (!web_contents() || !web_contents()->GetRenderViewHost() ||
 | 
						|
      !web_contents()->GetRenderViewHost()->IsRenderViewLive()) {
 | 
						|
    return false;
 | 
						|
  }
 | 
						|
 | 
						|
  // Is the document already complete?
 | 
						|
  if (print_job_->document() && print_job_->document()->IsComplete()) {
 | 
						|
    printing_succeeded_ = true;
 | 
						|
    return true;
 | 
						|
  }
 | 
						|
 | 
						|
  // WebContents is either dying or a second consecutive request to print
 | 
						|
  // happened before the first had time to finish. We need to render all the
 | 
						|
  // pages in an hurry if a print_job_ is still pending. No need to wait for it
 | 
						|
  // to actually spool the pages, only to have the renderer generate them. Run
 | 
						|
  // a message loop until we get our signal that the print job is satisfied.
 | 
						|
  // PrintJob will send a ALL_PAGES_REQUESTED after having received all the
 | 
						|
  // pages it needs. RunLoop::QuitCurrentWhenIdleDeprecated() will be called as
 | 
						|
  // soon as print_job_->document()->IsComplete() is true on either
 | 
						|
  // ALL_PAGES_REQUESTED or in DidPrintDocument(). The check is done in
 | 
						|
  // ShouldQuitFromInnerMessageLoop().
 | 
						|
  // BLOCKS until all the pages are received. (Need to enable recursive task)
 | 
						|
  if (!RunInnerMessageLoop()) {
 | 
						|
    // This function is always called from DisconnectFromCurrentPrintJob() so we
 | 
						|
    // know that the job will be stopped/canceled in any case.
 | 
						|
    return false;
 | 
						|
  }
 | 
						|
  return true;
 | 
						|
}
 | 
						|
 | 
						|
void CefPrintViewManagerBase::ShouldQuitFromInnerMessageLoop() {
 | 
						|
  // Look at the reason.
 | 
						|
  DCHECK(print_job_->document());
 | 
						|
  if (print_job_->document() && print_job_->document()->IsComplete() &&
 | 
						|
      inside_inner_message_loop_) {
 | 
						|
    // We are in a message loop created by RenderAllMissingPagesNow. Quit from
 | 
						|
    // it.
 | 
						|
    base::RunLoop::QuitCurrentWhenIdleDeprecated();
 | 
						|
    inside_inner_message_loop_ = false;
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
bool CefPrintViewManagerBase::CreateNewPrintJob(PrintJobWorkerOwner* job) {
 | 
						|
  DCHECK(!inside_inner_message_loop_);
 | 
						|
 | 
						|
  // Disconnect the current |print_job_|.
 | 
						|
  DisconnectFromCurrentPrintJob();
 | 
						|
 | 
						|
  // We can't print if there is no renderer.
 | 
						|
  if (!web_contents()->GetRenderViewHost() ||
 | 
						|
      !web_contents()->GetRenderViewHost()->IsRenderViewLive()) {
 | 
						|
    return false;
 | 
						|
  }
 | 
						|
 | 
						|
  // Ask the renderer to generate the print preview, create the print preview
 | 
						|
  // view and switch to it, initialize the printer and show the print dialog.
 | 
						|
  DCHECK(!print_job_.get());
 | 
						|
  DCHECK(job);
 | 
						|
  if (!job)
 | 
						|
    return false;
 | 
						|
 | 
						|
  print_job_ = new PrintJob();
 | 
						|
  print_job_->Initialize(job, RenderSourceName(), number_pages_);
 | 
						|
  registrar_.Add(this, chrome::NOTIFICATION_PRINT_JOB_EVENT,
 | 
						|
                 content::Source<PrintJob>(print_job_.get()));
 | 
						|
  printing_succeeded_ = false;
 | 
						|
  return true;
 | 
						|
}
 | 
						|
 | 
						|
void CefPrintViewManagerBase::DisconnectFromCurrentPrintJob() {
 | 
						|
  // Make sure all the necessary rendered page are done. Don't bother with the
 | 
						|
  // return value.
 | 
						|
  bool result = RenderAllMissingPagesNow();
 | 
						|
 | 
						|
  // Verify that assertion.
 | 
						|
  if (print_job_.get() && print_job_->document() &&
 | 
						|
      !print_job_->document()->IsComplete()) {
 | 
						|
    DCHECK(!result);
 | 
						|
    // That failed.
 | 
						|
    TerminatePrintJob(true);
 | 
						|
  } else {
 | 
						|
    // DO NOT wait for the job to finish.
 | 
						|
    ReleasePrintJob();
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
void CefPrintViewManagerBase::TerminatePrintJob(bool cancel) {
 | 
						|
  if (!print_job_.get())
 | 
						|
    return;
 | 
						|
 | 
						|
  if (cancel) {
 | 
						|
    // We don't need the metafile data anymore because the printing is canceled.
 | 
						|
    print_job_->Cancel();
 | 
						|
    inside_inner_message_loop_ = false;
 | 
						|
  } else {
 | 
						|
    DCHECK(!inside_inner_message_loop_);
 | 
						|
    DCHECK(!print_job_->document() || print_job_->document()->IsComplete());
 | 
						|
 | 
						|
    // WebContents is either dying or navigating elsewhere. We need to render
 | 
						|
    // all the pages in an hurry if a print job is still pending. This does the
 | 
						|
    // trick since it runs a blocking message loop:
 | 
						|
    print_job_->Stop();
 | 
						|
  }
 | 
						|
  ReleasePrintJob();
 | 
						|
}
 | 
						|
 | 
						|
void CefPrintViewManagerBase::ReleasePrintJob() {
 | 
						|
  content::RenderFrameHost* rfh = printing_rfh_;
 | 
						|
  printing_rfh_ = nullptr;
 | 
						|
 | 
						|
  if (!print_job_.get())
 | 
						|
    return;
 | 
						|
 | 
						|
  if (rfh) {
 | 
						|
    auto msg = std::make_unique<PrintMsg_PrintingDone>(rfh->GetRoutingID(),
 | 
						|
                                                       printing_succeeded_);
 | 
						|
    rfh->Send(msg.release());
 | 
						|
  }
 | 
						|
 | 
						|
  registrar_.Remove(this, chrome::NOTIFICATION_PRINT_JOB_EVENT,
 | 
						|
                    content::Source<PrintJob>(print_job_.get()));
 | 
						|
  // Don't close the worker thread.
 | 
						|
  print_job_ = nullptr;
 | 
						|
}
 | 
						|
 | 
						|
bool CefPrintViewManagerBase::RunInnerMessageLoop() {
 | 
						|
  // This value may actually be too low:
 | 
						|
  //
 | 
						|
  // - If we're looping because of printer settings initialization, the premise
 | 
						|
  // here is that some poor users have their print server away on a VPN over a
 | 
						|
  // slow connection. In this situation, the simple fact of opening the printer
 | 
						|
  // can be dead slow. On the other side, we don't want to die infinitely for a
 | 
						|
  // real network error. Give the printer 60 seconds to comply.
 | 
						|
  //
 | 
						|
  // - If we're looping because of renderer page generation, the renderer could
 | 
						|
  // be CPU bound, the page overly complex/large or the system just
 | 
						|
  // memory-bound.
 | 
						|
  static const int kPrinterSettingsTimeout = 60000;
 | 
						|
  base::OneShotTimer quit_timer;
 | 
						|
  base::RunLoop run_loop;
 | 
						|
  quit_timer.Start(FROM_HERE,
 | 
						|
                   TimeDelta::FromMilliseconds(kPrinterSettingsTimeout),
 | 
						|
                   run_loop.QuitWhenIdleClosure());
 | 
						|
 | 
						|
  inside_inner_message_loop_ = true;
 | 
						|
 | 
						|
  // Need to enable recursive task.
 | 
						|
  {
 | 
						|
    base::MessageLoop::ScopedNestableTaskAllower allow(
 | 
						|
        base::MessageLoop::current());
 | 
						|
    run_loop.Run();
 | 
						|
  }
 | 
						|
 | 
						|
  bool success = true;
 | 
						|
  if (inside_inner_message_loop_) {
 | 
						|
    // Ok we timed out. That's sad.
 | 
						|
    inside_inner_message_loop_ = false;
 | 
						|
    success = false;
 | 
						|
  }
 | 
						|
 | 
						|
  return success;
 | 
						|
}
 | 
						|
 | 
						|
bool CefPrintViewManagerBase::OpportunisticallyCreatePrintJob(int cookie) {
 | 
						|
  if (print_job_.get())
 | 
						|
    return true;
 | 
						|
 | 
						|
  if (!cookie) {
 | 
						|
    // Out of sync. It may happens since we are completely asynchronous. Old
 | 
						|
    // spurious message can happen if one of the processes is overloaded.
 | 
						|
    return false;
 | 
						|
  }
 | 
						|
 | 
						|
  // The job was initiated by a script. Time to get the corresponding worker
 | 
						|
  // thread.
 | 
						|
  scoped_refptr<PrinterQuery> queued_query = queue_->PopPrinterQuery(cookie);
 | 
						|
  if (!queued_query.get()) {
 | 
						|
    NOTREACHED();
 | 
						|
    return false;
 | 
						|
  }
 | 
						|
 | 
						|
  if (!CreateNewPrintJob(queued_query.get())) {
 | 
						|
    // Don't kill anything.
 | 
						|
    return false;
 | 
						|
  }
 | 
						|
 | 
						|
  // Settings are already loaded. Go ahead. This will set
 | 
						|
  // print_job_->is_job_pending() to true.
 | 
						|
  print_job_->StartPrinting();
 | 
						|
  return true;
 | 
						|
}
 | 
						|
 | 
						|
bool CefPrintViewManagerBase::PrintNowInternal(
 | 
						|
    content::RenderFrameHost* rfh,
 | 
						|
    std::unique_ptr<IPC::Message> message) {
 | 
						|
  // Don't print / print preview interstitials or crashed tabs.
 | 
						|
  if (web_contents()->ShowingInterstitialPage() || web_contents()->IsCrashed())
 | 
						|
    return false;
 | 
						|
  return rfh->Send(message.release());
 | 
						|
}
 | 
						|
 | 
						|
void CefPrintViewManagerBase::SetPrintingRFH(content::RenderFrameHost* rfh) {
 | 
						|
  DCHECK(!printing_rfh_);
 | 
						|
  printing_rfh_ = rfh;
 | 
						|
}
 | 
						|
 | 
						|
void CefPrintViewManagerBase::ReleasePrinterQuery() {
 | 
						|
  if (!cookie_)
 | 
						|
    return;
 | 
						|
 | 
						|
  int cookie = cookie_;
 | 
						|
  cookie_ = 0;
 | 
						|
 | 
						|
  PrintJobManager* print_job_manager = g_browser_process->print_job_manager();
 | 
						|
  // May be NULL in tests.
 | 
						|
  if (!print_job_manager)
 | 
						|
    return;
 | 
						|
 | 
						|
  scoped_refptr<PrinterQuery> printer_query;
 | 
						|
  printer_query = queue_->PopPrinterQuery(cookie);
 | 
						|
  if (!printer_query.get())
 | 
						|
    return;
 | 
						|
  BrowserThread::PostTask(
 | 
						|
      BrowserThread::IO, FROM_HERE,
 | 
						|
      base::BindOnce(&PrinterQuery::StopWorker, printer_query));
 | 
						|
}
 | 
						|
 | 
						|
void CefPrintViewManagerBase::SendPrintingEnabled(
 | 
						|
    bool enabled,
 | 
						|
    content::RenderFrameHost* rfh) {
 | 
						|
  rfh->Send(new PrintMsg_SetPrintingEnabled(rfh->GetRoutingID(), enabled));
 | 
						|
}
 | 
						|
 | 
						|
}  // namespace printing
 |