summaryrefslogtreecommitdiffstats
path: root/layout/printing/nsPrintJob.h
blob: 3eb6f5e57f4fbd85d74dea9f70c26fb1defeadd9 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef nsPrintJob_h
#define nsPrintJob_h

#include "mozilla/Attributes.h"
#include "mozilla/UniquePtr.h"

#include "nsCOMPtr.h"

#include "nsHashKeys.h"
#include "nsIFrame.h"  // For WeakFrame
#include "nsSize.h"
#include "nsTHashtable.h"
#include "nsWeakReference.h"

// Interfaces
#include "nsIObserver.h"
#include "nsIWebProgress.h"
#include "nsIWebProgressListener.h"

// Classes
class nsIFrame;
class nsIPrintProgressParams;
class nsIPrintSettings;
class nsPrintData;
class nsPagePrintTimer;
class nsIDocShell;
class nsIDocumentViewerPrint;
class nsIFrame;
class nsPrintObject;
class nsIDocShell;
class nsPageSequenceFrame;
class nsPIDOMWindowOuter;
class nsView;

namespace mozilla {
class PresShell;
namespace dom {
class Document;
class PrintPreviewResultInfo;
}  // namespace dom
}  // namespace mozilla

/**
 * A print job may be instantiated either for printing to an actual physical
 * printer, or for creating a print preview.
 */
