Line data Source code
1 : /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
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 "mozilla/dom/Element.h"
8 : #include "mozilla/dom/TabParent.h"
9 : #include "mozilla/Preferences.h"
10 : #include "mozilla/Unused.h"
11 : #include "nsIContent.h"
12 : #include "nsIDocument.h"
13 : #include "nsIDOMWindow.h"
14 : #include "nsIPrintingPromptService.h"
15 : #include "nsIPrintProgressParams.h"
16 : #include "nsIPrintSettingsService.h"
17 : #include "nsIServiceManager.h"
18 : #include "nsServiceManagerUtils.h"
19 : #include "nsIWebProgressListener.h"
20 : #include "PrintingParent.h"
21 : #include "PrintDataUtils.h"
22 : #include "PrintProgressDialogParent.h"
23 : #include "PrintSettingsDialogParent.h"
24 : #include "mozilla/layout/RemotePrintJobParent.h"
25 :
26 : using namespace mozilla;
27 : using namespace mozilla::dom;
28 : using namespace mozilla::layout;
29 :
30 : namespace mozilla {
31 : namespace embedding {
32 : mozilla::ipc::IPCResult
33 0 : PrintingParent::RecvShowProgress(PBrowserParent* parent,
34 : PPrintProgressDialogParent* printProgressDialog,
35 : PRemotePrintJobParent* remotePrintJob,
36 : const bool& isForPrinting)
37 : {
38 0 : bool notifyOnOpen = false;
39 :
40 0 : nsCOMPtr<nsPIDOMWindowOuter> parentWin = DOMWindowFromBrowserParent(parent);
41 0 : nsCOMPtr<nsIPrintingPromptService> pps(do_GetService("@mozilla.org/embedcomp/printingprompt-service;1"));
42 :
43 : PrintProgressDialogParent* dialogParent =
44 0 : static_cast<PrintProgressDialogParent*>(printProgressDialog);
45 0 : nsCOMPtr<nsIObserver> observer = do_QueryInterface(dialogParent);
46 :
47 0 : nsCOMPtr<nsIWebProgressListener> printProgressListener;
48 0 : nsCOMPtr<nsIPrintProgressParams> printProgressParams;
49 :
50 0 : nsresult rv = NS_ERROR_INVALID_ARG;
51 0 : if (parentWin && pps) {
52 0 : rv = pps->ShowProgress(parentWin, nullptr, nullptr, observer,
53 0 : isForPrinting,
54 0 : getter_AddRefs(printProgressListener),
55 0 : getter_AddRefs(printProgressParams),
56 0 : ¬ifyOnOpen);
57 : }
58 :
59 0 : if (NS_SUCCEEDED(rv)) {
60 0 : if (remotePrintJob) {
61 : // If we have a RemotePrintJob use that as a more general forwarder for
62 : // print progress listeners.
63 : static_cast<RemotePrintJobParent*>(remotePrintJob)
64 0 : ->RegisterListener(printProgressListener);
65 : } else {
66 0 : dialogParent->SetWebProgressListener(printProgressListener);
67 : }
68 :
69 0 : dialogParent->SetPrintProgressParams(printProgressParams);
70 : }
71 :
72 : // NOTE: If we aren't going to observe an event on our observer, we need to
73 : // fake one. This takes the form of sending the SendDialogOpened message. This
74 : // is safe because the child process proxy will always return `true` for
75 : // notifyOnOpen, as the request will always be async when performed across
76 : // process boundaries.
77 : //
78 : // We can pass nullptr for all of the arguments, as all consumers of this
79 : // observer don't care about the subject, topic, or data.
80 : //
81 : // If notifyOnOpen is true, then the ShowProgress call will handle notifying
82 : // our observer for us.
83 0 : if (!notifyOnOpen) {
84 0 : observer->Observe(nullptr, nullptr, nullptr);
85 : }
86 0 : return IPC_OK();
87 : }
88 :
89 : nsresult
90 0 : PrintingParent::ShowPrintDialog(PBrowserParent* aParent,
91 : const PrintData& aData,
92 : PrintData* aResult)
93 : {
94 : // If aParent is null this call is just being used to get print settings from
95 : // the printer for print preview.
96 0 : bool isPrintPreview = !aParent;
97 0 : nsCOMPtr<nsPIDOMWindowOuter> parentWin;
98 0 : if (aParent) {
99 0 : parentWin = DOMWindowFromBrowserParent(aParent);
100 0 : if (!parentWin) {
101 0 : return NS_ERROR_FAILURE;
102 : }
103 : }
104 :
105 0 : nsCOMPtr<nsIPrintingPromptService> pps(do_GetService("@mozilla.org/embedcomp/printingprompt-service;1"));
106 0 : if (!pps) {
107 0 : return NS_ERROR_FAILURE;
108 : }
109 :
110 : // The initSettings we got can be wrapped using
111 : // PrintDataUtils' MockWebBrowserPrint, which implements enough of
112 : // nsIWebBrowserPrint to keep the dialogs happy.
113 0 : nsCOMPtr<nsIWebBrowserPrint> wbp = new MockWebBrowserPrint(aData);
114 :
115 : // Use the existing RemotePrintJob and its settings, if we have one, to make
116 : // sure they stay current.
117 : RemotePrintJobParent* remotePrintJob =
118 0 : static_cast<RemotePrintJobParent*>(aData.remotePrintJobParent());
119 0 : nsCOMPtr<nsIPrintSettings> settings;
120 : nsresult rv;
121 0 : if (remotePrintJob) {
122 0 : settings = remotePrintJob->GetPrintSettings();
123 : } else {
124 0 : rv = mPrintSettingsSvc->GetNewPrintSettings(getter_AddRefs(settings));
125 0 : NS_ENSURE_SUCCESS(rv, rv);
126 : }
127 :
128 : // We only want to use the print silently setting from the parent.
129 : bool printSilently;
130 0 : rv = settings->GetPrintSilent(&printSilently);
131 0 : NS_ENSURE_SUCCESS(rv, rv);
132 :
133 0 : rv = mPrintSettingsSvc->DeserializeToPrintSettings(aData, settings);
134 0 : NS_ENSURE_SUCCESS(rv, rv);
135 :
136 0 : rv = settings->SetPrintSilent(printSilently);
137 0 : NS_ENSURE_SUCCESS(rv, rv);
138 :
139 0 : nsXPIDLString printerName;
140 0 : settings->GetPrinterName(getter_Copies(printerName));
141 : #ifdef MOZ_X11
142 : // Requesting the default printer name on Linux has been removed in the child,
143 : // because it was causing a sandbox violation (see Bug 1329216).
144 : // If no printer name is set at this point, use the print settings service
145 : // to get the default printer name.
146 0 : if (printerName.IsEmpty()) {
147 0 : mPrintSettingsSvc->GetDefaultPrinterName(getter_Copies(printerName));
148 0 : settings->SetPrinterName(printerName);
149 : }
150 0 : mPrintSettingsSvc->InitPrintSettingsFromPrinter(printerName, settings);
151 : #endif
152 :
153 : // If this is for print preview or we are printing silently then we just need
154 : // to initialize the print settings with anything specific from the printer.
155 0 : if (isPrintPreview || printSilently ||
156 0 : Preferences::GetBool("print.always_print_silent", printSilently)) {
157 0 : settings->SetIsInitializedFromPrinter(false);
158 0 : mPrintSettingsSvc->InitPrintSettingsFromPrinter(printerName, settings);
159 : } else {
160 0 : rv = pps->ShowPrintDialog(parentWin, wbp, settings);
161 0 : NS_ENSURE_SUCCESS(rv, rv);
162 : }
163 :
164 0 : if (isPrintPreview) {
165 : // For print preview we don't want a RemotePrintJob just the settings.
166 0 : rv = mPrintSettingsSvc->SerializeToPrintData(settings, nullptr, aResult);
167 : } else {
168 0 : rv = SerializeAndEnsureRemotePrintJob(settings, nullptr, remotePrintJob,
169 0 : aResult);
170 : }
171 :
172 0 : return rv;
173 : }
174 :
175 : mozilla::ipc::IPCResult
176 0 : PrintingParent::RecvShowPrintDialog(PPrintSettingsDialogParent* aDialog,
177 : PBrowserParent* aParent,
178 : const PrintData& aData)
179 : {
180 0 : PrintData resultData;
181 0 : nsresult rv = ShowPrintDialog(aParent, aData, &resultData);
182 :
183 : // The child has been spinning an event loop while waiting
184 : // to hear about the print settings. We return the results
185 : // with an async message which frees the child process from
186 : // its nested event loop.
187 0 : if (NS_FAILED(rv)) {
188 0 : mozilla::Unused << aDialog->Send__delete__(aDialog, rv);
189 : } else {
190 0 : mozilla::Unused << aDialog->Send__delete__(aDialog, resultData);
191 : }
192 0 : return IPC_OK();
193 : }
194 :
195 : mozilla::ipc::IPCResult
196 0 : PrintingParent::RecvSavePrintSettings(const PrintData& aData,
197 : const bool& aUsePrinterNamePrefix,
198 : const uint32_t& aFlags,
199 : nsresult* aResult)
200 : {
201 0 : nsCOMPtr<nsIPrintSettings> settings;
202 0 : *aResult = mPrintSettingsSvc->GetNewPrintSettings(getter_AddRefs(settings));
203 0 : NS_ENSURE_SUCCESS(*aResult, IPC_OK());
204 :
205 0 : *aResult = mPrintSettingsSvc->DeserializeToPrintSettings(aData, settings);
206 0 : NS_ENSURE_SUCCESS(*aResult, IPC_OK());
207 :
208 0 : *aResult = mPrintSettingsSvc->SavePrintSettingsToPrefs(settings,
209 0 : aUsePrinterNamePrefix,
210 0 : aFlags);
211 :
212 0 : return IPC_OK();
213 : }
214 :
215 : PPrintProgressDialogParent*
216 0 : PrintingParent::AllocPPrintProgressDialogParent()
217 : {
218 0 : PrintProgressDialogParent* actor = new PrintProgressDialogParent();
219 0 : NS_ADDREF(actor); // De-ref'd in the __delete__ handler for
220 : // PrintProgressDialogParent.
221 0 : return actor;
222 : }
223 :
224 : bool
225 0 : PrintingParent::DeallocPPrintProgressDialogParent(PPrintProgressDialogParent* doomed)
226 : {
227 : // We can't just delete the PrintProgressDialogParent since somebody might
228 : // still be holding a reference to it as nsIObserver, so just decrement the
229 : // refcount instead.
230 0 : PrintProgressDialogParent* actor = static_cast<PrintProgressDialogParent*>(doomed);
231 0 : NS_RELEASE(actor);
232 0 : return true;
233 : }
234 :
235 : PPrintSettingsDialogParent*
236 0 : PrintingParent::AllocPPrintSettingsDialogParent()
237 : {
238 0 : return new PrintSettingsDialogParent();
239 : }
240 :
241 : bool
242 0 : PrintingParent::DeallocPPrintSettingsDialogParent(PPrintSettingsDialogParent* aDoomed)
243 : {
244 0 : delete aDoomed;
245 0 : return true;
246 : }
247 :
248 : PRemotePrintJobParent*
249 0 : PrintingParent::AllocPRemotePrintJobParent()
250 : {
251 0 : MOZ_ASSERT_UNREACHABLE("No default constructors for implementations.");
252 : return nullptr;
253 : }
254 :
255 : bool
256 0 : PrintingParent::DeallocPRemotePrintJobParent(PRemotePrintJobParent* aDoomed)
257 : {
258 0 : delete aDoomed;
259 0 : return true;
260 : }
261 :
262 : void
263 0 : PrintingParent::ActorDestroy(ActorDestroyReason aWhy)
264 : {
265 0 : }
266 :
267 : nsPIDOMWindowOuter*
268 0 : PrintingParent::DOMWindowFromBrowserParent(PBrowserParent* parent)
269 : {
270 0 : if (!parent) {
271 0 : return nullptr;
272 : }
273 :
274 0 : TabParent* tabParent = TabParent::GetFrom(parent);
275 0 : if (!tabParent) {
276 0 : return nullptr;
277 : }
278 :
279 0 : nsCOMPtr<Element> frameElement = tabParent->GetOwnerElement();
280 0 : if (!frameElement) {
281 0 : return nullptr;
282 : }
283 :
284 0 : nsCOMPtr<nsIContent> frame(do_QueryInterface(frameElement));
285 0 : if (!frame) {
286 0 : return nullptr;
287 : }
288 :
289 0 : nsCOMPtr<nsPIDOMWindowOuter> parentWin = frame->OwnerDoc()->GetWindow();
290 0 : if (!parentWin) {
291 0 : return nullptr;
292 : }
293 :
294 0 : return parentWin;
295 : }
296 :
297 : nsresult
298 0 : PrintingParent::SerializeAndEnsureRemotePrintJob(
299 : nsIPrintSettings* aPrintSettings, nsIWebProgressListener* aListener,
300 : layout::RemotePrintJobParent* aRemotePrintJob, PrintData* aPrintData)
301 : {
302 0 : MOZ_ASSERT(aPrintData);
303 :
304 : nsresult rv;
305 0 : nsCOMPtr<nsIPrintSettings> printSettings;
306 0 : if (aPrintSettings) {
307 0 : printSettings = aPrintSettings;
308 : } else {
309 0 : rv = mPrintSettingsSvc->GetNewPrintSettings(getter_AddRefs(printSettings));
310 0 : if (NS_WARN_IF(NS_FAILED(rv))) {
311 0 : return rv;
312 : }
313 : }
314 :
315 0 : rv = mPrintSettingsSvc->SerializeToPrintData(printSettings, nullptr,
316 0 : aPrintData);
317 0 : if (NS_WARN_IF(NS_FAILED(rv))) {
318 0 : return rv;
319 : }
320 :
321 : RemotePrintJobParent* remotePrintJob;
322 0 : if (aRemotePrintJob) {
323 0 : remotePrintJob = aRemotePrintJob;
324 0 : aPrintData->remotePrintJobParent() = remotePrintJob;
325 : } else {
326 0 : remotePrintJob = new RemotePrintJobParent(aPrintSettings);
327 0 : aPrintData->remotePrintJobParent() =
328 0 : SendPRemotePrintJobConstructor(remotePrintJob);
329 : }
330 0 : if (aListener) {
331 0 : remotePrintJob->RegisterListener(aListener);
332 : }
333 :
334 0 : return NS_OK;
335 : }
336 :
337 1 : PrintingParent::PrintingParent()
338 : {
339 : mPrintSettingsSvc =
340 1 : do_GetService("@mozilla.org/gfx/printsettings-service;1");
341 1 : MOZ_ASSERT(mPrintSettingsSvc);
342 1 : }
343 :
344 0 : PrintingParent::~PrintingParent()
345 : {
346 0 : }
347 :
348 : } // namespace embedding
349 : } // namespace mozilla
350 :
|