1// Copyright (c) 2012 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#ifndef CHROME_BROWSER_PRINTING_PRINT_JOB_H_
6#define CHROME_BROWSER_PRINTING_PRINT_JOB_H_
7
8#include "base/basictypes.h"
9#include "base/memory/scoped_ptr.h"
10#include "base/memory/weak_ptr.h"
11#include "base/message_loop/message_loop.h"
12#include "chrome/browser/printing/print_job_worker_owner.h"
13#include "content/public/browser/notification_observer.h"
14#include "content/public/browser/notification_registrar.h"
15
16class Thread;
17
18namespace base {
19class RefCountedMemory;
20}
21
22namespace printing {
23
24class JobEventDetails;
25class MetafilePlayer;
26class PdfToEmfConverter;
27class PrintJobWorker;
28class PrintedDocument;
29class PrintedPage;
30class PrintedPagesSource;
31class PrinterQuery;
32
33// Manages the print work for a specific document. Talks to the printer through
34// PrintingContext through PrintJobWorker. Hides access to PrintingContext in a
35// worker thread so the caller never blocks. PrintJob will send notifications on
36// any state change. While printing, the PrintJobManager instance keeps a
37// reference to the job to be sure it is kept alive. All the code in this class
38// runs in the UI thread.
39class PrintJob : public PrintJobWorkerOwner,
40                 public content::NotificationObserver {
41 public:
42  // Create a empty PrintJob. When initializing with this constructor,
43  // post-constructor initialization must be done with Initialize().
44  PrintJob();
45
46  // Grabs the ownership of the PrintJobWorker from another job, which is
47  // usually a PrinterQuery. Set the expected page count of the print job.
48  void Initialize(PrintJobWorkerOwner* job, PrintedPagesSource* source,
49                  int page_count);
50
51  // content::NotificationObserver implementation.
52  virtual void Observe(int type,
53                       const content::NotificationSource& source,
54                       const content::NotificationDetails& details) OVERRIDE;
55
56  // PrintJobWorkerOwner implementation.
57  virtual void GetSettingsDone(const PrintSettings& new_settings,
58                               PrintingContext::Result result) OVERRIDE;
59  virtual PrintJobWorker* DetachWorker(PrintJobWorkerOwner* new_owner) OVERRIDE;
60  virtual const PrintSettings& settings() const OVERRIDE;
61  virtual int cookie() const OVERRIDE;
62
63  // Starts the actual printing. Signals the worker that it should begin to
64  // spool as soon as data is available.
65  void StartPrinting();
66
67  // Asks for the worker thread to finish its queued tasks and disconnects the
68  // delegate object. The PrintJobManager will remove its reference. This may
69  // have the side-effect of destroying the object if the caller doesn't have a
70  // handle to the object. Use PrintJob::is_stopped() to check whether the
71  // worker thread has actually stopped.
72  void Stop();
73
74  // Cancels printing job and stops the worker thread. Takes effect immediately.
75  void Cancel();
76
77  // Synchronously wait for the job to finish. It is mainly useful when the
78  // process is about to be shut down and we're waiting for the spooler to eat
79  // our data.
80  bool FlushJob(base::TimeDelta timeout);
81
82  // Disconnects the PrintedPage source (PrintedPagesSource). It is done when
83  // the source is being destroyed.
84  void DisconnectSource();
85
86  // Returns true if the print job is pending, i.e. between a StartPrinting()
87  // and the end of the spooling.
88  bool is_job_pending() const;
89
90  // Access the current printed document. Warning: may be NULL.
91  PrintedDocument* document() const;
92
93#if defined(OS_WIN)
94  void StartPdfToEmfConversion(
95      const scoped_refptr<base::RefCountedMemory>& bytes,
96      const gfx::Size& page_size,
97      const gfx::Rect& content_area);
98#endif  // OS_WIN
99
100 protected:
101  virtual ~PrintJob();
102
103 private:
104  // Updates document_ to a new instance.
105  void UpdatePrintedDocument(PrintedDocument* new_document);
106
107  // Processes a NOTIFY_PRINT_JOB_EVENT notification.
108  void OnNotifyPrintJobEvent(const JobEventDetails& event_details);
109
110  // Releases the worker thread by calling Stop(), then broadcasts a JOB_DONE
111  // notification.
112  void OnDocumentDone();
113
114  // Terminates the worker thread in a very controlled way, to work around any
115  // eventual deadlock.
116  void ControlledWorkerShutdown();
117
118  // Called at shutdown when running a nested message loop.
119  void Quit();
120
121  void HoldUntilStopIsCalled();
122
123#if defined(OS_WIN)
124  void OnPdfToEmfStarted(int page_count);
125  void OnPdfToEmfPageConverted(int page_number,
126                               double scale_factor,
127                               scoped_ptr<MetafilePlayer> emf);
128#endif  // OS_WIN
129
130  content::NotificationRegistrar registrar_;
131
132  // Source that generates the PrintedPage's (i.e. a WebContents). It will be
133  // set back to NULL if the source is deleted before this object.
134  PrintedPagesSource* source_;
135
136  // All the UI is done in a worker thread because many Win32 print functions
137  // are blocking and enters a message loop without your consent. There is one
138  // worker thread per print job.
139  scoped_ptr<PrintJobWorker> worker_;
140
141  // Cache of the print context settings for access in the UI thread.
142  PrintSettings settings_;
143
144  // The printed document.
145  scoped_refptr<PrintedDocument> document_;
146
147  // Is the worker thread printing.
148  bool is_job_pending_;
149
150  // Is Canceling? If so, try to not cause recursion if on FAILED notification,
151  // the notified calls Cancel() again.
152  bool is_canceling_;
153
154#if defined(OS_WIN)
155  class PdfToEmfState;
156  scoped_ptr<PdfToEmfState> ptd_to_emf_state_;
157#endif  // OS_WIN
158
159  // Used at shutdown so that we can quit a nested message loop.
160  base::WeakPtrFactory<PrintJob> quit_factory_;
161
162  DISALLOW_COPY_AND_ASSIGN(PrintJob);
163};
164
165// Details for a NOTIFY_PRINT_JOB_EVENT notification. The members may be NULL.
166class JobEventDetails : public base::RefCountedThreadSafe<JobEventDetails> {
167 public:
168  // Event type.
169  enum Type {
170    // Print... dialog box has been closed with OK button.
171    USER_INIT_DONE,
172
173    // Print... dialog box has been closed with CANCEL button.
174    USER_INIT_CANCELED,
175
176    // An automated initialization has been done, e.g. Init(false, NULL).
177    DEFAULT_INIT_DONE,
178
179    // A new document started printing.
180    NEW_DOC,
181
182    // A new page started printing.
183    NEW_PAGE,
184
185    // A page is done printing.
186    PAGE_DONE,
187
188    // A document is done printing. The worker thread is still alive. Warning:
189    // not a good moment to release the handle to PrintJob.
190    DOC_DONE,
191
192    // The worker thread is finished. A good moment to release the handle to
193    // PrintJob.
194    JOB_DONE,
195
196    // All missing pages have been requested.
197    ALL_PAGES_REQUESTED,
198
199    // An error occured. Printing is canceled.
200    FAILED,
201  };
202
203  JobEventDetails(Type type, PrintedDocument* document, PrintedPage* page);
204
205  // Getters.
206  PrintedDocument* document() const;
207  PrintedPage* page() const;
208  Type type() const {
209    return type_;
210  }
211
212 private:
213  friend class base::RefCountedThreadSafe<JobEventDetails>;
214
215  ~JobEventDetails();
216
217  scoped_refptr<PrintedDocument> document_;
218  scoped_refptr<PrintedPage> page_;
219  const Type type_;
220
221  DISALLOW_COPY_AND_ASSIGN(JobEventDetails);
222};
223
224}  // namespace printing
225
226#endif  // CHROME_BROWSER_PRINTING_PRINT_JOB_H_
227