class nsPrintJob final : public nsIObserver,
                         public nsIWebProgressListener,
                         public nsSupportsWeakReference {
  using Document = mozilla::dom::Document;
  using PrintPreviewResolver =
      std::function<void(const mozilla::dom::PrintPreviewResultInfo&)>;

 public:
  static void CloseProgressDialog(nsIWebProgressListener* aWebProgressListener);

  nsPrintJob();

  // nsISupports interface...
  NS_DECL_ISUPPORTS

  // nsIObserver
  NS_DECL_NSIOBSERVER

  NS_DECL_NSIWEBPROGRESSLISTENER

  /**
   * Initialize for printing, or for creating a print preview document.
   *
   * aDocViewerPrint owns us.
   *
   * When called in preparation for printing, aOriginalDoc is aDocViewerPrint's
   * document.  The document/viewer may be for a sub-document (an iframe).
   *
   * When called in preparation for print preview, aOriginalDoc belongs to a
   * different docViewer, in a different docShell, in a different TabGroup.
   * In this case our aDocViewerPrint is the docViewer for the about:blank
   * document in a new tab that the Firefox frontend code has created in
   * preparation for PrintPreview to generate a print preview document in it.
   *
   * NOTE: In the case we're called for print preview, aOriginalDoc actually
   * may not be the original document that the user selected to print.  It
   * is not the actual original document in the case when the user chooses to
   * display a simplified version of a print preview document.  In that
   * instance the Firefox frontend code creates a second print preview tab,
   * with a new docViewer and nsPrintJob, and passes the previous print preview
   * document as aOriginalDoc (it doesn't want to pass the actual original
   * document since it may have mutated)!
   */
  nsresult Initialize(nsIDocumentViewerPrint* aDocViewerPrint,
                      nsIDocShell* aDocShell, Document* aOriginalDoc,
                      float aScreenDPI);

  // Our nsIWebBrowserPrint implementation (nsDocumentViewer) defers to the
  // following methods.

  /**
   * May be called immediately after initialization, or after one or more
   * PrintPreview calls.
   */
  MOZ_CAN_RUN_SCRIPT_BOUNDARY nsresult
  Print(Document* aSourceDoc, nsIPrintSettings* aPrintSettings,
        nsIWebProgressListener* aWebProgressListener);

  /**
   * Generates a new print preview document and replaces our docViewer's
   * document with it.  (Note that this breaks the normal invariant that a
   * Document and its nsDocumentViewer have an unchanging 1:1 relationship.)
   *
   * This may be called multiple times on the same instance in order to
   * recreate the print preview document to take account of settings that the
   * user has changed in the print preview interface.  In this case aSourceDoc
   * is actually our docViewer's current document!
   */
  MOZ_CAN_RUN_SCRIPT_BOUNDARY nsresult
  PrintPreview(Document* aSourceDoc, nsIPrintSettings* aPrintSettings,
               nsIWebProgressListener* aWebProgressListener,
               PrintPreviewResolver&& aCallback);

  bool IsDoingPrint() const { return mIsDoingPrinting; }
  bool CreatedForPrintPreview() const { return mCreatedForPrintPreview; }
  bool HasEverPrinted() const { return mHasEverPrinted; }
  /// If the returned value is not greater than zero, an error occurred.
  int32_t GetRawNumPages() const;
  // Returns whether the preview is empty due to page range exclusion.
  bool GetIsEmpty() const;

  // Returns the total number of PrintedSheetFrames (i.e. faces of a sheet of
  // paper) for this print job. (This may be less than the raw number of pages,
  // due to pages having been skipped in a page range or combined into a single
  // sheet via pages-per-sheet.)
  int32_t GetPrintPreviewNumSheets() const;
  already_AddRefed<nsIPrintSettings> GetCurrentPrintSettings();

  // The setters here also update the DocViewer
  void SetIsPrinting(bool aIsPrinting);
  bool GetIsPrinting() const { return mIsDoingPrinting; }
  void SetIsPrintPreview(bool aIsPrintPreview);
  bool GetIsCreatingPrintPreview() const { return mIsCreatingPrintPreview; }

  std::tuple<nsPageSequenceFrame*, int32_t> GetSeqFrameAndCountSheets() const;

  bool PrePrintSheet();
  bool PrintSheet(nsPrintObject* aPOect, bool& aInRange);
  bool DonePrintingSheets(nsPrintObject* aPO, nsresult aResult);

  nsresult CleanupOnFailure(nsresult aResult, bool aIsPrinting);
  // If FinishPrintPreview() fails, caller may need to reset the state of the
  // object, for example by calling CleanupOnFailure().
  MOZ_CAN_RUN_SCRIPT_BOUNDARY nsresult FinishPrintPreview();
  void FirePrintingErrorEvent(nsresult aPrintError);

  bool CheckBeforeDestroy() const;
  mozilla::PresShell* GetPrintPreviewPresShell();
  nsresult Cancel();
  void Destroy();
  void DestroyPrintingData();

 private:
  nsPrintJob& operator=(const nsPrintJob& aOther) = delete;

  ~nsPrintJob();

  MOZ_CAN_RUN_SCRIPT nsresult DocumentReadyForPrinting();
  MOZ_CAN_RUN_SCRIPT nsresult SetupToPrintContent();
  nsresult EnablePOsForPrinting();
  nsPrintObject* FindSmallestSTF();

  bool PrintDocContent(const mozilla::UniquePtr<nsPrintObject>& aPO,
                       nsresult& aStatus);
  nsresult DoPrint(const mozilla::UniquePtr<nsPrintObject>& aPO);

  nsresult ReflowDocList(const mozilla::UniquePtr<nsPrintObject>& aPO,
                         bool aSetPixelScale);

  MOZ_CAN_RUN_SCRIPT_BOUNDARY
  nsresult ReflowPrintObject(const mozilla::UniquePtr<nsPrintObject>& aPO);

  void CalcNumPrintablePages(int32_t& aNumPages);
  void ShowPrintProgress(bool aIsForPrinting, bool& aDoNotify, Document* aDoc);
  void SetURLAndTitleOnProgressParams(
      const mozilla::UniquePtr<nsPrintObject>& aPO,
      nsIPrintProgressParams* aParams);
  void EllipseLongString(nsAString& aStr, const uint32_t aLen, bool aDoFront);

  nsresult StartPagePrintTimer(const mozilla::UniquePtr<nsPrintObject>& aPO);

  bool IsWindowsInOurSubTree(nsPIDOMWindowOuter* aDOMWindow) const;

  /**
   * @return The document from the focused windows for a document viewer.
   *
   * FIXME: This is somewhat unsound, this looks at the original document, which
   * could've mutated after print was initiated.
   */
  Document* FindFocusedDocument(Document* aDoc) const;

  /// Customizes the behaviour of GetDisplayTitleAndURL.
  enum class DocTitleDefault : uint32_t { eDocURLElseFallback, eFallback };

  /**
   * Gets the title and URL of the document for display in save-to-PDF dialogs,
   * print spooler lists and page headers/footers.  This will get the title/URL
   * from the PrintSettings, if set, otherwise it will get them from the
   * document.
   *
   * For the title specifically, if a value is not provided by the settings
   * object or the document then, if eDocURLElseFallback is passed, the document
   * URL will be returned as the title if it's non-empty (which should always be
   * the case).  Otherwise a non-empty fallback title will be returned.
   */
  static void GetDisplayTitleAndURL(Document& aDoc, nsIPrintSettings* aSettings,
                                    DocTitleDefault aTitleDefault,
                                    nsAString& aTitle, nsAString& aURLStr);

  MOZ_CAN_RUN_SCRIPT nsresult CommonPrint(
      bool aIsPrintPreview, nsIPrintSettings* aPrintSettings,
      nsIWebProgressListener* aWebProgressListener, Document* aSourceDoc);

  MOZ_CAN_RUN_SCRIPT nsresult DoCommonPrint(
      bool aIsPrintPreview, nsIPrintSettings* aPrintSettings,
      nsIWebProgressListener* aWebProgressListener, Document* aSourceDoc);

  void FirePrintCompletionEvent();

  void DisconnectPagePrintTimer();

  /**
   * This method is called to resume printing after all outstanding resources
   * referenced by the static clone have finished loading.  (It is possibly
   * called synchronously if there are no resources to load.)  While a static
   * clone will generally just be able to reference the (already loaded)
   * resources that the original document references, the static clone may
   * reference additional resources that have not previously been loaded
   * (if it has a 'print' style sheet, for example).
   */
  MOZ_CAN_RUN_SCRIPT nsresult
  MaybeResumePrintAfterResourcesLoaded(bool aCleanupOnError);

  bool ShouldResumePrint() const;

  nsresult SetRootView(nsPrintObject* aPO, bool& aDoReturn,
                       bool& aDocumentIsTopLevel, nsSize& aAdjSize);
  nsView* GetParentViewForRoot();
  bool DoSetPixelScale();
  void UpdateZoomRatio(nsPrintObject* aPO, bool aSetPixelScale);
  MOZ_CAN_RUN_SCRIPT nsresult ReconstructAndReflow(bool aDoSetPixelScale);
  MOZ_CAN_RUN_SCRIPT_BOUNDARY nsresult UpdateSelectionAndShrinkPrintObject(
      nsPrintObject* aPO, bool aDocumentIsTopLevel);
  MOZ_CAN_RUN_SCRIPT nsresult InitPrintDocConstruction(bool aHandleError);
  void FirePrintPreviewUpdateEvent();

  void PageDone(nsresult aResult);

  // The document that we were originally created for in order to print it or
  // create a print preview of it.  This may belong to mDocViewerPrint or may
  // belong to a different docViewer in a different docShell.  In reality, this
  // also may not be the original document that the user selected to print (see
  // the comment documenting Initialize() above).
  RefPtr<Document> mOriginalDoc;

  // The docViewer that owns us, and its docShell.
  nsCOMPtr<nsIDocumentViewerPrint> mDocViewerPrint;
  nsWeakPtr mDocShell;

  WeakFrame mPageSeqFrame;

  // We are the primary owner of our nsPrintData member vars.  These vars
  // are refcounted so that functions (e.g. nsPrintData methods) can create
  // temporary owning references when they need to fire a callback that
  // could conceivably destroy this nsPrintJob owner object and all its
  // member-data.
  RefPtr<nsPrintData> mPrt;

  // The nsPrintData for our last print preview (replaced every time the
  // user changes settings in the print preview window).
  // Note: Our new print preview nsPrintData is stored in mPtr until we move it
  // to mPrtPreview once we've finish creating the print preview.
  RefPtr<nsPrintData> mPrtPreview;

  RefPtr<nsPagePrintTimer> mPagePrintTimer;

  // If the code that initiates a print preview passes a PrintPreviewResolver
  // (a std::function) to be notified of the final sheet/page counts (once
  // we've sufficiently laid out the document to know what those are), that
  // callback is stored here.
  PrintPreviewResolver mPrintPreviewCallback;

  float mScreenDPI = 115.0f;

  bool mCreatedForPrintPreview = false;
  bool mIsCreatingPrintPreview = false;
  bool mIsDoingPrinting = false;
  bool mHasEverPrinted = false;
  bool mProgressDialogIsShown = false;
  bool mDidLoadDataForPrinting = false;
  bool mDoingInitialReflow = false;
  bool mIsDestroying = false;
  bool mDisallowSelectionPrint = false;
  bool mIsForModalWindow = false;
};

#endif  // nsPrintJob_h