Coverage Report

Created: 2018-09-25 14:53

/src/mozilla-central/layout/printing/ipc/RemotePrintJobParent.cpp
Line
Count
Source (jump to first uncovered line)
1
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
3
/* This Source Code Form is subject to the terms of the Mozilla Public
4
 * License, v. 2.0. If a copy of the MPL was not distributed with this
5
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6
7
#include "RemotePrintJobParent.h"
8
9
#include <fstream>
10
11
#include "gfxContext.h"
12
#include "mozilla/Attributes.h"
13
#include "mozilla/Unused.h"
14
#include "nsAppDirectoryServiceDefs.h"
15
#include "nsComponentManagerUtils.h"
16
#include "nsDirectoryServiceUtils.h"
17
#include "nsDeviceContext.h"
18
#include "nsIDeviceContextSpec.h"
19
#include "nsIPrintSettings.h"
20
#include "nsIWebProgressListener.h"
21
#include "PrintTranslator.h"
22
#include "private/pprio.h"
23
#include "nsAnonymousTemporaryFile.h"
24
25
namespace mozilla {
26
namespace layout {
27
28
RemotePrintJobParent::RemotePrintJobParent(nsIPrintSettings* aPrintSettings)
29
  : mPrintSettings(aPrintSettings)
30
  , mIsDoingPrinting(false)
31
0
{
32
0
  MOZ_COUNT_CTOR(RemotePrintJobParent);
33
0
}
34
35
mozilla::ipc::IPCResult
36
RemotePrintJobParent::RecvInitializePrint(const nsString& aDocumentTitle,
37
                                          const nsString& aPrintToFile,
38
                                          const int32_t& aStartPage,
39
                                          const int32_t& aEndPage)
40
0
{
41
0
  nsresult rv = InitializePrintDevice(aDocumentTitle, aPrintToFile, aStartPage,
42
0
                                      aEndPage);
43
0
  if (NS_FAILED(rv)) {
44
0
    Unused << SendPrintInitializationResult(rv, FileDescriptor());
45
0
    Unused << Send__delete__(this);
46
0
    return IPC_OK();
47
0
  }
48
0
49
0
  mPrintTranslator.reset(new PrintTranslator(mPrintDeviceContext));
50
0
  FileDescriptor fd;
51
0
  rv = PrepareNextPageFD(&fd);
52
0
  if (NS_FAILED(rv)) {
53
0
    Unused << SendPrintInitializationResult(rv, FileDescriptor());
54
0
    Unused << Send__delete__(this);
55
0
    return IPC_OK();
56
0
  }
57
0
58
0
  Unused << SendPrintInitializationResult(NS_OK, fd);
59
0
  return IPC_OK();
60
0
}
61
62
nsresult
63
RemotePrintJobParent::InitializePrintDevice(const nsString& aDocumentTitle,
64
                                            const nsString& aPrintToFile,
65
                                            const int32_t& aStartPage,
66
                                            const int32_t& aEndPage)
67
0
{
68
0
  nsresult rv;
69
0
  nsCOMPtr<nsIDeviceContextSpec> deviceContextSpec =
70
0
  do_CreateInstance("@mozilla.org/gfx/devicecontextspec;1", &rv);
71
0
  if (NS_WARN_IF(NS_FAILED(rv))) {
72
0
    return rv;
73
0
  }
74
0
75
0
  rv = deviceContextSpec->Init(nullptr, mPrintSettings, false);
76
0
  if (NS_WARN_IF(NS_FAILED(rv))) {
77
0
    return rv;
78
0
  }
79
0
80
0
  mPrintDeviceContext = new nsDeviceContext();
81
0
  rv = mPrintDeviceContext->InitForPrinting(deviceContextSpec);
82
0
  if (NS_WARN_IF(NS_FAILED(rv))) {
83
0
    return rv;
84
0
  }
85
0
86
0
  rv = mPrintDeviceContext->BeginDocument(aDocumentTitle, aPrintToFile,
87
0
                                          aStartPage, aEndPage);
88
0
  if (NS_FAILED(rv)) {
89
0
    NS_WARNING_ASSERTION(rv == NS_ERROR_ABORT,
90
0
                         "Failed to initialize print device");
91
0
    return rv;
92
0
  }
93
0
94
0
  if (!mPrintDeviceContext->IsSyncPagePrinting()) {
95
0
    mPrintDeviceContext->RegisterPageDoneCallback([this](nsresult aResult) { PageDone(aResult); });
96
0
  }
97
0
98
0
  mIsDoingPrinting = true;
99
0
100
0
  return NS_OK;
101
0
}
102
103
nsresult
104
RemotePrintJobParent::PrepareNextPageFD(FileDescriptor* aFd)
105
0
{
106
0
  PRFileDesc* prFd = nullptr;
107
0
  nsresult rv = NS_OpenAnonymousTemporaryFile(&prFd);
108
0
  if (NS_FAILED(rv)) {
109
0
    return rv;
110
0
  }
111
0
  *aFd = FileDescriptor(
112
0
    FileDescriptor::PlatformHandleType(PR_FileDesc2NativeHandle(prFd)));
113
0
  mCurrentPageStream.OpenFD(prFd);
114
0
  return NS_OK;
115
0
}
116
117
mozilla::ipc::IPCResult
118
RemotePrintJobParent::RecvProcessPage()
119
0
{
120
0
  if (!mCurrentPageStream.IsOpen()) {
121
0
    Unused << SendAbortPrint(NS_ERROR_FAILURE);
122
0
    return IPC_OK();
123
0
  }
124
0
  mCurrentPageStream.Seek(0, PR_SEEK_SET);
125
0
  nsresult rv = PrintPage(mCurrentPageStream);
126
0
  mCurrentPageStream.Close();
127
0
128
0
  if (mPrintDeviceContext->IsSyncPagePrinting()) {
129
0
    PageDone(rv);
130
0
  }
131
0
132
0
  return IPC_OK();
133
0
}
134
135
nsresult
136
RemotePrintJobParent::PrintPage(PRFileDescStream& aRecording)
137
0
{
138
0
  MOZ_ASSERT(mPrintDeviceContext);
139
0
140
0
  nsresult rv = mPrintDeviceContext->BeginPage();
141
0
  if (NS_WARN_IF(NS_FAILED(rv))) {
142
0
    return rv;
143
0
  }
144
0
  if (!mPrintTranslator->TranslateRecording(aRecording)) {
145
0
    return NS_ERROR_FAILURE;
146
0
  }
147
0
148
0
  rv = mPrintDeviceContext->EndPage();
149
0
  if (NS_WARN_IF(NS_FAILED(rv))) {
150
0
    return rv;
151
0
  }
152
0
153
0
  return NS_OK;
154
0
}
155
156
void
157
RemotePrintJobParent::PageDone(nsresult aResult)
158
0
{
159
0
  MOZ_ASSERT(mIsDoingPrinting);
160
0
161
0
  if (NS_FAILED(aResult)) {
162
0
    Unused << SendAbortPrint(aResult);
163
0
  } else {
164
0
    FileDescriptor fd;
165
0
    aResult = PrepareNextPageFD(&fd);
166
0
    if (NS_FAILED(aResult)) {
167
0
      Unused << SendAbortPrint(aResult);
168
0
    }
169
0
170
0
    Unused << SendPageProcessed(fd);
171
0
  }
172
0
}
173
174
mozilla::ipc::IPCResult
175
RemotePrintJobParent::RecvFinalizePrint()
176
0
{
177
0
  // EndDocument is sometimes called in the child even when BeginDocument has
178
0
  // not been called. See bug 1223332.
179
0
  if (mPrintDeviceContext) {
180
0
    DebugOnly<nsresult> rv = mPrintDeviceContext->EndDocument();
181
0
182
0
    // Too late to abort the child just log.
183
0
    NS_WARNING_ASSERTION(NS_SUCCEEDED(rv), "EndDocument failed");
184
0
185
0
    // Since RecvFinalizePrint is called after all page printed, there should
186
0
    // be no more page-done callbacks after that, in theory. Unregistering
187
0
    // page-done callback is not must have, but we still do this for safety.
188
0
    mPrintDeviceContext->UnregisterPageDoneCallback();
189
0
  }
190
0
191
0
  mIsDoingPrinting = false;
192
0
193
0
  Unused << Send__delete__(this);
194
0
  return IPC_OK();
195
0
}
196
197
mozilla::ipc::IPCResult
198
RemotePrintJobParent::RecvAbortPrint(const nsresult& aRv)
199
0
{
200
0
  if (mPrintDeviceContext) {
201
0
    Unused << mPrintDeviceContext->AbortDocument();
202
0
    mPrintDeviceContext->UnregisterPageDoneCallback();
203
0
  }
204
0
205
0
  mIsDoingPrinting = false;
206
0
207
0
  Unused << Send__delete__(this);
208
0
  return IPC_OK();
209
0
}
210
211
mozilla::ipc::IPCResult
212
RemotePrintJobParent::RecvStateChange(const long& aStateFlags,
213
                                      const nsresult& aStatus)
214
0
{
215
0
  uint32_t numberOfListeners = mPrintProgressListeners.Length();
216
0
  for (uint32_t i = 0; i < numberOfListeners; ++i) {
217
0
    nsIWebProgressListener* listener = mPrintProgressListeners.SafeElementAt(i);
218
0
    listener->OnStateChange(nullptr, nullptr, aStateFlags, aStatus);
219
0
  }
220
0
221
0
  return IPC_OK();
222
0
}
223
224
mozilla::ipc::IPCResult
225
RemotePrintJobParent::RecvProgressChange(const long& aCurSelfProgress,
226
                                         const long& aMaxSelfProgress,
227
                                         const long& aCurTotalProgress,
228
                                         const long& aMaxTotalProgress)
229
0
{
230
0
  uint32_t numberOfListeners = mPrintProgressListeners.Length();
231
0
  for (uint32_t i = 0; i < numberOfListeners; ++i) {
232
0
    nsIWebProgressListener* listener = mPrintProgressListeners.SafeElementAt(i);
233
0
    listener->OnProgressChange(nullptr, nullptr,
234
0
                               aCurSelfProgress, aMaxSelfProgress,
235
0
                               aCurTotalProgress, aMaxTotalProgress);
236
0
  }
237
0
238
0
  return IPC_OK();
239
0
}
240
241
mozilla::ipc::IPCResult
242
RemotePrintJobParent::RecvStatusChange(const nsresult& aStatus)
243
0
{
244
0
  uint32_t numberOfListeners = mPrintProgressListeners.Length();
245
0
  for (uint32_t i = 0; i < numberOfListeners; ++i) {
246
0
    nsIWebProgressListener* listener = mPrintProgressListeners.SafeElementAt(i);
247
0
    listener->OnStatusChange(nullptr, nullptr, aStatus, nullptr);
248
0
  }
249
0
250
0
  return IPC_OK();
251
0
}
252
253
void
254
RemotePrintJobParent::RegisterListener(nsIWebProgressListener* aListener)
255
0
{
256
0
  MOZ_ASSERT(aListener);
257
0
258
0
  mPrintProgressListeners.AppendElement(aListener);
259
0
}
260
261
already_AddRefed<nsIPrintSettings>
262
RemotePrintJobParent::GetPrintSettings()
263
0
{
264
0
  nsCOMPtr<nsIPrintSettings> printSettings = mPrintSettings;
265
0
  return printSettings.forget();
266
0
}
267
268
RemotePrintJobParent::~RemotePrintJobParent()
269
0
{
270
0
  MOZ_COUNT_DTOR(RemotePrintJobParent);
271
0
}
272
273
void
274
RemotePrintJobParent::ActorDestroy(ActorDestroyReason aWhy)
275
0
{
276
0
  if (mPrintDeviceContext) {
277
0
    mPrintDeviceContext->UnregisterPageDoneCallback();
278
0
  }
279
0
280
0
  mIsDoingPrinting = false;
281
0
282
0
  // If progress dialog is opened, notify closing it.
283
0
  for (auto listener : mPrintProgressListeners) {
284
0
    listener->OnStateChange(nullptr,
285
0
                            nullptr,
286
0
                            nsIWebProgressListener::STATE_STOP,
287
0
                            NS_OK);
288
0
  }
289
0
}
290
291
} // namespace layout
292
} // namespace mozilla