blob: c0db3bac427cf7b1b8239359923f5b7054166e7b [file] [log] [blame]
// Copyright 2012 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef CHROME_BROWSER_PRINTING_PRINT_JOB_H_
#define CHROME_BROWSER_PRINTING_PRINT_JOB_H_
#include <memory>
#include <optional>
#include <vector>
#include "base/functional/callback.h"
#include "base/gtest_prod_util.h"
#include "base/memory/ref_counted.h"
#include "base/observer_list.h"
#include "base/observer_list_types.h"
#include "base/time/time.h"
#include "build/build_config.h"
#include "build/chromeos_buildflags.h"
#include "components/enterprise/buildflags/buildflags.h"
#include "content/public/browser/global_routing_id.h"
#include "printing/print_settings.h"
#if BUILDFLAG(IS_CHROMEOS)
#include <string>
#include "chromeos/crosapi/mojom/local_printer.mojom.h"
#endif
#if BUILDFLAG(IS_WIN)
class GURL;
#endif
namespace base {
class Location;
class RefCountedMemory;
}
namespace printing {
class MetafilePlayer;
class PrintJobManager;
class PrintJobWorker;
class PrintedDocument;
#if BUILDFLAG(IS_WIN)
class PrintedPage;
#endif
class PrinterQuery;
class PrintSettings;
// Manages the print work for a specific document. Talks to the printer through
// PrintingContext through PrintJobWorker. Hides access to PrintingContext in a
// worker thread so the caller never blocks. PrintJob will send notifications on
// any state change. While printing, the PrintJobManager instance keeps a
// reference to the job to be sure it is kept alive. All the code in this class
// runs in the UI thread. All virtual functions are virtual only so that
// TestPrintJob can override them in tests.
class PrintJob : public base::RefCountedThreadSafe<PrintJob> {
public:
// An observer interface implemented by classes which are interested
// in `PrintJob` events.
class Observer : public base::CheckedObserver {
public:
virtual void OnDocDone(int job_id, PrintedDocument* document) {}
virtual void OnJobDone() {}
virtual void OnCanceling() {}
virtual void OnFailed() {}
virtual void OnDestruction() {}
};
#if BUILDFLAG(IS_CHROMEOS)
// An enumeration of components where print jobs can come from. The order of
// these enums must match that of
// chrome/browser/ash/printing/history/print_job_info.proto.
using Source = crosapi::mojom::PrintJob::Source;
#endif // BUILDFLAG(IS_CHROMEOS)
// Create a empty PrintJob. When initializing with this constructor,
// post-constructor initialization must be done with Initialize().
// If PrintJob is created on Chrome OS, call SetSource() to set which
// component initiated this print job.
// `print_job_manager` must outlive this object.
explicit PrintJob(PrintJobManager* print_job_manager);
PrintJob(const PrintJob&) = delete;
PrintJob& operator=(const PrintJob&) = delete;
// Grabs the ownership of the PrintJobWorker from a PrinterQuery along with
// the print settings. Sets the expected page count of the print job based on
// the settings.
virtual void Initialize(std::unique_ptr<PrinterQuery> query,
const std::u16string& name,
uint32_t page_count);
#if BUILDFLAG(IS_WIN)
void StartConversionToNativeFormat(
scoped_refptr<base::RefCountedMemory> print_data,
const gfx::Size& page_size,
const gfx::Rect& content_area,
const gfx::Point& physical_offsets,
const GURL& url);
// Overwrites the PDF page mapping to fill in values of -1 for all indices
// that are not selected. This is needed when the user opens the system
// dialog from the link in Print Preview on Windows and then sets a selection
// of pages, because all PDF pages will be converted, but only the user's
// selected pages should be sent to the printer. See https://crbug.com/823876.
void ResetPageMapping();
// Called when `page` is done printing.
void OnPageDone(PrintedPage* page);
#endif
// Called when the document is done printing.
virtual void OnDocDone(int job_id, PrintedDocument* document);
// Called if the document fails to print.
virtual void OnFailed();
// Starts the actual printing. Signals the worker that it should begin to
// spool as soon as data is available.
virtual void StartPrinting();
// Asks for the worker thread to finish its queued tasks and disconnects the
// delegate object. The PrintJobManager will remove its reference.
// WARNING: This may have the side-effect of destroying the object if the
// caller doesn't have a handle to the object. Use PrintJob::is_stopped() to
// check whether the worker thread has actually stopped.
virtual void Stop();
// Cancels printing job and stops the worker thread. Takes effect immediately.
// The caller must have a reference to the PrintJob before calling Cancel(),
// since Cancel() calls Stop(). See WARNING above for Stop().
virtual void Cancel();
#if BUILDFLAG(ENTERPRISE_CONTENT_ANALYSIS)
// Cleanup a printing job after content analysis denies printing. Performs
// any extra cleanup for this particular case that can't be safely done from
// within Cancel().
void CleanupAfterContentAnalysisDenial();
#endif
// Synchronously wait for the job to finish. It is mainly useful when the
// process is about to be shut down and we're waiting for the spooler to eat
// our data.
virtual bool FlushJob(base::TimeDelta timeout);
// Returns true if the print job is pending, i.e. between a StartPrinting()
// and the end of the spooling.
bool is_job_pending() const;
// Access the current printed document. Warning: may be NULL.
PrintedDocument* document() const;
// Access stored settings.
const PrintSettings& settings() const;
#if BUILDFLAG(IS_CHROMEOS)
// Sets the component which initiated the print job.
void SetSource(Source source, const std::string& source_id);
// Returns the source of print job.
Source source() const;
// Returns the ID of the source.
const std::string& source_id() const;
const base::ObserverList<Observer>& GetObserversForTesting() {
return observers_;
}
#endif // BUILDFLAG(IS_CHROMEOS)
// Posts the given task to be run.
bool PostTask(const base::Location& from_here, base::OnceClosure task);
// Adds and removes observers for `PrintJob` events. The order in
// which notifications are sent to observers is undefined. Observers must be
// sure to remove the observer before they go away.
void AddObserver(Observer& observer);
void RemoveObserver(Observer& observer);
protected:
// Refcounted class.
friend class base::RefCountedThreadSafe<PrintJob>;
virtual ~PrintJob();
// Constructs a PrintJob with a null PrintJobManager instance. Used only in
// testing contexts.
PrintJob();
void set_job_pending_for_testing(bool pending);
// Updates `document_` to a new instance. Protected so that tests can access
// it.
void UpdatePrintedDocument(scoped_refptr<PrintedDocument> new_document);
#if BUILDFLAG(IS_WIN)
// Virtual to support testing.
virtual void OnPdfPageConverted(uint32_t page_index,
float scale_factor,
std::unique_ptr<MetafilePlayer> metafile);
#endif
private:
#if BUILDFLAG(IS_WIN)
FRIEND_TEST_ALL_PREFIXES(PrintJobTest, PageRangeMapping);
#endif
// Clears reference to `document_`.
void ClearPrintedDocument();
// Helper method for UpdatePrintedDocument() and ClearPrintedDocument() to
// sync `document_` updates with `worker_`.
void SyncPrintedDocumentToWorker();
// Releases the worker thread by calling Stop(), then broadcasts a JOB_DONE
// notification.
void OnDocumentDone();
// Terminates the worker thread in a very controlled way, to work around any
// eventual deadlock.
void ControlledWorkerShutdown();
void HoldUntilStopIsCalled();
#if BUILDFLAG(IS_WIN)
virtual void StartPdfToEmfConversion(
scoped_refptr<base::RefCountedMemory> bytes,
const gfx::Size& page_size,
const gfx::Rect& content_area,
const GURL& url);
virtual void StartPdfToPostScriptConversion(
scoped_refptr<base::RefCountedMemory> bytes,
const gfx::Rect& content_area,
const gfx::Point& physical_offsets,
bool ps_level2,
const GURL& url);
virtual void StartPdfToTextConversion(
scoped_refptr<base::RefCountedMemory> bytes,
const gfx::Size& page_size,
const GURL& url);
void OnPdfConversionStarted(uint32_t page_count);
// Helper method to do the work for ResetPageMapping(). Split for unit tests.
static std::vector<uint32_t> GetFullPageMapping(
const std::vector<uint32_t>& pages,
uint32_t total_page_count);
#endif // BUILDFLAG(IS_WIN)
base::ObserverList<Observer> observers_;
// All the UI is done in a worker thread because many Win32 print functions
// are blocking and enters a message loop without your consent. There is one
// worker thread per print job.
std::unique_ptr<PrintJobWorker> worker_;
content::GlobalRenderFrameHostId rfh_id_;
// The global PrintJobManager. May be null in testing contexts
// only. Otherwise guaranteed to outlive this object.
raw_ptr<PrintJobManager> print_job_manager_ = nullptr;
// The printed document.
scoped_refptr<PrintedDocument> document_;
// Time at start of printing. Used for metrics.
std::optional<base::TimeTicks> printing_start_time_;
// Is the worker thread printing.
bool is_job_pending_ = false;
// Is Canceling? If so, try to not cause recursion if on FAILED notification,
// the notified calls Cancel() again.
bool is_canceling_ = false;
#if BUILDFLAG(IS_WIN)
class PdfConversionState;
std::unique_ptr<PdfConversionState> pdf_conversion_state_;
std::vector<uint32_t> pdf_page_mapping_;
std::optional<bool> use_skia_;
#endif // BUILDFLAG(IS_WIN)
#if BUILDFLAG(IS_CHROMEOS)
// The component which initiated the print job.
Source source_;
// ID of the source.
// This should be blank if the source is kPrintPreview or kArc.
std::string source_id_;
#endif // BUILDFLAG(IS_CHROMEOS)
// Holds the quit closure while running a nested RunLoop to flush tasks.
base::OnceClosure quit_closure_;
};
} // namespace printing
#endif // CHROME_BROWSER_PRINTING_PRINT_JOB_H_