/src/mozilla-central/layout/printing/nsPrintJob.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 "nsPrintJob.h" |
8 | | |
9 | | #include "nsIStringBundle.h" |
10 | | #include "nsReadableUtils.h" |
11 | | #include "nsCRT.h" |
12 | | |
13 | | #include "mozilla/AsyncEventDispatcher.h" |
14 | | #include "mozilla/ComputedStyleInlines.h" |
15 | | #include "mozilla/dom/Selection.h" |
16 | | #include "mozilla/dom/CustomEvent.h" |
17 | | #include "mozilla/dom/ScriptSettings.h" |
18 | | #include "nsIScriptGlobalObject.h" |
19 | | #include "nsPIDOMWindow.h" |
20 | | #include "nsIDocShell.h" |
21 | | #include "nsIURI.h" |
22 | | #include "nsITextToSubURI.h" |
23 | | #include "nsError.h" |
24 | | |
25 | | #include "nsView.h" |
26 | | #include <algorithm> |
27 | | |
28 | | // Print Options |
29 | | #include "nsIPrintSettings.h" |
30 | | #include "nsIPrintSettingsService.h" |
31 | | #include "nsIPrintSession.h" |
32 | | #include "nsGfxCIID.h" |
33 | | #include "nsIServiceManager.h" |
34 | | #include "nsGkAtoms.h" |
35 | | #include "nsXPCOM.h" |
36 | | #include "nsISupportsPrimitives.h" |
37 | | |
38 | | static const char sPrintSettingsServiceContractID[] = "@mozilla.org/gfx/printsettings-service;1"; |
39 | | |
40 | | // Printing Events |
41 | | #include "nsPrintPreviewListener.h" |
42 | | #include "nsThreadUtils.h" |
43 | | |
44 | | // Printing |
45 | | #include "nsIWebBrowserPrint.h" |
46 | | |
47 | | // Print Preview |
48 | | #include "imgIContainer.h" // image animation mode constants |
49 | | #include "nsIWebBrowserPrint.h" // needed for PrintPreview Navigation constants |
50 | | |
51 | | // Print Progress |
52 | | #include "nsIPrintProgress.h" |
53 | | #include "nsIPrintProgressParams.h" |
54 | | #include "nsIObserver.h" |
55 | | |
56 | | // Print error dialog |
57 | | #include "nsIPrompt.h" |
58 | | #include "nsIWindowWatcher.h" |
59 | | |
60 | | // Printing Prompts |
61 | | #include "nsIPrintingPromptService.h" |
62 | | static const char kPrintingPromptService[] = "@mozilla.org/embedcomp/printingprompt-service;1"; |
63 | | |
64 | | // Printing Timer |
65 | | #include "nsPagePrintTimer.h" |
66 | | |
67 | | // FrameSet |
68 | | #include "nsIDocument.h" |
69 | | #include "nsIDocumentInlines.h" |
70 | | |
71 | | // Focus |
72 | | #include "nsISelectionController.h" |
73 | | |
74 | | // Misc |
75 | | #include "gfxContext.h" |
76 | | #include "mozilla/gfx/DrawEventRecorder.h" |
77 | | #include "mozilla/layout/RemotePrintJobChild.h" |
78 | | #include "nsISupportsUtils.h" |
79 | | #include "nsIScriptContext.h" |
80 | | #include "nsIDocumentObserver.h" |
81 | | #include "nsISelectionListener.h" |
82 | | #include "nsContentCID.h" |
83 | | #include "nsLayoutCID.h" |
84 | | #include "nsContentUtils.h" |
85 | | #include "nsIPresShell.h" |
86 | | #include "nsLayoutStylesheetCache.h" |
87 | | #include "nsLayoutUtils.h" |
88 | | #include "mozilla/Preferences.h" |
89 | | #include "Text.h" |
90 | | |
91 | | #include "nsWidgetsCID.h" |
92 | | #include "nsIDeviceContextSpec.h" |
93 | | #include "nsDeviceContextSpecProxy.h" |
94 | | #include "nsViewManager.h" |
95 | | #include "nsView.h" |
96 | | |
97 | | #include "nsIPageSequenceFrame.h" |
98 | | #include "nsIURL.h" |
99 | | #include "nsIContentViewerEdit.h" |
100 | | #include "nsIInterfaceRequestor.h" |
101 | | #include "nsIInterfaceRequestorUtils.h" |
102 | | #include "nsIDocShellTreeOwner.h" |
103 | | #include "nsIWebBrowserChrome.h" |
104 | | #include "nsIBaseWindow.h" |
105 | | #include "nsILayoutHistoryState.h" |
106 | | #include "nsFrameManager.h" |
107 | | #include "mozilla/ReflowInput.h" |
108 | | #include "nsIContentViewer.h" |
109 | | #include "nsIDocumentViewerPrint.h" |
110 | | |
111 | | #include "nsFocusManager.h" |
112 | | #include "nsRange.h" |
113 | | #include "nsCDefaultURIFixup.h" |
114 | | #include "nsIURIFixup.h" |
115 | | #include "mozilla/dom/Element.h" |
116 | | #include "mozilla/dom/HTMLFrameElement.h" |
117 | | #include "nsContentList.h" |
118 | | #include "nsIChannel.h" |
119 | | #include "xpcpublic.h" |
120 | | #include "nsVariant.h" |
121 | | #include "mozilla/ServoStyleSet.h" |
122 | | |
123 | | using namespace mozilla; |
124 | | using namespace mozilla::dom; |
125 | | |
126 | | //----------------------------------------------------- |
127 | | // PR LOGGING |
128 | | #include "mozilla/Logging.h" |
129 | | |
130 | | #ifdef DEBUG |
131 | | // PR_LOGGING is force to always be on (even in release builds) |
132 | | // but we only want some of it on, |
133 | | //#define EXTENDED_DEBUG_PRINTING |
134 | | #endif |
135 | | |
136 | | // this log level turns on the dumping of each document's layout info |
137 | | #define DUMP_LAYOUT_LEVEL (static_cast<mozilla::LogLevel>(9)) |
138 | | |
139 | | #ifndef PR_PL |
140 | | static mozilla::LazyLogModule gPrintingLog("printing") |
141 | | |
142 | | #define PR_PL(_p1) MOZ_LOG(gPrintingLog, mozilla::LogLevel::Debug, _p1); |
143 | | #endif |
144 | | |
145 | | #ifdef EXTENDED_DEBUG_PRINTING |
146 | | static uint32_t gDumpFileNameCnt = 0; |
147 | | static uint32_t gDumpLOFileNameCnt = 0; |
148 | | #endif |
149 | | |
150 | | #define PRT_YESNO(_p) ((_p)?"YES":"NO") |
151 | | static const char * gFrameTypesStr[] = {"eDoc", "eFrame", "eIFrame", "eFrameSet"}; |
152 | | static const char * gPrintFrameTypeStr[] = {"kNoFrames", "kFramesAsIs", "kSelectedFrame", "kEachFrameSep"}; |
153 | | static const char * gFrameHowToEnableStr[] = {"kFrameEnableNone", "kFrameEnableAll", "kFrameEnableAsIsAndEach"}; |
154 | | static const char * gPrintRangeStr[] = {"kRangeAllPages", "kRangeSpecifiedPageRange", "kRangeSelection", "kRangeFocusFrame"}; |
155 | | |
156 | | // This processes the selection on aOrigDoc and creates an inverted selection on |
157 | | // aDoc, which it then deletes. If the start or end of the inverted selection |
158 | | // ranges occur in text nodes then an ellipsis is added. |
159 | | static nsresult DeleteUnselectedNodes(nsIDocument* aOrigDoc, nsIDocument* aDoc); |
160 | | |
161 | | #ifdef EXTENDED_DEBUG_PRINTING |
162 | | // Forward Declarations |
163 | | static void DumpPrintObjectsListStart(const char * aStr, const nsTArray<nsPrintObject*>& aDocList); |
164 | | static void DumpPrintObjectsTree(nsPrintObject * aPO, int aLevel= 0, FILE* aFD = nullptr); |
165 | | static void DumpPrintObjectsTreeLayout(const UniquePtr<nsPrintObject>& aPO, |
166 | | nsDeviceContext * aDC, int aLevel = 0, |
167 | | FILE * aFD = nullptr); |
168 | | |
169 | | #define DUMP_DOC_LIST(_title) DumpPrintObjectsListStart((_title), mPrt->mPrintDocList); |
170 | | #define DUMP_DOC_TREE DumpPrintObjectsTree(mPrt->mPrintObject.get()); |
171 | | #define DUMP_DOC_TREELAYOUT DumpPrintObjectsTreeLayout(mPrt->mPrintObject, mPrt->mPrintDC); |
172 | | #else |
173 | | #define DUMP_DOC_LIST(_title) |
174 | | #define DUMP_DOC_TREE |
175 | | #define DUMP_DOC_TREELAYOUT |
176 | | #endif |
177 | | |
178 | | class nsScriptSuppressor |
179 | | { |
180 | | public: |
181 | | explicit nsScriptSuppressor(nsPrintJob* aPrintJob) |
182 | | : mPrintJob(aPrintJob) |
183 | | , mSuppressed(false) |
184 | 0 | {} |
185 | | |
186 | 0 | ~nsScriptSuppressor() { Unsuppress(); } |
187 | | |
188 | | void Suppress() |
189 | 0 | { |
190 | 0 | if (mPrintJob) { |
191 | 0 | mSuppressed = true; |
192 | 0 | mPrintJob->TurnScriptingOn(false); |
193 | 0 | } |
194 | 0 | } |
195 | | |
196 | | void Unsuppress() |
197 | 0 | { |
198 | 0 | if (mPrintJob && mSuppressed) { |
199 | 0 | mPrintJob->TurnScriptingOn(true); |
200 | 0 | } |
201 | 0 | mSuppressed = false; |
202 | 0 | } |
203 | | |
204 | 0 | void Disconnect() { mPrintJob = nullptr; } |
205 | | protected: |
206 | | RefPtr<nsPrintJob> mPrintJob; |
207 | | bool mSuppressed; |
208 | | }; |
209 | | |
210 | | // ------------------------------------------------------- |
211 | | // Helpers |
212 | | // ------------------------------------------------------- |
213 | | |
214 | | static bool |
215 | | HasFramesetChild(nsIContent* aContent) |
216 | 0 | { |
217 | 0 | if (!aContent) { |
218 | 0 | return false; |
219 | 0 | } |
220 | 0 | |
221 | 0 | // do a breadth search across all siblings |
222 | 0 | for (nsIContent* child = aContent->GetFirstChild(); |
223 | 0 | child; |
224 | 0 | child = child->GetNextSibling()) { |
225 | 0 | if (child->IsHTMLElement(nsGkAtoms::frameset)) { |
226 | 0 | return true; |
227 | 0 | } |
228 | 0 | } |
229 | 0 |
|
230 | 0 | return false; |
231 | 0 | } |
232 | | |
233 | | static bool |
234 | | IsParentAFrameSet(nsIDocShell* aParent) |
235 | 0 | { |
236 | 0 | // See if the incoming doc is the root document |
237 | 0 | if (!aParent) return false; |
238 | 0 | |
239 | 0 | // When it is the top level document we need to check |
240 | 0 | // to see if it contains a frameset. If it does, then |
241 | 0 | // we only want to print the doc's children and not the document itself |
242 | 0 | // For anything else we always print all the children and the document |
243 | 0 | // for example, if the doc contains an IFRAME we eant to print the child |
244 | 0 | // document (the IFRAME) and then the rest of the document. |
245 | 0 | // |
246 | 0 | // XXX we really need to search the frame tree, and not the content |
247 | 0 | // but there is no way to distinguish between IFRAMEs and FRAMEs |
248 | 0 | // with the GetFrameType call. |
249 | 0 | // Bug 53459 has been files so we can eventually distinguish |
250 | 0 | // between IFRAME frames and FRAME frames |
251 | 0 | bool isFrameSet = false; |
252 | 0 | // only check to see if there is a frameset if there is |
253 | 0 | // NO parent doc for this doc. meaning this parent is the root doc |
254 | 0 | nsCOMPtr<nsIDocument> doc = aParent->GetDocument(); |
255 | 0 | if (doc) { |
256 | 0 | nsIContent *rootElement = doc->GetRootElement(); |
257 | 0 | if (rootElement) { |
258 | 0 | isFrameSet = HasFramesetChild(rootElement); |
259 | 0 | } |
260 | 0 | } |
261 | 0 | return isFrameSet; |
262 | 0 | } |
263 | | |
264 | | static nsPrintObject* |
265 | | FindPrintObjectByDOMWin(nsPrintObject* aPO, |
266 | | nsPIDOMWindowOuter* aDOMWin) |
267 | 0 | { |
268 | 0 | NS_ASSERTION(aPO, "Pointer is null!"); |
269 | 0 |
|
270 | 0 | // Often the CurFocused DOMWindow is passed in |
271 | 0 | // andit is valid for it to be null, so short circut |
272 | 0 | if (!aDOMWin) { |
273 | 0 | return nullptr; |
274 | 0 | } |
275 | 0 | |
276 | 0 | nsCOMPtr<nsIDocument> doc = aDOMWin->GetDoc(); |
277 | 0 | if (aPO->mDocument && aPO->mDocument->GetOriginalDocument() == doc) { |
278 | 0 | return aPO; |
279 | 0 | } |
280 | 0 | |
281 | 0 | for (const UniquePtr<nsPrintObject>& kid : aPO->mKids) { |
282 | 0 | nsPrintObject* po = FindPrintObjectByDOMWin(kid.get(), aDOMWin); |
283 | 0 | if (po) { |
284 | 0 | return po; |
285 | 0 | } |
286 | 0 | } |
287 | 0 |
|
288 | 0 | return nullptr; |
289 | 0 | } |
290 | | |
291 | | static void |
292 | | GetDocumentTitleAndURL(nsIDocument* aDoc, |
293 | | nsAString& aTitle, |
294 | | nsAString& aURLStr) |
295 | 0 | { |
296 | 0 | NS_ASSERTION(aDoc, "Pointer is null!"); |
297 | 0 |
|
298 | 0 | aTitle.Truncate(); |
299 | 0 | aURLStr.Truncate(); |
300 | 0 |
|
301 | 0 | aDoc->GetTitle(aTitle); |
302 | 0 |
|
303 | 0 | nsIURI* url = aDoc->GetDocumentURI(); |
304 | 0 | if (!url) return; |
305 | 0 | |
306 | 0 | nsCOMPtr<nsIURIFixup> urifixup(do_GetService(NS_URIFIXUP_CONTRACTID)); |
307 | 0 | if (!urifixup) return; |
308 | 0 | |
309 | 0 | nsCOMPtr<nsIURI> exposableURI; |
310 | 0 | urifixup->CreateExposableURI(url, getter_AddRefs(exposableURI)); |
311 | 0 |
|
312 | 0 | if (!exposableURI) return; |
313 | 0 | |
314 | 0 | nsAutoCString urlCStr; |
315 | 0 | nsresult rv = exposableURI->GetSpec(urlCStr); |
316 | 0 | if (NS_FAILED(rv)) return; |
317 | 0 | |
318 | 0 | nsCOMPtr<nsITextToSubURI> textToSubURI = |
319 | 0 | do_GetService(NS_ITEXTTOSUBURI_CONTRACTID, &rv); |
320 | 0 | if (NS_FAILED(rv)) return; |
321 | 0 | |
322 | 0 | textToSubURI->UnEscapeURIForUI(NS_LITERAL_CSTRING("UTF-8"), |
323 | 0 | urlCStr, aURLStr); |
324 | 0 | } |
325 | | |
326 | | static nsresult |
327 | | GetSeqFrameAndCountPagesInternal(const UniquePtr<nsPrintObject>& aPO, |
328 | | nsIFrame*& aSeqFrame, |
329 | | int32_t& aCount) |
330 | 0 | { |
331 | 0 | NS_ENSURE_ARG_POINTER(aPO); |
332 | 0 |
|
333 | 0 | // This is sometimes incorrectly called before the pres shell has been created |
334 | 0 | // (bug 1141756). MOZ_DIAGNOSTIC_ASSERT so we'll still see the crash in |
335 | 0 | // Nightly/Aurora in case the other patch fixes this. |
336 | 0 | if (!aPO->mPresShell) { |
337 | 0 | MOZ_DIAGNOSTIC_ASSERT(false, |
338 | 0 | "GetSeqFrameAndCountPages needs a non-null pres shell"); |
339 | 0 | return NS_ERROR_FAILURE; |
340 | 0 | } |
341 | 0 | |
342 | 0 | // Finds the SimplePageSequencer frame |
343 | 0 | nsIPageSequenceFrame* seqFrame = aPO->mPresShell->GetPageSequenceFrame(); |
344 | 0 | aSeqFrame = do_QueryFrame(seqFrame); |
345 | 0 | if (!aSeqFrame) { |
346 | 0 | return NS_ERROR_FAILURE; |
347 | 0 | } |
348 | 0 | |
349 | 0 | // count the total number of pages |
350 | 0 | aCount = aSeqFrame->PrincipalChildList().GetLength(); |
351 | 0 |
|
352 | 0 | return NS_OK; |
353 | 0 | } |
354 | | |
355 | | /** |
356 | | * Recursively sets the PO items to be printed "As Is" |
357 | | * from the given item down into the treei |
358 | | */ |
359 | | static void |
360 | | SetPrintAsIs(nsPrintObject* aPO, bool aAsIs = true) |
361 | 0 | { |
362 | 0 | NS_ASSERTION(aPO, "Pointer is null!"); |
363 | 0 |
|
364 | 0 | aPO->mPrintAsIs = aAsIs; |
365 | 0 | for (const UniquePtr<nsPrintObject>& kid : aPO->mKids) { |
366 | 0 | SetPrintAsIs(kid.get(), aAsIs); |
367 | 0 | } |
368 | 0 | } |
369 | | |
370 | | /** |
371 | | * This method is key to the entire print mechanism. |
372 | | * |
373 | | * This "maps" or figures out which sub-doc represents a |
374 | | * given Frame or IFrame in its parent sub-doc. |
375 | | * |
376 | | * So the Mcontent pointer in the child sub-doc points to the |
377 | | * content in the its parent document, that caused it to be printed. |
378 | | * This is used later to (after reflow) to find the absolute location |
379 | | * of the sub-doc on its parent's page frame so it can be |
380 | | * printed in the correct location. |
381 | | * |
382 | | * This method recursvely "walks" the content for a document finding |
383 | | * all the Frames and IFrames, then sets the "mFrameType" data member |
384 | | * which tells us what type of PO we have |
385 | | */ |
386 | | static void |
387 | | MapContentForPO(const UniquePtr<nsPrintObject>& aPO, |
388 | | nsIContent* aContent) |
389 | 0 | { |
390 | 0 | MOZ_ASSERT(aPO && aContent, "Null argument"); |
391 | 0 |
|
392 | 0 | nsIDocument* doc = aContent->GetComposedDoc(); |
393 | 0 |
|
394 | 0 | NS_ASSERTION(doc, "Content without a document from a document tree?"); |
395 | 0 |
|
396 | 0 | nsIDocument* subDoc = doc->GetSubDocumentFor(aContent); |
397 | 0 |
|
398 | 0 | if (subDoc) { |
399 | 0 | nsCOMPtr<nsIDocShell> docShell(subDoc->GetDocShell()); |
400 | 0 |
|
401 | 0 | if (docShell) { |
402 | 0 | nsPrintObject * po = nullptr; |
403 | 0 | for (const UniquePtr<nsPrintObject>& kid : aPO->mKids) { |
404 | 0 | if (kid->mDocument == subDoc) { |
405 | 0 | po = kid.get(); |
406 | 0 | break; |
407 | 0 | } |
408 | 0 | } |
409 | 0 |
|
410 | 0 | // XXX If a subdocument has no onscreen presentation, there will be no PO |
411 | 0 | // This is even if there should be a print presentation |
412 | 0 | if (po) { |
413 | 0 | // "frame" elements not in a frameset context should be treated |
414 | 0 | // as iframes |
415 | 0 | if (aContent->IsHTMLElement(nsGkAtoms::frame) && po->mParent->mFrameType == eFrameSet) { |
416 | 0 | po->mFrameType = eFrame; |
417 | 0 | } else { |
418 | 0 | // Assume something iframe-like, i.e. iframe, object, or embed |
419 | 0 | po->mFrameType = eIFrame; |
420 | 0 | SetPrintAsIs(po, true); |
421 | 0 | NS_ASSERTION(po->mParent, "The root must be a parent"); |
422 | 0 | po->mParent->mPrintAsIs = true; |
423 | 0 | } |
424 | 0 | } |
425 | 0 | } |
426 | 0 | } |
427 | 0 |
|
428 | 0 | // walk children content |
429 | 0 | for (nsIContent* child = aContent->GetFirstChild(); |
430 | 0 | child; |
431 | 0 | child = child->GetNextSibling()) { |
432 | 0 | MapContentForPO(aPO, child); |
433 | 0 | } |
434 | 0 | } |
435 | | |
436 | | /** |
437 | | * The walks the PO tree and for each document it walks the content |
438 | | * tree looking for any content that are sub-shells |
439 | | * |
440 | | * It then sets the mContent pointer in the "found" PO object back to the |
441 | | * the document that contained it. |
442 | | */ |
443 | | static void |
444 | | MapContentToWebShells(const UniquePtr<nsPrintObject>& aRootPO, |
445 | | const UniquePtr<nsPrintObject>& aPO) |
446 | 0 | { |
447 | 0 | NS_ASSERTION(aRootPO, "Pointer is null!"); |
448 | 0 | NS_ASSERTION(aPO, "Pointer is null!"); |
449 | 0 |
|
450 | 0 | // Recursively walk the content from the root item |
451 | 0 | // XXX Would be faster to enumerate the subdocuments, although right now |
452 | 0 | // nsIDocument doesn't expose quite what would be needed. |
453 | 0 | nsCOMPtr<nsIContentViewer> viewer; |
454 | 0 | aPO->mDocShell->GetContentViewer(getter_AddRefs(viewer)); |
455 | 0 | if (!viewer) return; |
456 | 0 | |
457 | 0 | nsCOMPtr<nsIDocument> doc = viewer->GetDocument(); |
458 | 0 | if (!doc) return; |
459 | 0 | |
460 | 0 | Element* rootElement = doc->GetRootElement(); |
461 | 0 | if (rootElement) { |
462 | 0 | MapContentForPO(aPO, rootElement); |
463 | 0 | } else { |
464 | 0 | NS_WARNING("Null root content on (sub)document."); |
465 | 0 | } |
466 | 0 |
|
467 | 0 | // Continue recursively walking the chilren of this PO |
468 | 0 | for (const UniquePtr<nsPrintObject>& kid : aPO->mKids) { |
469 | 0 | MapContentToWebShells(aRootPO, kid); |
470 | 0 | } |
471 | 0 |
|
472 | 0 | } |
473 | | |
474 | | |
475 | | //------------------------------------------------------- |
476 | | |
477 | | NS_IMPL_ISUPPORTS(nsPrintJob, nsIWebProgressListener, |
478 | | nsISupportsWeakReference, nsIObserver) |
479 | | |
480 | | //------------------------------------------------------- |
481 | | nsPrintJob::~nsPrintJob() |
482 | 0 | { |
483 | 0 | Destroy(); // for insurance |
484 | 0 | DisconnectPagePrintTimer(); |
485 | 0 | } |
486 | | |
487 | | //------------------------------------------------------- |
488 | | void |
489 | | nsPrintJob::Destroy() |
490 | 0 | { |
491 | 0 | if (mIsDestroying) { |
492 | 0 | return; |
493 | 0 | } |
494 | 0 | mIsDestroying = true; |
495 | 0 |
|
496 | 0 | mPrt = nullptr; |
497 | 0 |
|
498 | 0 | #ifdef NS_PRINT_PREVIEW |
499 | 0 | mPrtPreview = nullptr; |
500 | 0 | mOldPrtPreview = nullptr; |
501 | 0 | #endif |
502 | 0 | mDocViewerPrint = nullptr; |
503 | 0 | } |
504 | | |
505 | | //------------------------------------------------------- |
506 | | void |
507 | | nsPrintJob::DestroyPrintingData() |
508 | 0 | { |
509 | 0 | mPrt = nullptr; |
510 | 0 | } |
511 | | |
512 | | //--------------------------------------------------------------------------------- |
513 | | //-- Section: Methods needed by the DocViewer |
514 | | //--------------------------------------------------------------------------------- |
515 | | |
516 | | //-------------------------------------------------------- |
517 | | nsresult |
518 | | nsPrintJob::Initialize(nsIDocumentViewerPrint* aDocViewerPrint, |
519 | | nsIDocShell* aContainer, |
520 | | nsIDocument* aDocument, |
521 | | float aScreenDPI) |
522 | 0 | { |
523 | 0 | NS_ENSURE_ARG_POINTER(aDocViewerPrint); |
524 | 0 | NS_ENSURE_ARG_POINTER(aContainer); |
525 | 0 | NS_ENSURE_ARG_POINTER(aDocument); |
526 | 0 |
|
527 | 0 | mDocViewerPrint = aDocViewerPrint; |
528 | 0 | mContainer = do_GetWeakReference(aContainer); |
529 | 0 | mDocument = aDocument; |
530 | 0 | mScreenDPI = aScreenDPI; |
531 | 0 |
|
532 | 0 | return NS_OK; |
533 | 0 | } |
534 | | |
535 | | //------------------------------------------------------- |
536 | | bool |
537 | | nsPrintJob::CheckBeforeDestroy() |
538 | 0 | { |
539 | 0 | if (mPrt && mPrt->mPreparingForPrint) { |
540 | 0 | mPrt->mDocWasToBeDestroyed = true; |
541 | 0 | return true; |
542 | 0 | } |
543 | 0 | return false; |
544 | 0 | } |
545 | | |
546 | | //------------------------------------------------------- |
547 | | nsresult |
548 | | nsPrintJob::Cancelled() |
549 | 0 | { |
550 | 0 | if (mPrt && mPrt->mPrintSettings) { |
551 | 0 | return mPrt->mPrintSettings->SetIsCancelled(true); |
552 | 0 | } |
553 | 0 | return NS_ERROR_FAILURE; |
554 | 0 | } |
555 | | |
556 | | //------------------------------------------------------- |
557 | | // Install our event listeners on the document to prevent |
558 | | // some events from being processed while in PrintPreview |
559 | | // |
560 | | // No return code - if this fails, there isn't much we can do |
561 | | void |
562 | | nsPrintJob::InstallPrintPreviewListener() |
563 | 0 | { |
564 | 0 | if (!mPrt->mPPEventListeners) { |
565 | 0 | nsCOMPtr<nsIDocShell> docShell = do_QueryReferent(mContainer); |
566 | 0 | if (!docShell) { |
567 | 0 | return; |
568 | 0 | } |
569 | 0 | |
570 | 0 | if (nsPIDOMWindowOuter* win = docShell->GetWindow()) { |
571 | 0 | nsCOMPtr<EventTarget> target = win->GetFrameElementInternal(); |
572 | 0 | mPrt->mPPEventListeners = new nsPrintPreviewListener(target); |
573 | 0 | mPrt->mPPEventListeners->AddListeners(); |
574 | 0 | } |
575 | 0 | } |
576 | 0 | } |
577 | | |
578 | | //----------------------------------------------------------------- |
579 | | nsresult |
580 | | nsPrintJob::GetSeqFrameAndCountPages(nsIFrame*& aSeqFrame, int32_t& aCount) |
581 | 0 | { |
582 | 0 | MOZ_ASSERT(mPrtPreview); |
583 | 0 | // Guarantee that mPrintPreview->mPrintObject won't be deleted during a call |
584 | 0 | // of GetSeqFrameAndCountPagesInternal(). |
585 | 0 | RefPtr<nsPrintData> printDataForPrintPreview = mPrtPreview; |
586 | 0 | return GetSeqFrameAndCountPagesInternal( |
587 | 0 | printDataForPrintPreview->mPrintObject, aSeqFrame, aCount); |
588 | 0 | } |
589 | | //--------------------------------------------------------------------------------- |
590 | | //-- Done: Methods needed by the DocViewer |
591 | | //--------------------------------------------------------------------------------- |
592 | | |
593 | | |
594 | | //--------------------------------------------------------------------------------- |
595 | | //-- Section: nsIWebBrowserPrint |
596 | | //--------------------------------------------------------------------------------- |
597 | | |
598 | | // Foward decl for Debug Helper Functions |
599 | | #ifdef EXTENDED_DEBUG_PRINTING |
600 | | #ifdef XP_WIN |
601 | | static int RemoveFilesInDir(const char * aDir); |
602 | | #endif |
603 | | static void GetDocTitleAndURL(const UniquePtr<nsPrintObject>& aPO, |
604 | | nsACString& aDocStr, |
605 | | nsACString& aURLStr); |
606 | | static void DumpPrintObjectsTree(nsPrintObject * aPO, int aLevel, FILE* aFD); |
607 | | static void DumpPrintObjectsList(const nsTArray<nsPrintObject*>& aDocList); |
608 | | static void RootFrameList(nsPresContext* aPresContext, FILE* out, |
609 | | const char* aPrefix); |
610 | | static void DumpViews(nsIDocShell* aDocShell, FILE* out); |
611 | | static void DumpLayoutData(const char* aTitleStr, const char* aURLStr, |
612 | | nsPresContext* aPresContext, |
613 | | nsDeviceContext * aDC, nsIFrame * aRootFrame, |
614 | | nsIDocShell * aDocShell, FILE* aFD); |
615 | | #endif |
616 | | |
617 | | //-------------------------------------------------------------------------------- |
618 | | |
619 | | nsresult |
620 | | nsPrintJob::CommonPrint(bool aIsPrintPreview, |
621 | | nsIPrintSettings* aPrintSettings, |
622 | | nsIWebProgressListener* aWebProgressListener, |
623 | | nsIDocument* aDoc) |
624 | 0 | { |
625 | 0 | // Callers must hold a strong reference to |this| to ensure that we stay |
626 | 0 | // alive for the duration of this method, because our main owning reference |
627 | 0 | // (on nsDocumentViewer) might be cleared during this function (if we cause |
628 | 0 | // script to run and it cancels the print operation). |
629 | 0 |
|
630 | 0 | nsresult rv = DoCommonPrint(aIsPrintPreview, aPrintSettings, |
631 | 0 | aWebProgressListener, aDoc); |
632 | 0 | if (NS_FAILED(rv)) { |
633 | 0 | if (aIsPrintPreview) { |
634 | 0 | mIsCreatingPrintPreview = false; |
635 | 0 | SetIsPrintPreview(false); |
636 | 0 | } else { |
637 | 0 | SetIsPrinting(false); |
638 | 0 | } |
639 | 0 | if (mProgressDialogIsShown) |
640 | 0 | CloseProgressDialog(aWebProgressListener); |
641 | 0 | if (rv != NS_ERROR_ABORT && rv != NS_ERROR_OUT_OF_MEMORY) { |
642 | 0 | FirePrintingErrorEvent(rv); |
643 | 0 | } |
644 | 0 | mPrt = nullptr; |
645 | 0 | } |
646 | 0 |
|
647 | 0 | return rv; |
648 | 0 | } |
649 | | |
650 | | nsresult |
651 | | nsPrintJob::DoCommonPrint(bool aIsPrintPreview, |
652 | | nsIPrintSettings* aPrintSettings, |
653 | | nsIWebProgressListener* aWebProgressListener, |
654 | | nsIDocument* aDoc) |
655 | 0 | { |
656 | 0 | nsresult rv; |
657 | 0 |
|
658 | 0 | if (aIsPrintPreview) { |
659 | 0 | // The WebProgressListener can be QI'ed to nsIPrintingPromptService |
660 | 0 | // then that means the progress dialog is already being shown. |
661 | 0 | nsCOMPtr<nsIPrintingPromptService> pps(do_QueryInterface(aWebProgressListener)); |
662 | 0 | mProgressDialogIsShown = pps != nullptr; |
663 | 0 |
|
664 | 0 | if (mIsDoingPrintPreview) { |
665 | 0 | mOldPrtPreview = std::move(mPrtPreview); |
666 | 0 | } |
667 | 0 | } else { |
668 | 0 | mProgressDialogIsShown = false; |
669 | 0 | } |
670 | 0 |
|
671 | 0 | // Grab the new instance with local variable to guarantee that it won't be |
672 | 0 | // deleted during this method. |
673 | 0 | mPrt = new nsPrintData(aIsPrintPreview ? nsPrintData::eIsPrintPreview : |
674 | 0 | nsPrintData::eIsPrinting); |
675 | 0 | RefPtr<nsPrintData> printData = mPrt; |
676 | 0 |
|
677 | 0 | // if they don't pass in a PrintSettings, then get the Global PS |
678 | 0 | printData->mPrintSettings = aPrintSettings; |
679 | 0 | if (!printData->mPrintSettings) { |
680 | 0 | rv = GetGlobalPrintSettings(getter_AddRefs(printData->mPrintSettings)); |
681 | 0 | NS_ENSURE_SUCCESS(rv, rv); |
682 | 0 | } |
683 | 0 |
|
684 | 0 | rv = CheckForPrinters(printData->mPrintSettings); |
685 | 0 | NS_ENSURE_SUCCESS(rv, rv); |
686 | 0 |
|
687 | 0 | printData->mPrintSettings->SetIsCancelled(false); |
688 | 0 | printData->mPrintSettings->GetShrinkToFit(&printData->mShrinkToFit); |
689 | 0 |
|
690 | 0 | if (aIsPrintPreview) { |
691 | 0 | mIsCreatingPrintPreview = true; |
692 | 0 | SetIsPrintPreview(true); |
693 | 0 | nsCOMPtr<nsIContentViewer> viewer = |
694 | 0 | do_QueryInterface(mDocViewerPrint); |
695 | 0 | if (viewer) { |
696 | 0 | viewer->SetTextZoom(1.0f); |
697 | 0 | viewer->SetFullZoom(1.0f); |
698 | 0 | viewer->SetMinFontSize(0); |
699 | 0 | } |
700 | 0 | } |
701 | 0 |
|
702 | 0 | // Create a print session and let the print settings know about it. |
703 | 0 | // Don't overwrite an existing print session. |
704 | 0 | // The print settings hold an nsWeakPtr to the session so it does not |
705 | 0 | // need to be cleared from the settings at the end of the job. |
706 | 0 | // XXX What lifetime does the printSession need to have? |
707 | 0 | nsCOMPtr<nsIPrintSession> printSession; |
708 | 0 | bool remotePrintJobListening = false; |
709 | 0 | if (!aIsPrintPreview) { |
710 | 0 | rv = printData->mPrintSettings->GetPrintSession( |
711 | 0 | getter_AddRefs(printSession)); |
712 | 0 | if (NS_FAILED(rv) || !printSession) { |
713 | 0 | printSession = do_CreateInstance("@mozilla.org/gfx/printsession;1", &rv); |
714 | 0 | NS_ENSURE_SUCCESS(rv, rv); |
715 | 0 | printData->mPrintSettings->SetPrintSession(printSession); |
716 | 0 | } else { |
717 | 0 | RefPtr<mozilla::layout::RemotePrintJobChild> remotePrintJob; |
718 | 0 | printSession->GetRemotePrintJob(getter_AddRefs(remotePrintJob)); |
719 | 0 | if (NS_SUCCEEDED(rv) && remotePrintJob) { |
720 | 0 | // If we have a RemotePrintJob add it to the print progress listeners, |
721 | 0 | // so it can forward to the parent. |
722 | 0 | printData->mPrintProgressListeners.AppendElement(remotePrintJob); |
723 | 0 | remotePrintJobListening = true; |
724 | 0 | } |
725 | 0 | } |
726 | 0 |
|
727 | 0 | } |
728 | 0 |
|
729 | 0 | if (aWebProgressListener != nullptr) { |
730 | 0 | printData->mPrintProgressListeners.AppendObject(aWebProgressListener); |
731 | 0 | } |
732 | 0 |
|
733 | 0 | // Get the currently focused window and cache it |
734 | 0 | // because the Print Dialog will "steal" focus and later when you try |
735 | 0 | // to get the currently focused windows it will be nullptr |
736 | 0 | printData->mCurrentFocusWin = FindFocusedDOMWindow(); |
737 | 0 |
|
738 | 0 | // Check to see if there is a "regular" selection |
739 | 0 | bool isSelection = IsThereARangeSelection(printData->mCurrentFocusWin); |
740 | 0 |
|
741 | 0 | // Get the docshell for this documentviewer |
742 | 0 | nsCOMPtr<nsIDocShell> webContainer(do_QueryReferent(mContainer, &rv)); |
743 | 0 | NS_ENSURE_SUCCESS(rv, rv); |
744 | 0 |
|
745 | 0 | { |
746 | 0 | if (aIsPrintPreview) { |
747 | 0 | nsCOMPtr<nsIContentViewer> viewer; |
748 | 0 | webContainer->GetContentViewer(getter_AddRefs(viewer)); |
749 | 0 | if (viewer && viewer->GetDocument() && viewer->GetDocument()->IsShowing()) { |
750 | 0 | viewer->GetDocument()->OnPageHide(false, nullptr); |
751 | 0 | } |
752 | 0 | } |
753 | 0 |
|
754 | 0 | nsAutoScriptBlocker scriptBlocker; |
755 | 0 | printData->mPrintObject = MakeUnique<nsPrintObject>(); |
756 | 0 | rv = printData->mPrintObject->Init(webContainer, aDoc, aIsPrintPreview); |
757 | 0 | NS_ENSURE_SUCCESS(rv, rv); |
758 | 0 |
|
759 | 0 | NS_ENSURE_TRUE(printData->mPrintDocList.AppendElement( |
760 | 0 | printData->mPrintObject.get()), |
761 | 0 | NS_ERROR_OUT_OF_MEMORY); |
762 | 0 |
|
763 | 0 | printData->mIsParentAFrameSet = IsParentAFrameSet(webContainer); |
764 | 0 | printData->mPrintObject->mFrameType = |
765 | 0 | printData->mIsParentAFrameSet ? eFrameSet : eDoc; |
766 | 0 |
|
767 | 0 | // Build the "tree" of PrintObjects |
768 | 0 | BuildDocTree(printData->mPrintObject->mDocShell, &printData->mPrintDocList, |
769 | 0 | printData->mPrintObject); |
770 | 0 | } |
771 | 0 |
|
772 | 0 | // The nsAutoScriptBlocker above will now have been destroyed, which may |
773 | 0 | // cause our print/print-preview operation to finish. In this case, we |
774 | 0 | // should immediately return an error code so that the root caller knows |
775 | 0 | // it shouldn't continue to do anything with this instance. |
776 | 0 | if (mIsDestroying || (aIsPrintPreview && !mIsCreatingPrintPreview)) { |
777 | 0 | return NS_ERROR_FAILURE; |
778 | 0 | } |
779 | 0 | |
780 | 0 | if (!aIsPrintPreview) { |
781 | 0 | SetIsPrinting(true); |
782 | 0 | } |
783 | 0 |
|
784 | 0 | // XXX This isn't really correct... |
785 | 0 | if (!printData->mPrintObject->mDocument || |
786 | 0 | !printData->mPrintObject->mDocument->GetRootElement()) |
787 | 0 | return NS_ERROR_GFX_PRINTER_STARTDOC; |
788 | 0 | |
789 | 0 | // Create the linkage from the sub-docs back to the content element |
790 | 0 | // in the parent document |
791 | 0 | MapContentToWebShells(printData->mPrintObject, printData->mPrintObject); |
792 | 0 |
|
793 | 0 | printData->mIsIFrameSelected = |
794 | 0 | IsThereAnIFrameSelected(webContainer, printData->mCurrentFocusWin, |
795 | 0 | printData->mIsParentAFrameSet); |
796 | 0 |
|
797 | 0 | // Setup print options for UI |
798 | 0 | if (printData->mIsParentAFrameSet) { |
799 | 0 | if (printData->mCurrentFocusWin) { |
800 | 0 | printData->mPrintSettings->SetHowToEnableFrameUI(nsIPrintSettings::kFrameEnableAll); |
801 | 0 | } else { |
802 | 0 | printData->mPrintSettings->SetHowToEnableFrameUI(nsIPrintSettings::kFrameEnableAsIsAndEach); |
803 | 0 | } |
804 | 0 | } else { |
805 | 0 | printData->mPrintSettings->SetHowToEnableFrameUI(nsIPrintSettings::kFrameEnableNone); |
806 | 0 | } |
807 | 0 | // Now determine how to set up the Frame print UI |
808 | 0 | printData->mPrintSettings->SetPrintOptions( |
809 | 0 | nsIPrintSettings::kEnableSelectionRB, |
810 | 0 | isSelection || printData->mIsIFrameSelected); |
811 | 0 |
|
812 | 0 | bool printingViaParent = XRE_IsContentProcess() && |
813 | 0 | Preferences::GetBool("print.print_via_parent"); |
814 | 0 | nsCOMPtr<nsIDeviceContextSpec> devspec; |
815 | 0 | if (printingViaParent) { |
816 | 0 | devspec = new nsDeviceContextSpecProxy(); |
817 | 0 | } else { |
818 | 0 | devspec = do_CreateInstance("@mozilla.org/gfx/devicecontextspec;1", &rv); |
819 | 0 | NS_ENSURE_SUCCESS(rv, rv); |
820 | 0 | } |
821 | 0 |
|
822 | 0 | nsScriptSuppressor scriptSuppressor(this); |
823 | 0 | // If printing via parent we still call ShowPrintDialog even for print preview |
824 | 0 | // because we use that to retrieve the print settings from the printer. |
825 | 0 | // The dialog is not shown, but this means we don't need to access the printer |
826 | 0 | // driver from the child, which causes sandboxing issues. |
827 | 0 | if (!aIsPrintPreview || printingViaParent) { |
828 | 0 | scriptSuppressor.Suppress(); |
829 | 0 | bool printSilently; |
830 | 0 | printData->mPrintSettings->GetPrintSilent(&printSilently); |
831 | 0 |
|
832 | 0 | // Check prefs for a default setting as to whether we should print silently |
833 | 0 | printSilently = |
834 | 0 | Preferences::GetBool("print.always_print_silent", printSilently); |
835 | 0 |
|
836 | 0 | // Ask dialog to be Print Shown via the Plugable Printing Dialog Service |
837 | 0 | // This service is for the Print Dialog and the Print Progress Dialog |
838 | 0 | // If printing silently or you can't get the service continue on |
839 | 0 | // If printing via the parent then we need to confirm that the pref is set |
840 | 0 | // and get a remote print job, but the parent won't display a prompt. |
841 | 0 | if (!printSilently || printingViaParent) { |
842 | 0 | nsCOMPtr<nsIPrintingPromptService> printPromptService(do_GetService(kPrintingPromptService)); |
843 | 0 | if (printPromptService) { |
844 | 0 | nsPIDOMWindowOuter* domWin = nullptr; |
845 | 0 | // We leave domWin as nullptr to indicate a call for print preview. |
846 | 0 | if (!aIsPrintPreview) { |
847 | 0 | domWin = mDocument->GetWindow(); |
848 | 0 | NS_ENSURE_TRUE(domWin, NS_ERROR_FAILURE); |
849 | 0 | } |
850 | 0 |
|
851 | 0 | // Platforms not implementing a given dialog for the service may |
852 | 0 | // return NS_ERROR_NOT_IMPLEMENTED or an error code. |
853 | 0 | // |
854 | 0 | // NS_ERROR_NOT_IMPLEMENTED indicates they want default behavior |
855 | 0 | // Any other error code means we must bail out |
856 | 0 | // |
857 | 0 | nsCOMPtr<nsIWebBrowserPrint> wbp(do_QueryInterface(mDocViewerPrint)); |
858 | 0 | rv = printPromptService->ShowPrintDialog(domWin, wbp, |
859 | 0 | printData->mPrintSettings); |
860 | 0 | // |
861 | 0 | // ShowPrintDialog triggers an event loop which means we can't assume |
862 | 0 | // that the state of this->{anything} matches the state we've checked |
863 | 0 | // above. Including that a given {thing} is non null. |
864 | 0 | if (NS_WARN_IF(mPrt != printData)) { |
865 | 0 | return NS_ERROR_FAILURE; |
866 | 0 | } |
867 | 0 | |
868 | 0 | if (NS_SUCCEEDED(rv)) { |
869 | 0 | // since we got the dialog and it worked then make sure we |
870 | 0 | // are telling GFX we want to print silent |
871 | 0 | printSilently = true; |
872 | 0 |
|
873 | 0 | if (printData->mPrintSettings && !aIsPrintPreview) { |
874 | 0 | // The user might have changed shrink-to-fit in the print dialog, so update our copy of its state |
875 | 0 | printData->mPrintSettings->GetShrinkToFit(&printData->mShrinkToFit); |
876 | 0 |
|
877 | 0 | // If we haven't already added the RemotePrintJob as a listener, |
878 | 0 | // add it now if there is one. |
879 | 0 | if (!remotePrintJobListening) { |
880 | 0 | RefPtr<mozilla::layout::RemotePrintJobChild> remotePrintJob; |
881 | 0 | printSession->GetRemotePrintJob(getter_AddRefs(remotePrintJob)); |
882 | 0 | if (NS_SUCCEEDED(rv) && remotePrintJob) { |
883 | 0 | printData->mPrintProgressListeners.AppendElement( |
884 | 0 | remotePrintJob); |
885 | 0 | remotePrintJobListening = true; |
886 | 0 | } |
887 | 0 | } |
888 | 0 | } |
889 | 0 | } else if (rv == NS_ERROR_NOT_IMPLEMENTED) { |
890 | 0 | // This means the Dialog service was there, |
891 | 0 | // but they choose not to implement this dialog and |
892 | 0 | // are looking for default behavior from the toolkit |
893 | 0 | rv = NS_OK; |
894 | 0 | } |
895 | 0 | } else { |
896 | 0 | // No dialog service available |
897 | 0 | rv = NS_ERROR_NOT_IMPLEMENTED; |
898 | 0 | } |
899 | 0 | } else { |
900 | 0 | // Call any code that requires a run of the event loop. |
901 | 0 | rv = printData->mPrintSettings->SetupSilentPrinting(); |
902 | 0 | } |
903 | 0 | // Check explicitly for abort because it's expected |
904 | 0 | if (rv == NS_ERROR_ABORT) |
905 | 0 | return rv; |
906 | 0 | NS_ENSURE_SUCCESS(rv, rv); |
907 | 0 | } |
908 | 0 |
|
909 | 0 | rv = devspec->Init(nullptr, printData->mPrintSettings, aIsPrintPreview); |
910 | 0 | NS_ENSURE_SUCCESS(rv, rv); |
911 | 0 |
|
912 | 0 | printData->mPrintDC = new nsDeviceContext(); |
913 | 0 | rv = printData->mPrintDC->InitForPrinting(devspec); |
914 | 0 | NS_ENSURE_SUCCESS(rv, rv); |
915 | 0 |
|
916 | 0 | if (XRE_IsParentProcess() && !printData->mPrintDC->IsSyncPagePrinting()) { |
917 | 0 | RefPtr<nsPrintJob> self(this); |
918 | 0 | printData->mPrintDC->RegisterPageDoneCallback([self](nsresult aResult) { self->PageDone(aResult); }); |
919 | 0 | } |
920 | 0 |
|
921 | 0 | if (aIsPrintPreview) { |
922 | 0 | printData->mPrintSettings->SetPrintFrameType(nsIPrintSettings::kFramesAsIs); |
923 | 0 |
|
924 | 0 | // override any UI that wants to PrintPreview any selection or page range |
925 | 0 | // we want to view every page in PrintPreview each time |
926 | 0 | printData->mPrintSettings->SetPrintRange(nsIPrintSettings::kRangeAllPages); |
927 | 0 | } else { |
928 | 0 | // Always check and set the print settings first and then fall back |
929 | 0 | // onto the PrintService if there isn't a PrintSettings |
930 | 0 | // |
931 | 0 | // Posiible Usage values: |
932 | 0 | // nsIPrintSettings::kUseInternalDefault |
933 | 0 | // nsIPrintSettings::kUseSettingWhenPossible |
934 | 0 | // |
935 | 0 | // NOTE: The consts are the same for PrintSettings and PrintSettings |
936 | 0 | int16_t printFrameTypeUsage = nsIPrintSettings::kUseSettingWhenPossible; |
937 | 0 | printData->mPrintSettings->GetPrintFrameTypeUsage(&printFrameTypeUsage); |
938 | 0 |
|
939 | 0 | // Ok, see if we are going to use our value and override the default |
940 | 0 | if (printFrameTypeUsage == nsIPrintSettings::kUseSettingWhenPossible) { |
941 | 0 | // Get the Print Options/Settings PrintFrameType to see what is preferred |
942 | 0 | int16_t printFrameType = nsIPrintSettings::kEachFrameSep; |
943 | 0 | printData->mPrintSettings->GetPrintFrameType(&printFrameType); |
944 | 0 |
|
945 | 0 | // Don't let anybody do something stupid like try to set it to |
946 | 0 | // kNoFrames when we are printing a FrameSet |
947 | 0 | if (printFrameType == nsIPrintSettings::kNoFrames) { |
948 | 0 | printData->mPrintFrameType = nsIPrintSettings::kEachFrameSep; |
949 | 0 | printData->mPrintSettings->SetPrintFrameType( |
950 | 0 | printData->mPrintFrameType); |
951 | 0 | } else { |
952 | 0 | // First find out from the PrinService what options are available |
953 | 0 | // to us for Printing FrameSets |
954 | 0 | int16_t howToEnableFrameUI; |
955 | 0 | printData->mPrintSettings->GetHowToEnableFrameUI(&howToEnableFrameUI); |
956 | 0 | if (howToEnableFrameUI != nsIPrintSettings::kFrameEnableNone) { |
957 | 0 | switch (howToEnableFrameUI) { |
958 | 0 | case nsIPrintSettings::kFrameEnableAll: |
959 | 0 | printData->mPrintFrameType = printFrameType; |
960 | 0 | break; |
961 | 0 |
|
962 | 0 | case nsIPrintSettings::kFrameEnableAsIsAndEach: |
963 | 0 | if (printFrameType != nsIPrintSettings::kSelectedFrame) { |
964 | 0 | printData->mPrintFrameType = printFrameType; |
965 | 0 | } else { // revert back to a good value |
966 | 0 | printData->mPrintFrameType = nsIPrintSettings::kEachFrameSep; |
967 | 0 | } |
968 | 0 | break; |
969 | 0 | } // switch |
970 | 0 | printData->mPrintSettings->SetPrintFrameType( |
971 | 0 | printData->mPrintFrameType); |
972 | 0 | } |
973 | 0 | } |
974 | 0 | } else { |
975 | 0 | printData->mPrintSettings->GetPrintFrameType(&printData->mPrintFrameType); |
976 | 0 | } |
977 | 0 | } |
978 | 0 |
|
979 | 0 | if (printData->mPrintFrameType == nsIPrintSettings::kEachFrameSep) { |
980 | 0 | CheckForChildFrameSets(printData->mPrintObject); |
981 | 0 | } |
982 | 0 |
|
983 | 0 | if (NS_FAILED(EnablePOsForPrinting())) { |
984 | 0 | return NS_ERROR_FAILURE; |
985 | 0 | } |
986 | 0 | |
987 | 0 | // Attach progressListener to catch network requests. |
988 | 0 | nsCOMPtr<nsIWebProgress> webProgress = |
989 | 0 | do_QueryInterface(printData->mPrintObject->mDocShell); |
990 | 0 | webProgress->AddProgressListener( |
991 | 0 | static_cast<nsIWebProgressListener*>(this), |
992 | 0 | nsIWebProgress::NOTIFY_STATE_REQUEST); |
993 | 0 |
|
994 | 0 | mLoadCounter = 0; |
995 | 0 | mDidLoadDataForPrinting = false; |
996 | 0 |
|
997 | 0 | if (aIsPrintPreview) { |
998 | 0 | bool notifyOnInit = false; |
999 | 0 | ShowPrintProgress(false, notifyOnInit); |
1000 | 0 |
|
1001 | 0 | // Very important! Turn Off scripting |
1002 | 0 | TurnScriptingOn(false); |
1003 | 0 |
|
1004 | 0 | if (!notifyOnInit) { |
1005 | 0 | InstallPrintPreviewListener(); |
1006 | 0 | rv = InitPrintDocConstruction(false); |
1007 | 0 | } else { |
1008 | 0 | rv = NS_OK; |
1009 | 0 | } |
1010 | 0 | } else { |
1011 | 0 | bool doNotify; |
1012 | 0 | ShowPrintProgress(true, doNotify); |
1013 | 0 | if (!doNotify) { |
1014 | 0 | // Print listener setup... |
1015 | 0 | printData->OnStartPrinting(); |
1016 | 0 |
|
1017 | 0 | rv = InitPrintDocConstruction(false); |
1018 | 0 | } |
1019 | 0 | } |
1020 | 0 |
|
1021 | 0 | // We will enable scripting later after printing has finished. |
1022 | 0 | scriptSuppressor.Disconnect(); |
1023 | 0 |
|
1024 | 0 | return NS_OK; |
1025 | 0 | } |
1026 | | |
1027 | | //--------------------------------------------------------------------------------- |
1028 | | NS_IMETHODIMP |
1029 | | nsPrintJob::Print(nsIPrintSettings* aPrintSettings, |
1030 | | nsIWebProgressListener* aWebProgressListener) |
1031 | 0 | { |
1032 | 0 | // If we have a print preview document, use that instead of the original |
1033 | 0 | // mDocument. That way animated images etc. get printed using the same state |
1034 | 0 | // as in print preview. |
1035 | 0 | nsIDocument* doc = |
1036 | 0 | mPrtPreview && mPrtPreview->mPrintObject ? |
1037 | 0 | mPrtPreview->mPrintObject->mDocument : mDocument; |
1038 | 0 |
|
1039 | 0 | return CommonPrint(false, aPrintSettings, aWebProgressListener, doc); |
1040 | 0 | } |
1041 | | |
1042 | | NS_IMETHODIMP |
1043 | | nsPrintJob::PrintPreview(nsIPrintSettings* aPrintSettings, |
1044 | | mozIDOMWindowProxy* aChildDOMWin, |
1045 | | nsIWebProgressListener* aWebProgressListener) |
1046 | 0 | { |
1047 | 0 | // Get the DocShell and see if it is busy |
1048 | 0 | // (We can't Print Preview this document if it is still busy) |
1049 | 0 | nsCOMPtr<nsIDocShell> docShell(do_QueryReferent(mContainer)); |
1050 | 0 | NS_ENSURE_STATE(docShell); |
1051 | 0 |
|
1052 | 0 | uint32_t busyFlags = nsIDocShell::BUSY_FLAGS_NONE; |
1053 | 0 | if (NS_FAILED(docShell->GetBusyFlags(&busyFlags)) || |
1054 | 0 | busyFlags != nsIDocShell::BUSY_FLAGS_NONE) { |
1055 | 0 | CloseProgressDialog(aWebProgressListener); |
1056 | 0 | FirePrintingErrorEvent(NS_ERROR_GFX_PRINTER_DOC_IS_BUSY); |
1057 | 0 | return NS_ERROR_FAILURE; |
1058 | 0 | } |
1059 | 0 | |
1060 | 0 | auto* window = nsPIDOMWindowOuter::From(aChildDOMWin); |
1061 | 0 | NS_ENSURE_STATE(window); |
1062 | 0 | nsCOMPtr<nsIDocument> doc = window->GetDoc(); |
1063 | 0 | NS_ENSURE_STATE(doc); |
1064 | 0 |
|
1065 | 0 | // Document is not busy -- go ahead with the Print Preview |
1066 | 0 | return CommonPrint(true, aPrintSettings, aWebProgressListener, doc); |
1067 | 0 | } |
1068 | | |
1069 | | //---------------------------------------------------------------------------------- |
1070 | | NS_IMETHODIMP |
1071 | | nsPrintJob::GetIsFramesetDocument(bool* aIsFramesetDocument) |
1072 | 0 | { |
1073 | 0 | nsCOMPtr<nsIDocShell> webContainer(do_QueryReferent(mContainer)); |
1074 | 0 | *aIsFramesetDocument = IsParentAFrameSet(webContainer); |
1075 | 0 | return NS_OK; |
1076 | 0 | } |
1077 | | |
1078 | | //---------------------------------------------------------------------------------- |
1079 | | NS_IMETHODIMP |
1080 | | nsPrintJob::GetIsIFrameSelected(bool* aIsIFrameSelected) |
1081 | 0 | { |
1082 | 0 | *aIsIFrameSelected = false; |
1083 | 0 |
|
1084 | 0 | // Get the docshell for this documentviewer |
1085 | 0 | nsCOMPtr<nsIDocShell> webContainer(do_QueryReferent(mContainer)); |
1086 | 0 | // Get the currently focused window |
1087 | 0 | nsCOMPtr<nsPIDOMWindowOuter> currentFocusWin = FindFocusedDOMWindow(); |
1088 | 0 | if (currentFocusWin && webContainer) { |
1089 | 0 | // Get whether the doc contains a frameset |
1090 | 0 | // Also, check to see if the currently focus docshell |
1091 | 0 | // is a child of this docshell |
1092 | 0 | bool isParentFrameSet; |
1093 | 0 | *aIsIFrameSelected = IsThereAnIFrameSelected(webContainer, currentFocusWin, isParentFrameSet); |
1094 | 0 | } |
1095 | 0 | return NS_OK; |
1096 | 0 | } |
1097 | | |
1098 | | //---------------------------------------------------------------------------------- |
1099 | | NS_IMETHODIMP |
1100 | | nsPrintJob::GetIsRangeSelection(bool* aIsRangeSelection) |
1101 | 0 | { |
1102 | 0 | // Get the currently focused window |
1103 | 0 | nsCOMPtr<nsPIDOMWindowOuter> currentFocusWin = FindFocusedDOMWindow(); |
1104 | 0 | *aIsRangeSelection = IsThereARangeSelection(currentFocusWin); |
1105 | 0 | return NS_OK; |
1106 | 0 | } |
1107 | | |
1108 | | //---------------------------------------------------------------------------------- |
1109 | | NS_IMETHODIMP |
1110 | | nsPrintJob::GetIsFramesetFrameSelected(bool* aIsFramesetFrameSelected) |
1111 | 0 | { |
1112 | 0 | // Get the currently focused window |
1113 | 0 | nsCOMPtr<nsPIDOMWindowOuter> currentFocusWin = FindFocusedDOMWindow(); |
1114 | 0 | *aIsFramesetFrameSelected = currentFocusWin != nullptr; |
1115 | 0 | return NS_OK; |
1116 | 0 | } |
1117 | | |
1118 | | //---------------------------------------------------------------------------------- |
1119 | | NS_IMETHODIMP |
1120 | | nsPrintJob::GetPrintPreviewNumPages(int32_t* aPrintPreviewNumPages) |
1121 | 0 | { |
1122 | 0 | NS_ENSURE_ARG_POINTER(aPrintPreviewNumPages); |
1123 | 0 |
|
1124 | 0 | nsIFrame* seqFrame = nullptr; |
1125 | 0 | *aPrintPreviewNumPages = 0; |
1126 | 0 |
|
1127 | 0 | // When calling this function, the FinishPrintPreview() function might not |
1128 | 0 | // been called as there are still some |
1129 | 0 | RefPtr<nsPrintData> printData = mPrtPreview ? mPrtPreview : mPrt; |
1130 | 0 | if (NS_WARN_IF(!printData)) { |
1131 | 0 | return NS_ERROR_FAILURE; |
1132 | 0 | } |
1133 | 0 | nsresult rv = |
1134 | 0 | GetSeqFrameAndCountPagesInternal(printData->mPrintObject, seqFrame, |
1135 | 0 | *aPrintPreviewNumPages); |
1136 | 0 | if (NS_WARN_IF(NS_FAILED(rv))) { |
1137 | 0 | return NS_ERROR_FAILURE; |
1138 | 0 | } |
1139 | 0 | return NS_OK; |
1140 | 0 | } |
1141 | | |
1142 | | //---------------------------------------------------------------------------------- |
1143 | | // Enumerate all the documents for their titles |
1144 | | NS_IMETHODIMP |
1145 | | nsPrintJob::EnumerateDocumentNames(uint32_t* aCount, |
1146 | | char16_t*** aResult) |
1147 | 0 | { |
1148 | 0 | NS_ENSURE_ARG(aCount); |
1149 | 0 | NS_ENSURE_ARG_POINTER(aResult); |
1150 | 0 |
|
1151 | 0 | *aCount = 0; |
1152 | 0 | *aResult = nullptr; |
1153 | 0 |
|
1154 | 0 | int32_t numDocs = mPrt->mPrintDocList.Length(); |
1155 | 0 | char16_t** array = (char16_t**) moz_xmalloc(numDocs * sizeof(char16_t*)); |
1156 | 0 |
|
1157 | 0 | for (int32_t i=0;i<numDocs;i++) { |
1158 | 0 | nsPrintObject* po = mPrt->mPrintDocList.ElementAt(i); |
1159 | 0 | NS_ASSERTION(po, "nsPrintObject can't be null!"); |
1160 | 0 | nsAutoString docTitleStr; |
1161 | 0 | nsAutoString docURLStr; |
1162 | 0 | GetDocumentTitleAndURL(po->mDocument, docTitleStr, docURLStr); |
1163 | 0 |
|
1164 | 0 | // Use the URL if the doc is empty |
1165 | 0 | if (docTitleStr.IsEmpty() && !docURLStr.IsEmpty()) { |
1166 | 0 | docTitleStr = docURLStr; |
1167 | 0 | } |
1168 | 0 | array[i] = ToNewUnicode(docTitleStr); |
1169 | 0 | } |
1170 | 0 | *aCount = numDocs; |
1171 | 0 | *aResult = array; |
1172 | 0 |
|
1173 | 0 | return NS_OK; |
1174 | 0 |
|
1175 | 0 | } |
1176 | | |
1177 | | //---------------------------------------------------------------------------------- |
1178 | | nsresult |
1179 | | nsPrintJob::GetGlobalPrintSettings(nsIPrintSettings** aGlobalPrintSettings) |
1180 | 0 | { |
1181 | 0 | NS_ENSURE_ARG_POINTER(aGlobalPrintSettings); |
1182 | 0 |
|
1183 | 0 | nsresult rv = NS_ERROR_FAILURE; |
1184 | 0 | nsCOMPtr<nsIPrintSettingsService> printSettingsService = |
1185 | 0 | do_GetService(sPrintSettingsServiceContractID, &rv); |
1186 | 0 | if (NS_SUCCEEDED(rv)) { |
1187 | 0 | rv = printSettingsService->GetGlobalPrintSettings(aGlobalPrintSettings); |
1188 | 0 | } |
1189 | 0 | return rv; |
1190 | 0 | } |
1191 | | |
1192 | | //---------------------------------------------------------------------------------- |
1193 | | NS_IMETHODIMP |
1194 | | nsPrintJob::GetDoingPrint(bool* aDoingPrint) |
1195 | 0 | { |
1196 | 0 | NS_ENSURE_ARG_POINTER(aDoingPrint); |
1197 | 0 | *aDoingPrint = mIsDoingPrinting; |
1198 | 0 | return NS_OK; |
1199 | 0 | } |
1200 | | |
1201 | | //---------------------------------------------------------------------------------- |
1202 | | NS_IMETHODIMP |
1203 | | nsPrintJob::GetDoingPrintPreview(bool* aDoingPrintPreview) |
1204 | 0 | { |
1205 | 0 | NS_ENSURE_ARG_POINTER(aDoingPrintPreview); |
1206 | 0 | *aDoingPrintPreview = mIsDoingPrintPreview; |
1207 | 0 | return NS_OK; |
1208 | 0 | } |
1209 | | |
1210 | | //---------------------------------------------------------------------------------- |
1211 | | NS_IMETHODIMP |
1212 | | nsPrintJob::GetCurrentPrintSettings(nsIPrintSettings** aCurrentPrintSettings) |
1213 | 0 | { |
1214 | 0 | NS_ENSURE_ARG_POINTER(aCurrentPrintSettings); |
1215 | 0 |
|
1216 | 0 | if (mPrt) { |
1217 | 0 | *aCurrentPrintSettings = mPrt->mPrintSettings; |
1218 | 0 |
|
1219 | 0 | } else if (mPrtPreview) { |
1220 | 0 | *aCurrentPrintSettings = mPrtPreview->mPrintSettings; |
1221 | 0 |
|
1222 | 0 | } else { |
1223 | 0 | *aCurrentPrintSettings = nullptr; |
1224 | 0 | } |
1225 | 0 | NS_IF_ADDREF(*aCurrentPrintSettings); |
1226 | 0 | return NS_OK; |
1227 | 0 | } |
1228 | | |
1229 | | //----------------------------------------------------------------- |
1230 | | //-- Section: Pre-Reflow Methods |
1231 | | //----------------------------------------------------------------- |
1232 | | |
1233 | | //--------------------------------------------------------------------- |
1234 | | // This method checks to see if there is at least one printer defined |
1235 | | // and if so, it sets the first printer in the list as the default name |
1236 | | // in the PrintSettings which is then used for Printer Preview |
1237 | | nsresult |
1238 | | nsPrintJob::CheckForPrinters(nsIPrintSettings* aPrintSettings) |
1239 | 0 | { |
1240 | | #if defined(XP_MACOSX) || defined(ANDROID) |
1241 | | // Mac doesn't support retrieving a printer list. |
1242 | | return NS_OK; |
1243 | | #else |
1244 | | #if defined(MOZ_X11) |
1245 | 0 | // On Linux, default printer name should be requested on the parent side. |
1246 | 0 | // Unless we are in the parent, we ignore this function |
1247 | 0 | if (!XRE_IsParentProcess()) { |
1248 | 0 | return NS_OK; |
1249 | 0 | } |
1250 | 0 | #endif |
1251 | 0 | NS_ENSURE_ARG_POINTER(aPrintSettings); |
1252 | 0 |
|
1253 | 0 | // See if aPrintSettings already has a printer |
1254 | 0 | nsString printerName; |
1255 | 0 | nsresult rv = aPrintSettings->GetPrinterName(printerName); |
1256 | 0 | if (NS_SUCCEEDED(rv) && !printerName.IsEmpty()) { |
1257 | 0 | return NS_OK; |
1258 | 0 | } |
1259 | 0 | |
1260 | 0 | // aPrintSettings doesn't have a printer set. Try to fetch the default. |
1261 | 0 | nsCOMPtr<nsIPrintSettingsService> printSettingsService = |
1262 | 0 | do_GetService(sPrintSettingsServiceContractID, &rv); |
1263 | 0 | NS_ENSURE_SUCCESS(rv, rv); |
1264 | 0 |
|
1265 | 0 | rv = printSettingsService->GetDefaultPrinterName(printerName); |
1266 | 0 | if (NS_SUCCEEDED(rv) && !printerName.IsEmpty()) { |
1267 | 0 | rv = aPrintSettings->SetPrinterName(printerName); |
1268 | 0 | } |
1269 | 0 | return rv; |
1270 | 0 | #endif |
1271 | 0 | } |
1272 | | |
1273 | | //---------------------------------------------------------------------- |
1274 | | // Set up to use the "pluggable" Print Progress Dialog |
1275 | | void |
1276 | | nsPrintJob::ShowPrintProgress(bool aIsForPrinting, bool& aDoNotify) |
1277 | 0 | { |
1278 | 0 | // default to not notifying, that if something here goes wrong |
1279 | 0 | // or we aren't going to show the progress dialog we can straight into |
1280 | 0 | // reflowing the doc for printing. |
1281 | 0 | aDoNotify = false; |
1282 | 0 |
|
1283 | 0 | // Assume we can't do progress and then see if we can |
1284 | 0 | bool showProgresssDialog = false; |
1285 | 0 |
|
1286 | 0 | // if it is already being shown then don't bother to find out if it should be |
1287 | 0 | // so skip this and leave mShowProgressDialog set to FALSE |
1288 | 0 | if (!mProgressDialogIsShown) { |
1289 | 0 | showProgresssDialog = Preferences::GetBool("print.show_print_progress"); |
1290 | 0 | } |
1291 | 0 |
|
1292 | 0 | // Guarantee that mPrt and the objects it owns won't be deleted. If this |
1293 | 0 | // method shows a progress dialog and spins the event loop. So, mPrt may be |
1294 | 0 | // cleared or recreated. |
1295 | 0 | RefPtr<nsPrintData> printData = mPrt; |
1296 | 0 |
|
1297 | 0 | // Turning off the showing of Print Progress in Prefs overrides |
1298 | 0 | // whether the calling PS desire to have it on or off, so only check PS if |
1299 | 0 | // prefs says it's ok to be on. |
1300 | 0 | if (showProgresssDialog) { |
1301 | 0 | printData->mPrintSettings->GetShowPrintProgress(&showProgresssDialog); |
1302 | 0 | } |
1303 | 0 |
|
1304 | 0 | // Now open the service to get the progress dialog |
1305 | 0 | // If we don't get a service, that's ok, then just don't show progress |
1306 | 0 | if (showProgresssDialog) { |
1307 | 0 | nsCOMPtr<nsIPrintingPromptService> printPromptService(do_GetService(kPrintingPromptService)); |
1308 | 0 | if (printPromptService) { |
1309 | 0 | nsPIDOMWindowOuter* domWin = mDocument->GetWindow(); |
1310 | 0 | if (!domWin) return; |
1311 | 0 | |
1312 | 0 | nsCOMPtr<nsIDocShell> docShell = domWin->GetDocShell(); |
1313 | 0 | if (!docShell) return; |
1314 | 0 | nsCOMPtr<nsIDocShellTreeOwner> owner; |
1315 | 0 | docShell->GetTreeOwner(getter_AddRefs(owner)); |
1316 | 0 | nsCOMPtr<nsIWebBrowserChrome> browserChrome = do_GetInterface(owner); |
1317 | 0 | if (!browserChrome) return; |
1318 | 0 | bool isModal = true; |
1319 | 0 | browserChrome->IsWindowModal(&isModal); |
1320 | 0 | if (isModal) { |
1321 | 0 | // Showing a print progress dialog when printing a modal window |
1322 | 0 | // isn't supported. See bug 301560. |
1323 | 0 | return; |
1324 | 0 | } |
1325 | 0 | |
1326 | 0 | nsCOMPtr<nsIWebProgressListener> printProgressListener; |
1327 | 0 |
|
1328 | 0 | nsCOMPtr<nsIWebBrowserPrint> wbp(do_QueryInterface(mDocViewerPrint)); |
1329 | 0 | nsresult rv = |
1330 | 0 | printPromptService->ShowProgress( |
1331 | 0 | domWin, wbp, printData->mPrintSettings, this, |
1332 | 0 | aIsForPrinting, |
1333 | 0 | getter_AddRefs(printProgressListener), |
1334 | 0 | getter_AddRefs(printData->mPrintProgressParams), |
1335 | 0 | &aDoNotify); |
1336 | 0 | if (NS_SUCCEEDED(rv)) { |
1337 | 0 | if (printProgressListener) { |
1338 | 0 | printData->mPrintProgressListeners.AppendObject( |
1339 | 0 | printProgressListener); |
1340 | 0 | } |
1341 | 0 |
|
1342 | 0 | if (printData->mPrintProgressParams) { |
1343 | 0 | SetDocAndURLIntoProgress(printData->mPrintObject, |
1344 | 0 | printData->mPrintProgressParams); |
1345 | 0 | } |
1346 | 0 | } |
1347 | 0 | } |
1348 | 0 | } |
1349 | 0 | } |
1350 | | |
1351 | | //--------------------------------------------------------------------- |
1352 | | bool |
1353 | | nsPrintJob::IsThereARangeSelection(nsPIDOMWindowOuter* aDOMWin) |
1354 | 0 | { |
1355 | 0 | if (mDisallowSelectionPrint) |
1356 | 0 | return false; |
1357 | 0 | |
1358 | 0 | nsCOMPtr<nsIPresShell> presShell; |
1359 | 0 | if (aDOMWin) { |
1360 | 0 | presShell = aDOMWin->GetDocShell()->GetPresShell(); |
1361 | 0 | } |
1362 | 0 |
|
1363 | 0 | if (!presShell) |
1364 | 0 | return false; |
1365 | 0 | |
1366 | 0 | // check here to see if there is a range selection |
1367 | 0 | // so we know whether to turn on the "Selection" radio button |
1368 | 0 | Selection* selection = presShell->GetCurrentSelection(SelectionType::eNormal); |
1369 | 0 | if (!selection) { |
1370 | 0 | return false; |
1371 | 0 | } |
1372 | 0 | |
1373 | 0 | int32_t rangeCount = selection->RangeCount(); |
1374 | 0 | if (!rangeCount) { |
1375 | 0 | return false; |
1376 | 0 | } |
1377 | 0 | |
1378 | 0 | if (rangeCount > 1) { |
1379 | 0 | return true; |
1380 | 0 | } |
1381 | 0 | |
1382 | 0 | // check to make sure it isn't an insertion selection |
1383 | 0 | return selection->GetRangeAt(0) && !selection->IsCollapsed(); |
1384 | 0 | } |
1385 | | |
1386 | | //--------------------------------------------------------------------- |
1387 | | // Recursively build a list of sub documents to be printed |
1388 | | // that mirrors the document tree |
1389 | | void |
1390 | | nsPrintJob::BuildDocTree(nsIDocShell* aParentNode, |
1391 | | nsTArray<nsPrintObject*>* aDocList, |
1392 | | const UniquePtr<nsPrintObject>& aPO) |
1393 | 0 | { |
1394 | 0 | NS_ASSERTION(aParentNode, "Pointer is null!"); |
1395 | 0 | NS_ASSERTION(aDocList, "Pointer is null!"); |
1396 | 0 | NS_ASSERTION(aPO, "Pointer is null!"); |
1397 | 0 |
|
1398 | 0 | int32_t childWebshellCount; |
1399 | 0 | aParentNode->GetChildCount(&childWebshellCount); |
1400 | 0 | if (childWebshellCount > 0) { |
1401 | 0 | for (int32_t i=0;i<childWebshellCount;i++) { |
1402 | 0 | nsCOMPtr<nsIDocShellTreeItem> child; |
1403 | 0 | aParentNode->GetChildAt(i, getter_AddRefs(child)); |
1404 | 0 | nsCOMPtr<nsIDocShell> childAsShell(do_QueryInterface(child)); |
1405 | 0 |
|
1406 | 0 | nsCOMPtr<nsIContentViewer> viewer; |
1407 | 0 | childAsShell->GetContentViewer(getter_AddRefs(viewer)); |
1408 | 0 | if (viewer) { |
1409 | 0 | nsCOMPtr<nsIDocument> doc = do_GetInterface(childAsShell); |
1410 | 0 | auto po = MakeUnique<nsPrintObject>(); |
1411 | 0 | po->mParent = aPO.get(); |
1412 | 0 | nsresult rv = po->Init(childAsShell, doc, aPO->mPrintPreview); |
1413 | 0 | if (NS_FAILED(rv)) |
1414 | 0 | MOZ_ASSERT_UNREACHABLE("Init failed?"); |
1415 | 0 | aPO->mKids.AppendElement(std::move(po)); |
1416 | 0 | aDocList->AppendElement(aPO->mKids.LastElement().get()); |
1417 | 0 | BuildDocTree(childAsShell, aDocList, aPO->mKids.LastElement()); |
1418 | 0 | } |
1419 | 0 | } |
1420 | 0 | } |
1421 | 0 | } |
1422 | | |
1423 | | //------------------------------------------------------- |
1424 | | // A Frame's sub-doc may contain content or a FrameSet |
1425 | | // When it contains a FrameSet the mFrameType for the PrintObject |
1426 | | // is always set to an eFrame. Which is fine when printing "AsIs" |
1427 | | // but is incorrect when when printing "Each Frame Separately". |
1428 | | // When printing "Each Frame Separately" the Frame really acts like |
1429 | | // a frameset. |
1430 | | // |
1431 | | // This method walks the PO tree and checks to see if the PrintObject is |
1432 | | // an eFrame and has children that are eFrames (meaning it's a Frame containing a FrameSet) |
1433 | | // If so, then the mFrameType need to be changed to eFrameSet |
1434 | | // |
1435 | | // Also note: We only want to call this we are printing "Each Frame Separately" |
1436 | | // when printing "As Is" leave it as an eFrame |
1437 | | void |
1438 | | nsPrintJob::CheckForChildFrameSets(const UniquePtr<nsPrintObject>& aPO) |
1439 | 0 | { |
1440 | 0 | NS_ASSERTION(aPO, "Pointer is null!"); |
1441 | 0 |
|
1442 | 0 | // Continue recursively walking the chilren of this PO |
1443 | 0 | bool hasChildFrames = false; |
1444 | 0 | for (const UniquePtr<nsPrintObject>& po : aPO->mKids) { |
1445 | 0 | if (po->mFrameType == eFrame) { |
1446 | 0 | hasChildFrames = true; |
1447 | 0 | CheckForChildFrameSets(po); |
1448 | 0 | } |
1449 | 0 | } |
1450 | 0 |
|
1451 | 0 | if (hasChildFrames && aPO->mFrameType == eFrame) { |
1452 | 0 | aPO->mFrameType = eFrameSet; |
1453 | 0 | } |
1454 | 0 | } |
1455 | | |
1456 | | //--------------------------------------------------------------------- |
1457 | | bool |
1458 | | nsPrintJob::IsThereAnIFrameSelected(nsIDocShell* aDocShell, |
1459 | | nsPIDOMWindowOuter* aDOMWin, |
1460 | | bool& aIsParentFrameSet) |
1461 | 0 | { |
1462 | 0 | aIsParentFrameSet = IsParentAFrameSet(aDocShell); |
1463 | 0 | bool iFrameIsSelected = false; |
1464 | 0 | if (mPrt && mPrt->mPrintObject) { |
1465 | 0 | nsPrintObject* po = FindPrintObjectByDOMWin(mPrt->mPrintObject.get(), aDOMWin); |
1466 | 0 | iFrameIsSelected = po && po->mFrameType == eIFrame; |
1467 | 0 | } else { |
1468 | 0 | // First, check to see if we are a frameset |
1469 | 0 | if (!aIsParentFrameSet) { |
1470 | 0 | // Check to see if there is a currenlt focused frame |
1471 | 0 | // if so, it means the selected frame is either the main docshell |
1472 | 0 | // or an IFRAME |
1473 | 0 | if (aDOMWin) { |
1474 | 0 | // Get the main docshell's DOMWin to see if it matches |
1475 | 0 | // the frame that is selected |
1476 | 0 | nsPIDOMWindowOuter* domWin = aDocShell ? aDocShell->GetWindow() : nullptr; |
1477 | 0 | if (domWin != aDOMWin) { |
1478 | 0 | iFrameIsSelected = true; // we have a selected IFRAME |
1479 | 0 | } |
1480 | 0 | } |
1481 | 0 | } |
1482 | 0 | } |
1483 | 0 |
|
1484 | 0 | return iFrameIsSelected; |
1485 | 0 | } |
1486 | | |
1487 | | //--------------------------------------------------------------------- |
1488 | | // Recursively sets all the PO items to be printed |
1489 | | // from the given item down into the tree |
1490 | | void |
1491 | | nsPrintJob::SetPrintPO(nsPrintObject* aPO, bool aPrint) |
1492 | 0 | { |
1493 | 0 | NS_ASSERTION(aPO, "Pointer is null!"); |
1494 | 0 |
|
1495 | 0 | // Set whether to print flag |
1496 | 0 | aPO->mDontPrint = !aPrint; |
1497 | 0 |
|
1498 | 0 | for (const UniquePtr<nsPrintObject>& kid : aPO->mKids) { |
1499 | 0 | SetPrintPO(kid.get(), aPrint); |
1500 | 0 | } |
1501 | 0 | } |
1502 | | |
1503 | | //--------------------------------------------------------------------- |
1504 | | // This will first use a Title and/or URL from the PrintSettings |
1505 | | // if one isn't set then it uses the one from the document |
1506 | | // then if not title is there we will make sure we send something back |
1507 | | // depending on the situation. |
1508 | | void |
1509 | | nsPrintJob::GetDisplayTitleAndURL(const UniquePtr<nsPrintObject>& aPO, |
1510 | | nsAString& aTitle, |
1511 | | nsAString& aURLStr, |
1512 | | eDocTitleDefault aDefType) |
1513 | 0 | { |
1514 | 0 | NS_ASSERTION(aPO, "Pointer is null!"); |
1515 | 0 |
|
1516 | 0 | if (!mPrt) |
1517 | 0 | return; |
1518 | 0 | |
1519 | 0 | aTitle.Truncate(); |
1520 | 0 | aURLStr.Truncate(); |
1521 | 0 |
|
1522 | 0 | // First check to see if the PrintSettings has defined an alternate title |
1523 | 0 | // and use that if it did |
1524 | 0 | if (mPrt->mPrintSettings) { |
1525 | 0 | mPrt->mPrintSettings->GetTitle(aTitle); |
1526 | 0 | mPrt->mPrintSettings->GetDocURL(aURLStr); |
1527 | 0 | } |
1528 | 0 |
|
1529 | 0 | nsAutoString docTitle; |
1530 | 0 | nsAutoString docUrl; |
1531 | 0 | GetDocumentTitleAndURL(aPO->mDocument, docTitle, docUrl); |
1532 | 0 |
|
1533 | 0 | if (aURLStr.IsEmpty() && !docUrl.IsEmpty()) { |
1534 | 0 | aURLStr = docUrl; |
1535 | 0 | } |
1536 | 0 |
|
1537 | 0 | if (aTitle.IsEmpty()) { |
1538 | 0 | if (!docTitle.IsEmpty()) { |
1539 | 0 | aTitle = docTitle; |
1540 | 0 | } else { |
1541 | 0 | if (aDefType == eDocTitleDefURLDoc) { |
1542 | 0 | if (!aURLStr.IsEmpty()) { |
1543 | 0 | aTitle = aURLStr; |
1544 | 0 | } else if (!mPrt->mBrandName.IsEmpty()) { |
1545 | 0 | aTitle = mPrt->mBrandName; |
1546 | 0 | } |
1547 | 0 | } |
1548 | 0 | } |
1549 | 0 | } |
1550 | 0 | } |
1551 | | |
1552 | | //--------------------------------------------------------------------- |
1553 | | nsresult |
1554 | | nsPrintJob::DocumentReadyForPrinting() |
1555 | 0 | { |
1556 | 0 | if (mPrt->mPrintFrameType == nsIPrintSettings::kEachFrameSep) { |
1557 | 0 | // Guarantee that mPrt->mPrintObject won't be deleted during a call of |
1558 | 0 | // CheckForChildFrameSets(). |
1559 | 0 | RefPtr<nsPrintData> printData = mPrt; |
1560 | 0 | CheckForChildFrameSets(printData->mPrintObject); |
1561 | 0 | } |
1562 | 0 |
|
1563 | 0 | // |
1564 | 0 | // Send the document to the printer... |
1565 | 0 | // |
1566 | 0 | nsresult rv = SetupToPrintContent(); |
1567 | 0 | if (NS_FAILED(rv)) { |
1568 | 0 | // The print job was canceled or there was a problem |
1569 | 0 | // So remove all other documents from the print list |
1570 | 0 | DonePrintingPages(nullptr, rv); |
1571 | 0 | } |
1572 | 0 | return rv; |
1573 | 0 | } |
1574 | | |
1575 | | /** --------------------------------------------------- |
1576 | | * Cleans up when an error occurred |
1577 | | */ |
1578 | | nsresult |
1579 | | nsPrintJob::CleanupOnFailure(nsresult aResult, bool aIsPrinting) |
1580 | 0 | { |
1581 | 0 | PR_PL(("**** Failed %s - rv 0x%" PRIX32, aIsPrinting?"Printing":"Print Preview", |
1582 | 0 | static_cast<uint32_t>(aResult))); |
1583 | 0 |
|
1584 | 0 | /* cleanup... */ |
1585 | 0 | if (mPagePrintTimer) { |
1586 | 0 | mPagePrintTimer->Stop(); |
1587 | 0 | DisconnectPagePrintTimer(); |
1588 | 0 | } |
1589 | 0 |
|
1590 | 0 | if (aIsPrinting) { |
1591 | 0 | SetIsPrinting(false); |
1592 | 0 | } else { |
1593 | 0 | SetIsPrintPreview(false); |
1594 | 0 | mIsCreatingPrintPreview = false; |
1595 | 0 | } |
1596 | 0 |
|
1597 | 0 | /* cleanup done, let's fire-up an error dialog to notify the user |
1598 | 0 | * what went wrong... |
1599 | 0 | * |
1600 | 0 | * When rv == NS_ERROR_ABORT, it means we want out of the |
1601 | 0 | * print job without displaying any error messages |
1602 | 0 | */ |
1603 | 0 | if (aResult != NS_ERROR_ABORT) { |
1604 | 0 | FirePrintingErrorEvent(aResult); |
1605 | 0 | } |
1606 | 0 |
|
1607 | 0 | FirePrintCompletionEvent(); |
1608 | 0 |
|
1609 | 0 | return aResult; |
1610 | 0 |
|
1611 | 0 | } |
1612 | | |
1613 | | //--------------------------------------------------------------------- |
1614 | | void |
1615 | | nsPrintJob::FirePrintingErrorEvent(nsresult aPrintError) |
1616 | 0 | { |
1617 | 0 | nsCOMPtr<nsIContentViewer> cv = do_QueryInterface(mDocViewerPrint); |
1618 | 0 | if (NS_WARN_IF(!cv)) { |
1619 | 0 | return; |
1620 | 0 | } |
1621 | 0 | |
1622 | 0 | nsCOMPtr<nsIDocument> doc = cv->GetDocument(); |
1623 | 0 | RefPtr<CustomEvent> event = |
1624 | 0 | NS_NewDOMCustomEvent(doc, nullptr, nullptr); |
1625 | 0 |
|
1626 | 0 | MOZ_ASSERT(event); |
1627 | 0 |
|
1628 | 0 | AutoJSAPI jsapi; |
1629 | 0 | if (!jsapi.Init(event->GetParentObject())) { |
1630 | 0 | return; |
1631 | 0 | } |
1632 | 0 | JSContext* cx = jsapi.cx(); |
1633 | 0 |
|
1634 | 0 | JS::Rooted<JS::Value> detail(cx, |
1635 | 0 | JS::NumberValue(static_cast<double>(aPrintError))); |
1636 | 0 | event->InitCustomEvent(cx, NS_LITERAL_STRING("PrintingError"), false, false, |
1637 | 0 | detail); |
1638 | 0 | event->SetTrusted(true); |
1639 | 0 |
|
1640 | 0 | RefPtr<AsyncEventDispatcher> asyncDispatcher = |
1641 | 0 | new AsyncEventDispatcher(doc, event); |
1642 | 0 | asyncDispatcher->mOnlyChromeDispatch = ChromeOnlyDispatch::eYes; |
1643 | 0 | asyncDispatcher->RunDOMEventWhenSafe(); |
1644 | 0 |
|
1645 | 0 | // Inform any progress listeners of the Error. |
1646 | 0 | if (mPrt) { |
1647 | 0 | // Note that nsPrintData::DoOnStatusChange() will call some listeners. |
1648 | 0 | // So, mPrt can be cleared or recreated. |
1649 | 0 | RefPtr<nsPrintData> printData = mPrt; |
1650 | 0 | printData->DoOnStatusChange(aPrintError); |
1651 | 0 | } |
1652 | 0 | } |
1653 | | |
1654 | | //----------------------------------------------------------------- |
1655 | | //-- Section: Reflow Methods |
1656 | | //----------------------------------------------------------------- |
1657 | | |
1658 | | nsresult |
1659 | | nsPrintJob::ReconstructAndReflow(bool doSetPixelScale) |
1660 | 0 | { |
1661 | 0 | if (NS_WARN_IF(!mPrt)) { |
1662 | 0 | return NS_ERROR_FAILURE; |
1663 | 0 | } |
1664 | 0 | |
1665 | | #if defined(XP_WIN) && defined(EXTENDED_DEBUG_PRINTING) |
1666 | | // We need to clear all the output files here |
1667 | | // because they will be re-created with second reflow of the docs |
1668 | | if (MOZ_LOG_TEST(gPrintingLog, DUMP_LAYOUT_LEVEL)) { |
1669 | | RemoveFilesInDir(".\\"); |
1670 | | gDumpFileNameCnt = 0; |
1671 | | gDumpLOFileNameCnt = 0; |
1672 | | } |
1673 | | #endif |
1674 | | |
1675 | 0 | // In this loop, it's conceivable that one of our helpers might clear mPrt, |
1676 | 0 | // while we're using it & its members! So we capture it in an owning local |
1677 | 0 | // reference & use that instead of using mPrt directly. |
1678 | 0 | RefPtr<nsPrintData> printData = mPrt; |
1679 | 0 | for (uint32_t i = 0; i < printData->mPrintDocList.Length(); ++i) { |
1680 | 0 | nsPrintObject* po = printData->mPrintDocList.ElementAt(i); |
1681 | 0 | NS_ASSERTION(po, "nsPrintObject can't be null!"); |
1682 | 0 |
|
1683 | 0 | if (po->mDontPrint || po->mInvisible) { |
1684 | 0 | continue; |
1685 | 0 | } |
1686 | 0 | |
1687 | 0 | // When the print object has been marked as "print the document" (i.e, |
1688 | 0 | // po->mDontPrint is false), mPresContext and mPresShell should be |
1689 | 0 | // non-nullptr (i.e., should've been created for the print) since they |
1690 | 0 | // are necessary to print the document. |
1691 | 0 | MOZ_ASSERT(po->mPresContext && po->mPresShell, |
1692 | 0 | "mPresContext and mPresShell shouldn't be nullptr when the print object " |
1693 | 0 | "has been marked as \"print the document\""); |
1694 | 0 |
|
1695 | 0 | UpdateZoomRatio(po, doSetPixelScale); |
1696 | 0 |
|
1697 | 0 | po->mPresContext->SetPageScale(po->mZoomRatio); |
1698 | 0 |
|
1699 | 0 | // Calculate scale factor from printer to screen |
1700 | 0 | float printDPI = float(AppUnitsPerCSSInch()) / |
1701 | 0 | float(printData->mPrintDC->AppUnitsPerDevPixel()); |
1702 | 0 | po->mPresContext->SetPrintPreviewScale(mScreenDPI / printDPI); |
1703 | 0 |
|
1704 | 0 | po->mPresShell->ReconstructFrames(); |
1705 | 0 |
|
1706 | 0 | // If the printing was canceled or restarted with different data, |
1707 | 0 | // let's stop doing this printing. |
1708 | 0 | if (NS_WARN_IF(mPrt != printData)) { |
1709 | 0 | return NS_ERROR_FAILURE; |
1710 | 0 | } |
1711 | 0 | |
1712 | 0 | // For all views except the first one, setup the root view. |
1713 | 0 | // ??? Can there be multiple po for the top-level-document? |
1714 | 0 | bool documentIsTopLevel = true; |
1715 | 0 | if (i != 0) { |
1716 | 0 | nsSize adjSize; |
1717 | 0 | bool doReturn; |
1718 | 0 | nsresult rv = SetRootView(po, doReturn, documentIsTopLevel, adjSize); |
1719 | 0 |
|
1720 | 0 | MOZ_ASSERT(!documentIsTopLevel, "How could this happen?"); |
1721 | 0 |
|
1722 | 0 | if (NS_FAILED(rv) || doReturn) { |
1723 | 0 | return rv; |
1724 | 0 | } |
1725 | 0 | } |
1726 | 0 | |
1727 | 0 | po->mPresShell->FlushPendingNotifications(FlushType::Layout); |
1728 | 0 |
|
1729 | 0 | // If the printing was canceled or restarted with different data, |
1730 | 0 | // let's stop doing this printing. |
1731 | 0 | if (NS_WARN_IF(mPrt != printData)) { |
1732 | 0 | return NS_ERROR_FAILURE; |
1733 | 0 | } |
1734 | 0 | |
1735 | 0 | nsresult rv = UpdateSelectionAndShrinkPrintObject(po, documentIsTopLevel); |
1736 | 0 | NS_ENSURE_SUCCESS(rv, rv); |
1737 | 0 | } |
1738 | 0 | return NS_OK; |
1739 | 0 | } |
1740 | | |
1741 | | //------------------------------------------------------- |
1742 | | nsresult |
1743 | | nsPrintJob::SetupToPrintContent() |
1744 | 0 | { |
1745 | 0 | // This method may be called while DoCommonPrint() initializes the instance |
1746 | 0 | // when its script blocker goes out of scope. In such case, this cannot do |
1747 | 0 | // its job as expected because some objects in mPrt have not been initialized |
1748 | 0 | // yet but they are necessary. |
1749 | 0 | // Note: it shouldn't be possible for mPrt->mPrintObject to be null; we check |
1750 | 0 | // it for good measure (after we check its owner) before we start |
1751 | 0 | // dereferencing it below. |
1752 | 0 | if (NS_WARN_IF(!mPrt) || |
1753 | 0 | NS_WARN_IF(!mPrt->mPrintObject)) { |
1754 | 0 | return NS_ERROR_FAILURE; |
1755 | 0 | } |
1756 | 0 | |
1757 | 0 | // If this is creating print preview, mPrt->mPrintObject->mPresContext and |
1758 | 0 | // mPrt->mPrintObject->mPresShell need to be non-nullptr because this cannot |
1759 | 0 | // initialize page sequence frame without them at end of this method since |
1760 | 0 | // page sequence frame has already been destroyed or not been created yet. |
1761 | 0 | if (mIsCreatingPrintPreview && |
1762 | 0 | (NS_WARN_IF(!mPrt->mPrintObject->mPresContext) || |
1763 | 0 | NS_WARN_IF(!mPrt->mPrintObject->mPresShell))) { |
1764 | 0 | return NS_ERROR_FAILURE; |
1765 | 0 | } |
1766 | 0 | |
1767 | 0 | // If this is printing some documents (not print-previewing the documents), |
1768 | 0 | // mPrt->mPrintObject->mPresContext and mPrt->mPrintObject->mPresShell can be |
1769 | 0 | // nullptr only when mPrt->mPrintObject->mDontPrint is set to true. E.g., if |
1770 | 0 | // the document has a <frameset> element and it's printing only content in a |
1771 | 0 | // <frame> element or all <frame> elements separately. |
1772 | 0 | MOZ_ASSERT( |
1773 | 0 | (!mIsCreatingPrintPreview && !mPrt->mPrintObject->IsPrintable()) || |
1774 | 0 | (mPrt->mPrintObject->mPresContext && mPrt->mPrintObject->mPresShell), |
1775 | 0 | "mPresContext and mPresShell shouldn't be nullptr when printing the " |
1776 | 0 | "document or creating print-preview"); |
1777 | 0 |
|
1778 | 0 | bool didReconstruction = false; |
1779 | 0 |
|
1780 | 0 | // This method works with mPrt->mPrintObject. So, we need to guarantee that |
1781 | 0 | // it won't be deleted in this method. We achieve this by holding a strong |
1782 | 0 | // local reference to mPrt, which in turn keeps mPrintObject alive. |
1783 | 0 | RefPtr<nsPrintData> printData = mPrt; |
1784 | 0 |
|
1785 | 0 | // If some new content got loaded since the initial reflow rebuild |
1786 | 0 | // everything. |
1787 | 0 | if (mDidLoadDataForPrinting) { |
1788 | 0 | nsresult rv = ReconstructAndReflow(DoSetPixelScale()); |
1789 | 0 | if (NS_WARN_IF(NS_FAILED(rv))) { |
1790 | 0 | return rv; |
1791 | 0 | } |
1792 | 0 | // If the printing was canceled or restarted with different data, |
1793 | 0 | // let's stop doing this printing. |
1794 | 0 | if (NS_WARN_IF(mPrt != printData)) { |
1795 | 0 | return NS_ERROR_FAILURE; |
1796 | 0 | } |
1797 | 0 | didReconstruction = true; |
1798 | 0 | } |
1799 | 0 |
|
1800 | 0 | // Here is where we figure out if extra reflow for shrinking the content |
1801 | 0 | // is required. |
1802 | 0 | // But skip this step if we are in PrintPreview |
1803 | 0 | bool ppIsShrinkToFit = mPrtPreview && mPrtPreview->mShrinkToFit; |
1804 | 0 | if (printData->mShrinkToFit && !ppIsShrinkToFit) { |
1805 | 0 | // Now look for the PO that has the smallest percent for shrink to fit |
1806 | 0 | if (printData->mPrintDocList.Length() > 1 && |
1807 | 0 | printData->mPrintObject->mFrameType == eFrameSet) { |
1808 | 0 | nsPrintObject* smallestPO = FindSmallestSTF(); |
1809 | 0 | NS_ASSERTION(smallestPO, "There must always be an XMost PO!"); |
1810 | 0 | if (smallestPO) { |
1811 | 0 | // Calc the shrinkage based on the entire content area |
1812 | 0 | printData->mShrinkRatio = smallestPO->mShrinkRatio; |
1813 | 0 | } |
1814 | 0 | } else { |
1815 | 0 | // Single document so use the Shrink as calculated for the PO |
1816 | 0 | printData->mShrinkRatio = printData->mPrintObject->mShrinkRatio; |
1817 | 0 | } |
1818 | 0 |
|
1819 | 0 | if (printData->mShrinkRatio < 0.998f) { |
1820 | 0 | nsresult rv = ReconstructAndReflow(true); |
1821 | 0 | if (NS_WARN_IF(NS_FAILED(rv))) { |
1822 | 0 | return rv; |
1823 | 0 | } |
1824 | 0 | // If the printing was canceled or restarted with different data, |
1825 | 0 | // let's stop doing this printing. |
1826 | 0 | if (NS_WARN_IF(mPrt != printData)) { |
1827 | 0 | return NS_ERROR_FAILURE; |
1828 | 0 | } |
1829 | 0 | didReconstruction = true; |
1830 | 0 | } |
1831 | 0 |
|
1832 | 0 | if (MOZ_LOG_TEST(gPrintingLog, LogLevel::Debug)) { |
1833 | 0 | float calcRatio = 0.0f; |
1834 | 0 | if (printData->mPrintDocList.Length() > 1 && |
1835 | 0 | printData->mPrintObject->mFrameType == eFrameSet) { |
1836 | 0 | nsPrintObject* smallestPO = FindSmallestSTF(); |
1837 | 0 | NS_ASSERTION(smallestPO, "There must always be an XMost PO!"); |
1838 | 0 | if (smallestPO) { |
1839 | 0 | // Calc the shrinkage based on the entire content area |
1840 | 0 | calcRatio = smallestPO->mShrinkRatio; |
1841 | 0 | } |
1842 | 0 | } else { |
1843 | 0 | // Single document so use the Shrink as calculated for the PO |
1844 | 0 | calcRatio = printData->mPrintObject->mShrinkRatio; |
1845 | 0 | } |
1846 | 0 | PR_PL(("**************************************************************************\n")); |
1847 | 0 | PR_PL(("STF Ratio is: %8.5f Effective Ratio: %8.5f Diff: %8.5f\n", |
1848 | 0 | printData->mShrinkRatio, calcRatio, |
1849 | 0 | printData->mShrinkRatio-calcRatio)); |
1850 | 0 | PR_PL(("**************************************************************************\n")); |
1851 | 0 | } |
1852 | 0 | } |
1853 | 0 |
|
1854 | 0 | // If the frames got reconstructed and reflowed the number of pages might |
1855 | 0 | // has changed. |
1856 | 0 | if (didReconstruction) { |
1857 | 0 | FirePrintPreviewUpdateEvent(); |
1858 | 0 | // If the printing was canceled or restarted with different data, |
1859 | 0 | // let's stop doing this printing. |
1860 | 0 | if (NS_WARN_IF(mPrt != printData)) { |
1861 | 0 | return NS_ERROR_FAILURE; |
1862 | 0 | } |
1863 | 0 | } |
1864 | 0 | |
1865 | 0 | DUMP_DOC_LIST(("\nAfter Reflow------------------------------------------")); |
1866 | 0 | PR_PL(("\n")); |
1867 | 0 | PR_PL(("-------------------------------------------------------\n")); |
1868 | 0 | PR_PL(("\n")); |
1869 | 0 |
|
1870 | 0 | CalcNumPrintablePages(printData->mNumPrintablePages); |
1871 | 0 |
|
1872 | 0 | PR_PL(("--- Printing %d pages\n", printData->mNumPrintablePages)); |
1873 | 0 | DUMP_DOC_TREELAYOUT; |
1874 | 0 |
|
1875 | 0 | // Print listener setup... |
1876 | 0 | printData->OnStartPrinting(); |
1877 | 0 |
|
1878 | 0 | // If the printing was canceled or restarted with different data, |
1879 | 0 | // let's stop doing this printing. |
1880 | 0 | if (NS_WARN_IF(mPrt != printData)) { |
1881 | 0 | return NS_ERROR_FAILURE; |
1882 | 0 | } |
1883 | 0 | |
1884 | 0 | nsAutoString fileNameStr; |
1885 | 0 | // check to see if we are printing to a file |
1886 | 0 | bool isPrintToFile = false; |
1887 | 0 | printData->mPrintSettings->GetPrintToFile(&isPrintToFile); |
1888 | 0 | if (isPrintToFile) { |
1889 | 0 | // On some platforms The BeginDocument needs to know the name of the file. |
1890 | 0 | printData->mPrintSettings->GetToFileName(fileNameStr); |
1891 | 0 | } |
1892 | 0 |
|
1893 | 0 | nsAutoString docTitleStr; |
1894 | 0 | nsAutoString docURLStr; |
1895 | 0 | GetDisplayTitleAndURL(printData->mPrintObject, docTitleStr, docURLStr, |
1896 | 0 | eDocTitleDefURLDoc); |
1897 | 0 |
|
1898 | 0 | int32_t startPage = 1; |
1899 | 0 | int32_t endPage = printData->mNumPrintablePages; |
1900 | 0 |
|
1901 | 0 | int16_t printRangeType = nsIPrintSettings::kRangeAllPages; |
1902 | 0 | printData->mPrintSettings->GetPrintRange(&printRangeType); |
1903 | 0 | if (printRangeType == nsIPrintSettings::kRangeSpecifiedPageRange) { |
1904 | 0 | printData->mPrintSettings->GetStartPageRange(&startPage); |
1905 | 0 | printData->mPrintSettings->GetEndPageRange(&endPage); |
1906 | 0 | if (endPage > printData->mNumPrintablePages) { |
1907 | 0 | endPage = printData->mNumPrintablePages; |
1908 | 0 | } |
1909 | 0 | } |
1910 | 0 |
|
1911 | 0 | nsresult rv = NS_OK; |
1912 | 0 | // BeginDocument may pass back a FAILURE code |
1913 | 0 | // i.e. On Windows, if you are printing to a file and hit "Cancel" |
1914 | 0 | // to the "File Name" dialog, this comes back as an error |
1915 | 0 | // Don't start printing when regression test are executed |
1916 | 0 | if (mIsDoingPrinting) { |
1917 | 0 | rv = printData->mPrintDC->BeginDocument(docTitleStr, fileNameStr, startPage, |
1918 | 0 | endPage); |
1919 | 0 | } |
1920 | 0 |
|
1921 | 0 | if (mIsCreatingPrintPreview) { |
1922 | 0 | // Copy docTitleStr and docURLStr to the pageSequenceFrame, to be displayed |
1923 | 0 | // in the header |
1924 | 0 | nsIPageSequenceFrame* seqFrame = |
1925 | 0 | printData->mPrintObject->mPresShell->GetPageSequenceFrame(); |
1926 | 0 | if (seqFrame) { |
1927 | 0 | seqFrame->StartPrint(printData->mPrintObject->mPresContext, |
1928 | 0 | printData->mPrintSettings, docTitleStr, docURLStr); |
1929 | 0 | } |
1930 | 0 | } |
1931 | 0 |
|
1932 | 0 | PR_PL(("****************** Begin Document ************************\n")); |
1933 | 0 |
|
1934 | 0 | if (NS_FAILED(rv)) { |
1935 | 0 | NS_WARNING_ASSERTION(rv == NS_ERROR_ABORT, |
1936 | 0 | "Failed to begin document for printing"); |
1937 | 0 | return rv; |
1938 | 0 | } |
1939 | 0 |
|
1940 | 0 | // This will print the docshell document |
1941 | 0 | // when it completes asynchronously in the DonePrintingPages method |
1942 | 0 | // it will check to see if there are more docshells to be printed and |
1943 | 0 | // then PrintDocContent will be called again. |
1944 | 0 |
|
1945 | 0 | if (mIsDoingPrinting) { |
1946 | 0 | PrintDocContent(printData->mPrintObject, rv); // ignore return value |
1947 | 0 | } |
1948 | 0 |
|
1949 | 0 | return rv; |
1950 | 0 | } |
1951 | | |
1952 | | //------------------------------------------------------- |
1953 | | // Recursively reflow each sub-doc and then calc |
1954 | | // all the frame locations of the sub-docs |
1955 | | nsresult |
1956 | | nsPrintJob::ReflowDocList(const UniquePtr<nsPrintObject>& aPO, |
1957 | | bool aSetPixelScale) |
1958 | 0 | { |
1959 | 0 | NS_ENSURE_ARG_POINTER(aPO); |
1960 | 0 |
|
1961 | 0 | // Check to see if the subdocument's element has been hidden by the parent document |
1962 | 0 | if (aPO->mParent && aPO->mParent->mPresShell) { |
1963 | 0 | nsIFrame* frame = aPO->mContent ? aPO->mContent->GetPrimaryFrame() : nullptr; |
1964 | 0 | if (!frame || !frame->StyleVisibility()->IsVisible()) { |
1965 | 0 | SetPrintPO(aPO.get(), false); |
1966 | 0 | aPO->mInvisible = true; |
1967 | 0 | return NS_OK; |
1968 | 0 | } |
1969 | 0 | } |
1970 | 0 | |
1971 | 0 | UpdateZoomRatio(aPO.get(), aSetPixelScale); |
1972 | 0 |
|
1973 | 0 | nsresult rv; |
1974 | 0 | // Reflow the PO |
1975 | 0 | rv = ReflowPrintObject(aPO); |
1976 | 0 | NS_ENSURE_SUCCESS(rv, rv); |
1977 | 0 |
|
1978 | 0 | for (const UniquePtr<nsPrintObject>& kid : aPO->mKids) { |
1979 | 0 | rv = ReflowDocList(kid, aSetPixelScale); |
1980 | 0 | NS_ENSURE_SUCCESS(rv, rv); |
1981 | 0 | } |
1982 | 0 | return NS_OK; |
1983 | 0 | } |
1984 | | |
1985 | | void |
1986 | | nsPrintJob::FirePrintPreviewUpdateEvent() |
1987 | 0 | { |
1988 | 0 | // Dispatch the event only while in PrintPreview. When printing, there is no |
1989 | 0 | // listener bound to this event and therefore no need to dispatch it. |
1990 | 0 | if (mIsDoingPrintPreview && !mIsDoingPrinting) { |
1991 | 0 | nsCOMPtr<nsIContentViewer> cv = do_QueryInterface(mDocViewerPrint); |
1992 | 0 | (new AsyncEventDispatcher( |
1993 | 0 | cv->GetDocument(), NS_LITERAL_STRING("printPreviewUpdate"), |
1994 | 0 | CanBubble::eYes, ChromeOnlyDispatch::eYes |
1995 | 0 | ))->RunDOMEventWhenSafe(); |
1996 | 0 | } |
1997 | 0 | } |
1998 | | |
1999 | | nsresult |
2000 | | nsPrintJob::InitPrintDocConstruction(bool aHandleError) |
2001 | 0 | { |
2002 | 0 | nsresult rv; |
2003 | 0 | // Guarantee that mPrt->mPrintObject won't be deleted. It's owned by mPrt. |
2004 | 0 | // So, we should grab it with local variable. |
2005 | 0 | RefPtr<nsPrintData> printData = mPrt; |
2006 | 0 | rv = ReflowDocList(printData->mPrintObject, DoSetPixelScale()); |
2007 | 0 | NS_ENSURE_SUCCESS(rv, rv); |
2008 | 0 |
|
2009 | 0 | FirePrintPreviewUpdateEvent(); |
2010 | 0 |
|
2011 | 0 | if (mLoadCounter == 0) { |
2012 | 0 | AfterNetworkPrint(aHandleError); |
2013 | 0 | } |
2014 | 0 | return rv; |
2015 | 0 | } |
2016 | | |
2017 | | nsresult |
2018 | | nsPrintJob::AfterNetworkPrint(bool aHandleError) |
2019 | 0 | { |
2020 | 0 | // If Destroy() has already been called, mPtr is nullptr. Then, the instance |
2021 | 0 | // needs to do nothing anymore in this method. |
2022 | 0 | // Note: it shouldn't be possible for mPrt->mPrintObject to be null; we |
2023 | 0 | // just check it for good measure, as we check its owner. |
2024 | 0 | // Note: it shouldn't be possible for mPrt->mPrintObject->mDocShell to be |
2025 | 0 | // null; we just check it for good measure, as we check its owner. |
2026 | 0 | if (!mPrt || |
2027 | 0 | NS_WARN_IF(!mPrt->mPrintObject) || |
2028 | 0 | NS_WARN_IF(!mPrt->mPrintObject->mDocShell)) { |
2029 | 0 | return NS_ERROR_FAILURE; |
2030 | 0 | } |
2031 | 0 | |
2032 | 0 | nsCOMPtr<nsIWebProgress> webProgress = do_QueryInterface(mPrt->mPrintObject->mDocShell); |
2033 | 0 |
|
2034 | 0 | webProgress->RemoveProgressListener( |
2035 | 0 | static_cast<nsIWebProgressListener*>(this)); |
2036 | 0 |
|
2037 | 0 | nsresult rv; |
2038 | 0 | if (mIsDoingPrinting) { |
2039 | 0 | rv = DocumentReadyForPrinting(); |
2040 | 0 | } else { |
2041 | 0 | rv = FinishPrintPreview(); |
2042 | 0 | } |
2043 | 0 |
|
2044 | 0 | /* cleaup on failure + notify user */ |
2045 | 0 | if (aHandleError && NS_FAILED(rv)) { |
2046 | 0 | NS_WARNING_ASSERTION(rv == NS_ERROR_ABORT, |
2047 | 0 | "nsPrintJob::AfterNetworkPrint failed"); |
2048 | 0 | CleanupOnFailure(rv, !mIsDoingPrinting); |
2049 | 0 | } |
2050 | 0 |
|
2051 | 0 | return rv; |
2052 | 0 | } |
2053 | | |
2054 | | //////////////////////////////////////////////////////////////////////////////// |
2055 | | // nsIWebProgressListener |
2056 | | |
2057 | | NS_IMETHODIMP |
2058 | | nsPrintJob::OnStateChange(nsIWebProgress* aWebProgress, |
2059 | | nsIRequest* aRequest, |
2060 | | uint32_t aStateFlags, |
2061 | | nsresult aStatus) |
2062 | 0 | { |
2063 | 0 | nsAutoCString name; |
2064 | 0 | aRequest->GetName(name); |
2065 | 0 | if (name.EqualsLiteral("about:document-onload-blocker")) { |
2066 | 0 | return NS_OK; |
2067 | 0 | } |
2068 | 0 | if (aStateFlags & STATE_START) { |
2069 | 0 | ++mLoadCounter; |
2070 | 0 | } else if (aStateFlags & STATE_STOP) { |
2071 | 0 | mDidLoadDataForPrinting = true; |
2072 | 0 | --mLoadCounter; |
2073 | 0 |
|
2074 | 0 | // If all resources are loaded, then do a small timeout and if there |
2075 | 0 | // are still no new requests, then another reflow. |
2076 | 0 | if (mLoadCounter == 0) { |
2077 | 0 | AfterNetworkPrint(true); |
2078 | 0 | } |
2079 | 0 | } |
2080 | 0 | return NS_OK; |
2081 | 0 | } |
2082 | | |
2083 | | |
2084 | | NS_IMETHODIMP |
2085 | | nsPrintJob::OnProgressChange(nsIWebProgress* aWebProgress, |
2086 | | nsIRequest* aRequest, |
2087 | | int32_t aCurSelfProgress, |
2088 | | int32_t aMaxSelfProgress, |
2089 | | int32_t aCurTotalProgress, |
2090 | | int32_t aMaxTotalProgress) |
2091 | 0 | { |
2092 | 0 | MOZ_ASSERT_UNREACHABLE("notification excluded in AddProgressListener(...)"); |
2093 | 0 | return NS_OK; |
2094 | 0 | } |
2095 | | |
2096 | | NS_IMETHODIMP |
2097 | | nsPrintJob::OnLocationChange(nsIWebProgress* aWebProgress, |
2098 | | nsIRequest* aRequest, |
2099 | | nsIURI* aLocation, |
2100 | | uint32_t aFlags) |
2101 | 0 | { |
2102 | 0 | MOZ_ASSERT_UNREACHABLE("notification excluded in AddProgressListener(...)"); |
2103 | 0 | return NS_OK; |
2104 | 0 | } |
2105 | | |
2106 | | NS_IMETHODIMP |
2107 | | nsPrintJob::OnStatusChange(nsIWebProgress* aWebProgress, |
2108 | | nsIRequest* aRequest, |
2109 | | nsresult aStatus, |
2110 | | const char16_t* aMessage) |
2111 | 0 | { |
2112 | 0 | MOZ_ASSERT_UNREACHABLE("notification excluded in AddProgressListener(...)"); |
2113 | 0 | return NS_OK; |
2114 | 0 | } |
2115 | | |
2116 | | NS_IMETHODIMP |
2117 | | nsPrintJob::OnSecurityChange(nsIWebProgress* aWebProgress, |
2118 | | nsIRequest* aRequest, |
2119 | | uint32_t aState) |
2120 | 0 | { |
2121 | 0 | MOZ_ASSERT_UNREACHABLE("notification excluded in AddProgressListener(...)"); |
2122 | 0 | return NS_OK; |
2123 | 0 | } |
2124 | | |
2125 | | //------------------------------------------------------- |
2126 | | |
2127 | | void |
2128 | | nsPrintJob::UpdateZoomRatio(nsPrintObject* aPO, bool aSetPixelScale) |
2129 | 0 | { |
2130 | 0 | // Here is where we set the shrinkage value into the DC |
2131 | 0 | // and this is what actually makes it shrink |
2132 | 0 | if (aSetPixelScale && aPO->mFrameType != eIFrame) { |
2133 | 0 | float ratio; |
2134 | 0 | if (mPrt->mPrintFrameType == nsIPrintSettings::kFramesAsIs || mPrt->mPrintFrameType == nsIPrintSettings::kNoFrames) { |
2135 | 0 | ratio = mPrt->mShrinkRatio - 0.005f; // round down |
2136 | 0 | } else { |
2137 | 0 | ratio = aPO->mShrinkRatio - 0.005f; // round down |
2138 | 0 | } |
2139 | 0 | aPO->mZoomRatio = ratio; |
2140 | 0 | } else if (!mPrt->mShrinkToFit) { |
2141 | 0 | double scaling; |
2142 | 0 | mPrt->mPrintSettings->GetScaling(&scaling); |
2143 | 0 | aPO->mZoomRatio = float(scaling); |
2144 | 0 | } |
2145 | 0 | } |
2146 | | |
2147 | | nsresult |
2148 | | nsPrintJob::UpdateSelectionAndShrinkPrintObject(nsPrintObject* aPO, |
2149 | | bool aDocumentIsTopLevel) |
2150 | 0 | { |
2151 | 0 | nsCOMPtr<nsIPresShell> displayShell = aPO->mDocShell->GetPresShell(); |
2152 | 0 | // Transfer Selection Ranges to the new Print PresShell |
2153 | 0 | RefPtr<Selection> selection, selectionPS; |
2154 | 0 | // It's okay if there is no display shell, just skip copying the selection |
2155 | 0 | if (displayShell) { |
2156 | 0 | selection = displayShell->GetCurrentSelection(SelectionType::eNormal); |
2157 | 0 | } |
2158 | 0 | selectionPS = aPO->mPresShell->GetCurrentSelection(SelectionType::eNormal); |
2159 | 0 |
|
2160 | 0 | // Reset all existing selection ranges that might have been added by calling |
2161 | 0 | // this function before. |
2162 | 0 | if (selectionPS) { |
2163 | 0 | selectionPS->RemoveAllRanges(IgnoreErrors()); |
2164 | 0 | } |
2165 | 0 | if (selection && selectionPS) { |
2166 | 0 | int32_t cnt = selection->RangeCount(); |
2167 | 0 | int32_t inx; |
2168 | 0 | for (inx = 0; inx < cnt; ++inx) { |
2169 | 0 | selectionPS->AddRange(*selection->GetRangeAt(inx), IgnoreErrors()); |
2170 | 0 | } |
2171 | 0 | } |
2172 | 0 |
|
2173 | 0 | // If we are trying to shrink the contents to fit on the page |
2174 | 0 | // we must first locate the "pageContent" frame |
2175 | 0 | // Then we walk the frame tree and look for the "xmost" frame |
2176 | 0 | // this is the frame where the right-hand side of the frame extends |
2177 | 0 | // the furthest |
2178 | 0 | if (mPrt->mShrinkToFit && aDocumentIsTopLevel) { |
2179 | 0 | nsIPageSequenceFrame* pageSequence = aPO->mPresShell->GetPageSequenceFrame(); |
2180 | 0 | NS_ENSURE_STATE(pageSequence); |
2181 | 0 | pageSequence->GetSTFPercent(aPO->mShrinkRatio); |
2182 | 0 | // Limit the shrink-to-fit scaling for some text-ish type of documents. |
2183 | 0 | nsAutoString contentType; |
2184 | 0 | aPO->mPresShell->GetDocument()->GetContentType(contentType); |
2185 | 0 | if (contentType.EqualsLiteral("application/xhtml+xml") || |
2186 | 0 | StringBeginsWith(contentType, NS_LITERAL_STRING("text/"))) { |
2187 | 0 | int32_t limitPercent = |
2188 | 0 | Preferences::GetInt("print.shrink-to-fit.scale-limit-percent", 20); |
2189 | 0 | limitPercent = std::max(0, limitPercent); |
2190 | 0 | limitPercent = std::min(100, limitPercent); |
2191 | 0 | float minShrinkRatio = float(limitPercent) / 100; |
2192 | 0 | aPO->mShrinkRatio = std::max(aPO->mShrinkRatio, minShrinkRatio); |
2193 | 0 | } |
2194 | 0 | } |
2195 | 0 | return NS_OK; |
2196 | 0 | } |
2197 | | |
2198 | | bool |
2199 | | nsPrintJob::DoSetPixelScale() |
2200 | 0 | { |
2201 | 0 | // This is an Optimization |
2202 | 0 | // If we are in PP then we already know all the shrinkage information |
2203 | 0 | // so just transfer it to the PrintData and we will skip the extra shrinkage reflow |
2204 | 0 | // |
2205 | 0 | // doSetPixelScale tells Reflow whether to set the shrinkage value into the DC |
2206 | 0 | // The first time we do not want to do this, the second time through we do |
2207 | 0 | bool doSetPixelScale = false; |
2208 | 0 | bool ppIsShrinkToFit = mPrtPreview && mPrtPreview->mShrinkToFit; |
2209 | 0 | if (ppIsShrinkToFit) { |
2210 | 0 | mPrt->mShrinkRatio = mPrtPreview->mShrinkRatio; |
2211 | 0 | doSetPixelScale = true; |
2212 | 0 | } |
2213 | 0 | return doSetPixelScale; |
2214 | 0 | } |
2215 | | |
2216 | | nsView* |
2217 | | nsPrintJob::GetParentViewForRoot() |
2218 | 0 | { |
2219 | 0 | if (mIsCreatingPrintPreview) { |
2220 | 0 | nsCOMPtr<nsIContentViewer> cv = do_QueryInterface(mDocViewerPrint); |
2221 | 0 | if (cv) { |
2222 | 0 | return cv->FindContainerView(); |
2223 | 0 | } |
2224 | 0 | } |
2225 | 0 | return nullptr; |
2226 | 0 | } |
2227 | | |
2228 | | nsresult |
2229 | | nsPrintJob::SetRootView(nsPrintObject* aPO, |
2230 | | bool& doReturn, |
2231 | | bool& documentIsTopLevel, |
2232 | | nsSize& adjSize) |
2233 | 0 | { |
2234 | 0 | bool canCreateScrollbars = true; |
2235 | 0 |
|
2236 | 0 | nsView* rootView; |
2237 | 0 | nsView* parentView = nullptr; |
2238 | 0 |
|
2239 | 0 | doReturn = false; |
2240 | 0 |
|
2241 | 0 | if (aPO->mParent && aPO->mParent->IsPrintable()) { |
2242 | 0 | nsIFrame* frame = aPO->mContent ? aPO->mContent->GetPrimaryFrame() : nullptr; |
2243 | 0 | // Without a frame, this document can't be displayed; therefore, there is no |
2244 | 0 | // point to reflowing it |
2245 | 0 | if (!frame) { |
2246 | 0 | SetPrintPO(aPO, false); |
2247 | 0 | doReturn = true; |
2248 | 0 | return NS_OK; |
2249 | 0 | } |
2250 | 0 | |
2251 | 0 | //XXX If printing supported printing document hierarchies with non-constant |
2252 | 0 | // zoom this would be wrong as we use the same mPrt->mPrintDC for all |
2253 | 0 | // subdocuments. |
2254 | 0 | adjSize = frame->GetContentRect().Size(); |
2255 | 0 | documentIsTopLevel = false; |
2256 | 0 | // presshell exists because parent is printable |
2257 | 0 |
|
2258 | 0 | // the top nsPrintObject's widget will always have scrollbars |
2259 | 0 | if (frame && frame->IsSubDocumentFrame()) { |
2260 | 0 | nsView* view = frame->GetView(); |
2261 | 0 | NS_ENSURE_TRUE(view, NS_ERROR_FAILURE); |
2262 | 0 | view = view->GetFirstChild(); |
2263 | 0 | NS_ENSURE_TRUE(view, NS_ERROR_FAILURE); |
2264 | 0 | parentView = view; |
2265 | 0 | canCreateScrollbars = false; |
2266 | 0 | } |
2267 | 0 | } else { |
2268 | 0 | nscoord pageWidth, pageHeight; |
2269 | 0 | mPrt->mPrintDC->GetDeviceSurfaceDimensions(pageWidth, pageHeight); |
2270 | 0 | adjSize = nsSize(pageWidth, pageHeight); |
2271 | 0 | documentIsTopLevel = true; |
2272 | 0 | parentView = GetParentViewForRoot(); |
2273 | 0 | } |
2274 | 0 |
|
2275 | 0 | if (aPO->mViewManager->GetRootView()) { |
2276 | 0 | // Reuse the root view that is already on the root frame. |
2277 | 0 | rootView = aPO->mViewManager->GetRootView(); |
2278 | 0 | // Remove it from its existing parent if necessary |
2279 | 0 | aPO->mViewManager->RemoveChild(rootView); |
2280 | 0 | rootView->SetParent(parentView); |
2281 | 0 | } else { |
2282 | 0 | // Create a child window of the parent that is our "root view/window" |
2283 | 0 | nsRect tbounds = nsRect(nsPoint(0, 0), adjSize); |
2284 | 0 | rootView = aPO->mViewManager->CreateView(tbounds, parentView); |
2285 | 0 | NS_ENSURE_TRUE(rootView, NS_ERROR_OUT_OF_MEMORY); |
2286 | 0 | } |
2287 | 0 |
|
2288 | 0 | if (mIsCreatingPrintPreview && documentIsTopLevel) { |
2289 | 0 | aPO->mPresContext->SetPaginatedScrolling(canCreateScrollbars); |
2290 | 0 | } |
2291 | 0 |
|
2292 | 0 | // Setup hierarchical relationship in view manager |
2293 | 0 | aPO->mViewManager->SetRootView(rootView); |
2294 | 0 |
|
2295 | 0 | return NS_OK; |
2296 | 0 | } |
2297 | | |
2298 | | // Reflow a nsPrintObject |
2299 | | nsresult |
2300 | | nsPrintJob::ReflowPrintObject(const UniquePtr<nsPrintObject>& aPO) |
2301 | 0 | { |
2302 | 0 | NS_ENSURE_STATE(aPO); |
2303 | 0 |
|
2304 | 0 | if (!aPO->IsPrintable()) { |
2305 | 0 | return NS_OK; |
2306 | 0 | } |
2307 | 0 | |
2308 | 0 | NS_ASSERTION(!aPO->mPresContext, "Recreating prescontext"); |
2309 | 0 |
|
2310 | 0 | // Guarantee that mPrt and the objects it owns won't be deleted in this method |
2311 | 0 | // because it might be cleared if other modules called from here may fire |
2312 | 0 | // events, notifying observers and/or listeners. |
2313 | 0 | RefPtr<nsPrintData> printData = mPrt; |
2314 | 0 |
|
2315 | 0 | // create the PresContext |
2316 | 0 | nsPresContext::nsPresContextType type = |
2317 | 0 | mIsCreatingPrintPreview ? nsPresContext::eContext_PrintPreview: |
2318 | 0 | nsPresContext::eContext_Print; |
2319 | 0 | nsView* parentView = |
2320 | 0 | aPO->mParent && aPO->mParent->IsPrintable() ? nullptr : GetParentViewForRoot(); |
2321 | 0 | aPO->mPresContext = parentView ? |
2322 | 0 | new nsPresContext(aPO->mDocument, type) : |
2323 | 0 | new nsRootPresContext(aPO->mDocument, type); |
2324 | 0 | NS_ENSURE_TRUE(aPO->mPresContext, NS_ERROR_OUT_OF_MEMORY); |
2325 | 0 | aPO->mPresContext->SetPrintSettings(printData->mPrintSettings); |
2326 | 0 |
|
2327 | 0 | // set the presentation context to the value in the print settings |
2328 | 0 | bool printBGColors; |
2329 | 0 | printData->mPrintSettings->GetPrintBGColors(&printBGColors); |
2330 | 0 | aPO->mPresContext->SetBackgroundColorDraw(printBGColors); |
2331 | 0 | printData->mPrintSettings->GetPrintBGImages(&printBGColors); |
2332 | 0 | aPO->mPresContext->SetBackgroundImageDraw(printBGColors); |
2333 | 0 |
|
2334 | 0 | // init it with the DC |
2335 | 0 | nsresult rv = aPO->mPresContext->Init(printData->mPrintDC); |
2336 | 0 | NS_ENSURE_SUCCESS(rv, rv); |
2337 | 0 |
|
2338 | 0 | aPO->mViewManager = new nsViewManager(); |
2339 | 0 |
|
2340 | 0 | rv = aPO->mViewManager->Init(printData->mPrintDC); |
2341 | 0 | NS_ENSURE_SUCCESS(rv,rv); |
2342 | 0 |
|
2343 | 0 | UniquePtr<ServoStyleSet> styleSet = |
2344 | 0 | mDocViewerPrint->CreateStyleSet(aPO->mDocument); |
2345 | 0 |
|
2346 | 0 | aPO->mPresShell = aPO->mDocument->CreateShell(aPO->mPresContext, |
2347 | 0 | aPO->mViewManager, |
2348 | 0 | std::move(styleSet)); |
2349 | 0 | if (!aPO->mPresShell) { |
2350 | 0 | return NS_ERROR_FAILURE; |
2351 | 0 | } |
2352 | 0 | |
2353 | 0 | // If we're printing selection then remove the unselected nodes from our |
2354 | 0 | // cloned document. |
2355 | 0 | int16_t printRangeType = nsIPrintSettings::kRangeAllPages; |
2356 | 0 | printData->mPrintSettings->GetPrintRange(&printRangeType); |
2357 | 0 | if (printRangeType == nsIPrintSettings::kRangeSelection) { |
2358 | 0 | DeleteUnselectedNodes(aPO->mDocument->GetOriginalDocument(), aPO->mDocument); |
2359 | 0 | } |
2360 | 0 |
|
2361 | 0 | // The pres shell now owns the style set object. |
2362 | 0 |
|
2363 | 0 | bool doReturn = false;; |
2364 | 0 | bool documentIsTopLevel = false; |
2365 | 0 | nsSize adjSize; |
2366 | 0 |
|
2367 | 0 | rv = SetRootView(aPO.get(), doReturn, documentIsTopLevel, adjSize); |
2368 | 0 |
|
2369 | 0 | if (NS_FAILED(rv) || doReturn) { |
2370 | 0 | return rv; |
2371 | 0 | } |
2372 | 0 | |
2373 | 0 | PR_PL(("In DV::ReflowPrintObject PO: %p pS: %p (%9s) Setting w,h to %d,%d\n", |
2374 | 0 | aPO.get(), aPO->mPresShell.get(), |
2375 | 0 | gFrameTypesStr[aPO->mFrameType], adjSize.width, adjSize.height)); |
2376 | 0 |
|
2377 | 0 |
|
2378 | 0 | // This docshell stuff is weird; will go away when we stop having multiple |
2379 | 0 | // presentations per document |
2380 | 0 | aPO->mPresContext->SetContainer(aPO->mDocShell); |
2381 | 0 |
|
2382 | 0 | aPO->mPresShell->BeginObservingDocument(); |
2383 | 0 |
|
2384 | 0 | aPO->mPresContext->SetPageSize(adjSize); |
2385 | 0 | aPO->mPresContext->SetVisibleArea(nsRect(0, 0, adjSize.width, adjSize.height)); |
2386 | 0 | aPO->mPresContext->SetIsRootPaginatedDocument(documentIsTopLevel); |
2387 | 0 | aPO->mPresContext->SetPageScale(aPO->mZoomRatio); |
2388 | 0 | // Calculate scale factor from printer to screen |
2389 | 0 | float printDPI = float(AppUnitsPerCSSInch()) / |
2390 | 0 | float(printData->mPrintDC->AppUnitsPerDevPixel()); |
2391 | 0 | aPO->mPresContext->SetPrintPreviewScale(mScreenDPI / printDPI); |
2392 | 0 |
|
2393 | 0 | if (mIsCreatingPrintPreview && documentIsTopLevel) { |
2394 | 0 | mDocViewerPrint->SetPrintPreviewPresentation(aPO->mViewManager, |
2395 | 0 | aPO->mPresContext, |
2396 | 0 | aPO->mPresShell); |
2397 | 0 | } |
2398 | 0 |
|
2399 | 0 | rv = aPO->mPresShell->Initialize(); |
2400 | 0 |
|
2401 | 0 | NS_ENSURE_SUCCESS(rv, rv); |
2402 | 0 | NS_ASSERTION(aPO->mPresShell, "Presshell should still be here"); |
2403 | 0 |
|
2404 | 0 | // Process the reflow event Initialize posted |
2405 | 0 | aPO->mPresShell->FlushPendingNotifications(FlushType::Layout); |
2406 | 0 |
|
2407 | 0 | rv = UpdateSelectionAndShrinkPrintObject(aPO.get(), documentIsTopLevel); |
2408 | 0 | NS_ENSURE_SUCCESS(rv, rv); |
2409 | 0 |
|
2410 | | #ifdef EXTENDED_DEBUG_PRINTING |
2411 | | if (MOZ_LOG_TEST(gPrintingLog, DUMP_LAYOUT_LEVEL)) { |
2412 | | nsAutoCString docStr; |
2413 | | nsAutoCString urlStr; |
2414 | | GetDocTitleAndURL(aPO, docStr, urlStr); |
2415 | | char filename[256]; |
2416 | | sprintf(filename, "print_dump_%d.txt", gDumpFileNameCnt++); |
2417 | | // Dump all the frames and view to a a file |
2418 | | FILE * fd = fopen(filename, "w"); |
2419 | | if (fd) { |
2420 | | nsIFrame *theRootFrame = |
2421 | | aPO->mPresShell->GetRootFrame(); |
2422 | | fprintf(fd, "Title: %s\n", docStr.get()); |
2423 | | fprintf(fd, "URL: %s\n", urlStr.get()); |
2424 | | fprintf(fd, "--------------- Frames ----------------\n"); |
2425 | | //RefPtr<gfxContext> renderingContext = |
2426 | | // printData->mPrintDocDC->CreateRenderingContext(); |
2427 | | RootFrameList(aPO->mPresContext, fd, 0); |
2428 | | //DumpFrames(fd, aPO->mPresContext, renderingContext, theRootFrame, 0); |
2429 | | fprintf(fd, "---------------------------------------\n\n"); |
2430 | | fprintf(fd, "--------------- Views From Root Frame----------------\n"); |
2431 | | nsView* v = theRootFrame->GetView(); |
2432 | | if (v) { |
2433 | | v->List(fd); |
2434 | | } else { |
2435 | | printf("View is null!\n"); |
2436 | | } |
2437 | | if (aPO->mDocShell) { |
2438 | | fprintf(fd, "--------------- All Views ----------------\n"); |
2439 | | DumpViews(aPO->mDocShell, fd); |
2440 | | fprintf(fd, "---------------------------------------\n\n"); |
2441 | | } |
2442 | | fclose(fd); |
2443 | | } |
2444 | | } |
2445 | | #endif |
2446 | |
|
2447 | 0 | return NS_OK; |
2448 | 0 | } |
2449 | | |
2450 | | //------------------------------------------------------- |
2451 | | // Figure out how many documents and how many total pages we are printing |
2452 | | void |
2453 | | nsPrintJob::CalcNumPrintablePages(int32_t& aNumPages) |
2454 | 0 | { |
2455 | 0 | aNumPages = 0; |
2456 | 0 | // Count the number of printable documents |
2457 | 0 | // and printable pages |
2458 | 0 | for (uint32_t i=0; i<mPrt->mPrintDocList.Length(); i++) { |
2459 | 0 | nsPrintObject* po = mPrt->mPrintDocList.ElementAt(i); |
2460 | 0 | NS_ASSERTION(po, "nsPrintObject can't be null!"); |
2461 | 0 | // Note: The po->mPresContext null-check below is necessary, because it's |
2462 | 0 | // possible po->mPresContext might never have been set. (e.g., if |
2463 | 0 | // IsPrintable() returns false, ReflowPrintObject bails before setting |
2464 | 0 | // mPresContext) |
2465 | 0 | if (po->mPresContext && po->mPresContext->IsRootPaginatedDocument()) { |
2466 | 0 | nsIPageSequenceFrame* pageSequence = po->mPresShell->GetPageSequenceFrame(); |
2467 | 0 | nsIFrame * seqFrame = do_QueryFrame(pageSequence); |
2468 | 0 | if (seqFrame) { |
2469 | 0 | aNumPages += seqFrame->PrincipalChildList().GetLength(); |
2470 | 0 | } |
2471 | 0 | } |
2472 | 0 | } |
2473 | 0 | } |
2474 | | |
2475 | | //----------------------------------------------------------------- |
2476 | | //-- Done: Reflow Methods |
2477 | | //----------------------------------------------------------------- |
2478 | | |
2479 | | //----------------------------------------------------------------- |
2480 | | //-- Section: Printing Methods |
2481 | | //----------------------------------------------------------------- |
2482 | | |
2483 | | //------------------------------------------------------- |
2484 | | // Called for each DocShell that needs to be printed |
2485 | | bool |
2486 | | nsPrintJob::PrintDocContent(const UniquePtr<nsPrintObject>& aPO, |
2487 | | nsresult& aStatus) |
2488 | 0 | { |
2489 | 0 | NS_ASSERTION(aPO, "Pointer is null!"); |
2490 | 0 | aStatus = NS_OK; |
2491 | 0 |
|
2492 | 0 | if (!aPO->mHasBeenPrinted && aPO->IsPrintable()) { |
2493 | 0 | aStatus = DoPrint(aPO); |
2494 | 0 | return true; |
2495 | 0 | } |
2496 | 0 | |
2497 | 0 | // If |aPO->mPrintAsIs| and |aPO->mHasBeenPrinted| are true, |
2498 | 0 | // the kids frames are already processed in |PrintPage|. |
2499 | 0 | if (!aPO->mInvisible && !(aPO->mPrintAsIs && aPO->mHasBeenPrinted)) { |
2500 | 0 | for (const UniquePtr<nsPrintObject>& po : aPO->mKids) { |
2501 | 0 | bool printed = PrintDocContent(po, aStatus); |
2502 | 0 | if (printed || NS_FAILED(aStatus)) { |
2503 | 0 | return true; |
2504 | 0 | } |
2505 | 0 | } |
2506 | 0 | } |
2507 | 0 | return false; |
2508 | 0 | } |
2509 | | |
2510 | | static nsINode* |
2511 | | GetCorrespondingNodeInDocument(const nsINode* aNode, nsIDocument* aDoc) |
2512 | 0 | { |
2513 | 0 | MOZ_ASSERT(aNode); |
2514 | 0 | MOZ_ASSERT(aDoc); |
2515 | 0 |
|
2516 | 0 | // Selections in anonymous subtrees aren't supported. |
2517 | 0 | if (aNode->IsInAnonymousSubtree()) { |
2518 | 0 | return nullptr; |
2519 | 0 | } |
2520 | 0 | |
2521 | 0 | nsTArray<int32_t> indexArray; |
2522 | 0 | const nsINode* child = aNode; |
2523 | 0 | while (const nsINode* parent = child->GetParentNode()) { |
2524 | 0 | int32_t index = parent->ComputeIndexOf(child); |
2525 | 0 | MOZ_ASSERT(index >= 0); |
2526 | 0 | indexArray.AppendElement(index); |
2527 | 0 | child = parent; |
2528 | 0 | } |
2529 | 0 | MOZ_ASSERT(child->IsDocument()); |
2530 | 0 |
|
2531 | 0 | nsINode* correspondingNode = aDoc; |
2532 | 0 | for (int32_t i = indexArray.Length() - 1; i >= 0; --i) { |
2533 | 0 | correspondingNode = correspondingNode->GetChildAt_Deprecated(indexArray[i]); |
2534 | 0 | NS_ENSURE_TRUE(correspondingNode, nullptr); |
2535 | 0 | } |
2536 | 0 |
|
2537 | 0 | return correspondingNode; |
2538 | 0 | } |
2539 | | |
2540 | | static NS_NAMED_LITERAL_STRING(kEllipsis, u"\x2026"); |
2541 | | |
2542 | | static nsresult |
2543 | | DeleteUnselectedNodes(nsIDocument* aOrigDoc, nsIDocument* aDoc) |
2544 | 0 | { |
2545 | 0 | nsIPresShell* origShell = aOrigDoc->GetShell(); |
2546 | 0 | nsIPresShell* shell = aDoc->GetShell(); |
2547 | 0 | NS_ENSURE_STATE(origShell && shell); |
2548 | 0 |
|
2549 | 0 | RefPtr<Selection> origSelection = |
2550 | 0 | origShell->GetCurrentSelection(SelectionType::eNormal); |
2551 | 0 | RefPtr<Selection> selection = |
2552 | 0 | shell->GetCurrentSelection(SelectionType::eNormal); |
2553 | 0 | NS_ENSURE_STATE(origSelection && selection); |
2554 | 0 |
|
2555 | 0 | nsINode* bodyNode = aDoc->GetBodyElement(); |
2556 | 0 | nsINode* startNode = bodyNode; |
2557 | 0 | uint32_t startOffset = 0; |
2558 | 0 | uint32_t ellipsisOffset = 0; |
2559 | 0 |
|
2560 | 0 | int32_t rangeCount = origSelection->RangeCount(); |
2561 | 0 | for (int32_t i = 0; i < rangeCount; ++i) { |
2562 | 0 | nsRange* origRange = origSelection->GetRangeAt(i); |
2563 | 0 |
|
2564 | 0 | // New end is start of original range. |
2565 | 0 | nsINode* endNode = |
2566 | 0 | GetCorrespondingNodeInDocument(origRange->GetStartContainer(), aDoc); |
2567 | 0 |
|
2568 | 0 | // If we're no longer in the same text node reset the ellipsis offset. |
2569 | 0 | if (endNode != startNode) { |
2570 | 0 | ellipsisOffset = 0; |
2571 | 0 | } |
2572 | 0 | uint32_t endOffset = origRange->StartOffset() + ellipsisOffset; |
2573 | 0 |
|
2574 | 0 | // Create the range that we want to remove. Note that if startNode or |
2575 | 0 | // endNode are null CreateRange will fail and we won't remove that section. |
2576 | 0 | RefPtr<nsRange> range; |
2577 | 0 | nsresult rv = nsRange::CreateRange(startNode, startOffset, endNode, |
2578 | 0 | endOffset, getter_AddRefs(range)); |
2579 | 0 |
|
2580 | 0 | if (NS_SUCCEEDED(rv) && !range->Collapsed()) { |
2581 | 0 | selection->AddRange(*range, IgnoreErrors()); |
2582 | 0 |
|
2583 | 0 | // Unless we've already added an ellipsis at the start, if we ended mid |
2584 | 0 | // text node then add ellipsis. |
2585 | 0 | Text* text = endNode->GetAsText(); |
2586 | 0 | if (!ellipsisOffset && text && endOffset && endOffset < text->Length()) { |
2587 | 0 | text->InsertData(endOffset, kEllipsis, IgnoreErrors()); |
2588 | 0 | ellipsisOffset += kEllipsis.Length(); |
2589 | 0 | } |
2590 | 0 | } |
2591 | 0 |
|
2592 | 0 | // Next new start is end of original range. |
2593 | 0 | startNode = |
2594 | 0 | GetCorrespondingNodeInDocument(origRange->GetEndContainer(), aDoc); |
2595 | 0 |
|
2596 | 0 | // If we're no longer in the same text node reset the ellipsis offset. |
2597 | 0 | if (startNode != endNode) { |
2598 | 0 | ellipsisOffset = 0; |
2599 | 0 | } |
2600 | 0 | startOffset = origRange->EndOffset() + ellipsisOffset; |
2601 | 0 |
|
2602 | 0 | // If the next node will start mid text node then add ellipsis. |
2603 | 0 | Text* text = startNode ? startNode->GetAsText() : nullptr; |
2604 | 0 | if (text && startOffset && startOffset < text->Length()) { |
2605 | 0 | text->InsertData(startOffset, kEllipsis, IgnoreErrors()); |
2606 | 0 | startOffset += kEllipsis.Length(); |
2607 | 0 | ellipsisOffset += kEllipsis.Length(); |
2608 | 0 | } |
2609 | 0 | } |
2610 | 0 |
|
2611 | 0 | // Add in the last range to the end of the body. |
2612 | 0 | RefPtr<nsRange> lastRange; |
2613 | 0 | nsresult rv = nsRange::CreateRange(startNode, startOffset, bodyNode, |
2614 | 0 | bodyNode->GetChildCount(), |
2615 | 0 | getter_AddRefs(lastRange)); |
2616 | 0 | if (NS_SUCCEEDED(rv) && !lastRange->Collapsed()) { |
2617 | 0 | selection->AddRange(*lastRange, IgnoreErrors()); |
2618 | 0 | } |
2619 | 0 |
|
2620 | 0 | selection->DeleteFromDocument(IgnoreErrors()); |
2621 | 0 | return NS_OK; |
2622 | 0 | } |
2623 | | |
2624 | | //------------------------------------------------------- |
2625 | | nsresult |
2626 | | nsPrintJob::DoPrint(const UniquePtr<nsPrintObject>& aPO) |
2627 | 0 | { |
2628 | 0 | PR_PL(("\n")); |
2629 | 0 | PR_PL(("**************************** %s ****************************\n", gFrameTypesStr[aPO->mFrameType])); |
2630 | 0 | PR_PL(("****** In DV::DoPrint PO: %p \n", aPO.get())); |
2631 | 0 |
|
2632 | 0 | nsIPresShell* poPresShell = aPO->mPresShell; |
2633 | 0 | nsPresContext* poPresContext = aPO->mPresContext; |
2634 | 0 |
|
2635 | 0 | NS_ASSERTION(poPresContext, "PrintObject has not been reflowed"); |
2636 | 0 | NS_ASSERTION(poPresContext->Type() != nsPresContext::eContext_PrintPreview, |
2637 | 0 | "How did this context end up here?"); |
2638 | 0 |
|
2639 | 0 | // Guarantee that mPrt and the objects it owns won't be deleted in this method |
2640 | 0 | // because it might be cleared if other modules called from here may fire |
2641 | 0 | // events, notifying observers and/or listeners. |
2642 | 0 | RefPtr<nsPrintData> printData = mPrt; |
2643 | 0 |
|
2644 | 0 | if (printData->mPrintProgressParams) { |
2645 | 0 | SetDocAndURLIntoProgress(aPO, printData->mPrintProgressParams); |
2646 | 0 | } |
2647 | 0 |
|
2648 | 0 | { |
2649 | 0 | // Ask the page sequence frame to print all the pages |
2650 | 0 | nsIPageSequenceFrame* pageSequence = poPresShell->GetPageSequenceFrame(); |
2651 | 0 | NS_ASSERTION(nullptr != pageSequence, "no page sequence frame"); |
2652 | 0 |
|
2653 | 0 | // We are done preparing for printing, so we can turn this off |
2654 | 0 | printData->mPreparingForPrint = false; |
2655 | 0 |
|
2656 | | #ifdef EXTENDED_DEBUG_PRINTING |
2657 | | nsIFrame* rootFrame = poPresShell->GetRootFrame(); |
2658 | | if (aPO->IsPrintable()) { |
2659 | | nsAutoCString docStr; |
2660 | | nsAutoCString urlStr; |
2661 | | GetDocTitleAndURL(aPO, docStr, urlStr); |
2662 | | DumpLayoutData(docStr.get(), urlStr.get(), poPresContext, |
2663 | | printData->mPrintDC, rootFrame, aPO->mDocShell, nullptr); |
2664 | | } |
2665 | | #endif |
2666 | |
|
2667 | 0 | if (!printData->mPrintSettings) { |
2668 | 0 | // not sure what to do here! |
2669 | 0 | SetIsPrinting(false); |
2670 | 0 | return NS_ERROR_FAILURE; |
2671 | 0 | } |
2672 | 0 | |
2673 | 0 | nsAutoString docTitleStr; |
2674 | 0 | nsAutoString docURLStr; |
2675 | 0 | GetDisplayTitleAndURL(aPO, docTitleStr, docURLStr, eDocTitleDefBlank); |
2676 | 0 |
|
2677 | 0 | nsIFrame * seqFrame = do_QueryFrame(pageSequence); |
2678 | 0 | if (!seqFrame) { |
2679 | 0 | SetIsPrinting(false); |
2680 | 0 | return NS_ERROR_FAILURE; |
2681 | 0 | } |
2682 | 0 | |
2683 | 0 | mPageSeqFrame = seqFrame; |
2684 | 0 | pageSequence->StartPrint(poPresContext, printData->mPrintSettings, |
2685 | 0 | docTitleStr, docURLStr); |
2686 | 0 |
|
2687 | 0 | // Schedule Page to Print |
2688 | 0 | PR_PL(("Scheduling Print of PO: %p (%s) \n", aPO.get(), gFrameTypesStr[aPO->mFrameType])); |
2689 | 0 | StartPagePrintTimer(aPO); |
2690 | 0 | } |
2691 | 0 |
|
2692 | 0 | return NS_OK; |
2693 | 0 | } |
2694 | | |
2695 | | //--------------------------------------------------------------------- |
2696 | | void |
2697 | | nsPrintJob::SetDocAndURLIntoProgress(const UniquePtr<nsPrintObject>& aPO, |
2698 | | nsIPrintProgressParams* aParams) |
2699 | 0 | { |
2700 | 0 | NS_ASSERTION(aPO, "Must have valid nsPrintObject"); |
2701 | 0 | NS_ASSERTION(aParams, "Must have valid nsIPrintProgressParams"); |
2702 | 0 |
|
2703 | 0 | if (!aPO || !aPO->mDocShell || !aParams) { |
2704 | 0 | return; |
2705 | 0 | } |
2706 | 0 | const uint32_t kTitleLength = 64; |
2707 | 0 |
|
2708 | 0 | nsAutoString docTitleStr; |
2709 | 0 | nsAutoString docURLStr; |
2710 | 0 | GetDisplayTitleAndURL(aPO, docTitleStr, docURLStr, eDocTitleDefURLDoc); |
2711 | 0 |
|
2712 | 0 | // Make sure the Titles & URLS don't get too long for the progress dialog |
2713 | 0 | EllipseLongString(docTitleStr, kTitleLength, false); |
2714 | 0 | EllipseLongString(docURLStr, kTitleLength, true); |
2715 | 0 |
|
2716 | 0 | aParams->SetDocTitle(docTitleStr); |
2717 | 0 | aParams->SetDocURL(docURLStr); |
2718 | 0 | } |
2719 | | |
2720 | | //--------------------------------------------------------------------- |
2721 | | void |
2722 | | nsPrintJob::EllipseLongString(nsAString& aStr, const uint32_t aLen, bool aDoFront) |
2723 | 0 | { |
2724 | 0 | // Make sure the URLS don't get too long for the progress dialog |
2725 | 0 | if (aLen >= 3 && aStr.Length() > aLen) { |
2726 | 0 | if (aDoFront) { |
2727 | 0 | nsAutoString newStr; |
2728 | 0 | newStr.AppendLiteral("..."); |
2729 | 0 | newStr += Substring(aStr, aStr.Length() - (aLen - 3), aLen - 3); |
2730 | 0 | aStr = newStr; |
2731 | 0 | } else { |
2732 | 0 | aStr.SetLength(aLen - 3); |
2733 | 0 | aStr.AppendLiteral("..."); |
2734 | 0 | } |
2735 | 0 | } |
2736 | 0 | } |
2737 | | |
2738 | | static bool |
2739 | | DocHasPrintCallbackCanvas(nsIDocument* aDoc, void* aData) |
2740 | 0 | { |
2741 | 0 | if (!aDoc) { |
2742 | 0 | return true; |
2743 | 0 | } |
2744 | 0 | Element* root = aDoc->GetRootElement(); |
2745 | 0 | if (!root) { |
2746 | 0 | return true; |
2747 | 0 | } |
2748 | 0 | RefPtr<nsContentList> canvases = NS_GetContentList(root, |
2749 | 0 | kNameSpaceID_XHTML, |
2750 | 0 | NS_LITERAL_STRING("canvas")); |
2751 | 0 | uint32_t canvasCount = canvases->Length(true); |
2752 | 0 | for (uint32_t i = 0; i < canvasCount; ++i) { |
2753 | 0 | HTMLCanvasElement* canvas = HTMLCanvasElement::FromNodeOrNull(canvases->Item(i, false)); |
2754 | 0 | if (canvas && canvas->GetMozPrintCallback()) { |
2755 | 0 | // This subdocument has a print callback. Set result and return false to |
2756 | 0 | // stop iteration. |
2757 | 0 | *static_cast<bool*>(aData) = true; |
2758 | 0 | return false; |
2759 | 0 | } |
2760 | 0 | } |
2761 | 0 | return true; |
2762 | 0 | } |
2763 | | |
2764 | | static bool |
2765 | | DocHasPrintCallbackCanvas(nsIDocument* aDoc) |
2766 | 0 | { |
2767 | 0 | bool result = false; |
2768 | 0 | aDoc->EnumerateSubDocuments(&DocHasPrintCallbackCanvas, static_cast<void*>(&result)); |
2769 | 0 | return result; |
2770 | 0 | } |
2771 | | |
2772 | | /** |
2773 | | * Checks to see if the document this print engine is associated with has any |
2774 | | * canvases that have a mozPrintCallback. |
2775 | | * https://developer.mozilla.org/en-US/docs/Web/API/HTMLCanvasElement#Properties |
2776 | | */ |
2777 | | bool |
2778 | | nsPrintJob::HasPrintCallbackCanvas() |
2779 | 0 | { |
2780 | 0 | if (!mDocument) { |
2781 | 0 | return false; |
2782 | 0 | } |
2783 | 0 | // First check this mDocument. |
2784 | 0 | bool result = false; |
2785 | 0 | DocHasPrintCallbackCanvas(mDocument, static_cast<void*>(&result)); |
2786 | 0 | // Also check the sub documents. |
2787 | 0 | return result || DocHasPrintCallbackCanvas(mDocument); |
2788 | 0 | } |
2789 | | |
2790 | | //------------------------------------------------------- |
2791 | | bool |
2792 | | nsPrintJob::PrePrintPage() |
2793 | 0 | { |
2794 | 0 | NS_ASSERTION(mPageSeqFrame.IsAlive(), "mPageSeqFrame is not alive!"); |
2795 | 0 | NS_ASSERTION(mPrt, "mPrt is null!"); |
2796 | 0 |
|
2797 | 0 | // Although these should NEVER be nullptr |
2798 | 0 | // This is added insurance, to make sure we don't crash in optimized builds |
2799 | 0 | if (!mPrt || !mPageSeqFrame.IsAlive()) { |
2800 | 0 | return true; // means we are done preparing the page. |
2801 | 0 | } |
2802 | 0 | |
2803 | 0 | // Guarantee that mPrt won't be deleted during a call of |
2804 | 0 | // FirePrintingErrorEvent(). |
2805 | 0 | RefPtr<nsPrintData> printData = mPrt; |
2806 | 0 |
|
2807 | 0 | // Check setting to see if someone request it be cancelled |
2808 | 0 | bool isCancelled = false; |
2809 | 0 | printData->mPrintSettings->GetIsCancelled(&isCancelled); |
2810 | 0 | if (isCancelled) |
2811 | 0 | return true; |
2812 | 0 | |
2813 | 0 | // Ask mPageSeqFrame if the page is ready to be printed. |
2814 | 0 | // If the page doesn't get printed at all, the |done| will be |true|. |
2815 | 0 | bool done = false; |
2816 | 0 | nsIPageSequenceFrame* pageSeqFrame = do_QueryFrame(mPageSeqFrame.GetFrame()); |
2817 | 0 | nsresult rv = pageSeqFrame->PrePrintNextPage(mPagePrintTimer, &done); |
2818 | 0 | if (NS_FAILED(rv)) { |
2819 | 0 | // ??? ::PrintPage doesn't set |printData->mIsAborted = true| if |
2820 | 0 | // rv != NS_ERROR_ABORT, but I don't really understand why this should be |
2821 | 0 | // the right thing to do? Shouldn't |printData->mIsAborted| set to true |
2822 | 0 | // all the time if something went wrong? |
2823 | 0 | if (rv != NS_ERROR_ABORT) { |
2824 | 0 | FirePrintingErrorEvent(rv); |
2825 | 0 | printData->mIsAborted = true; |
2826 | 0 | } |
2827 | 0 | done = true; |
2828 | 0 | } |
2829 | 0 | return done; |
2830 | 0 | } |
2831 | | |
2832 | | bool |
2833 | | nsPrintJob::PrintPage(nsPrintObject* aPO, |
2834 | | bool& aInRange) |
2835 | 0 | { |
2836 | 0 | NS_ASSERTION(aPO, "aPO is null!"); |
2837 | 0 | NS_ASSERTION(mPageSeqFrame.IsAlive(), "mPageSeqFrame is not alive!"); |
2838 | 0 | NS_ASSERTION(mPrt, "mPrt is null!"); |
2839 | 0 |
|
2840 | 0 | // Although these should NEVER be nullptr |
2841 | 0 | // This is added insurance, to make sure we don't crash in optimized builds |
2842 | 0 | if (!mPrt || !aPO || !mPageSeqFrame.IsAlive()) { |
2843 | 0 | FirePrintingErrorEvent(NS_ERROR_FAILURE); |
2844 | 0 | return true; // means we are done printing |
2845 | 0 | } |
2846 | 0 | |
2847 | 0 | // Guarantee that mPrt won't be deleted during a call of |
2848 | 0 | // nsPrintData::DoOnProgressChange() which runs some listeners, |
2849 | 0 | // which may clear (& might otherwise destroy). |
2850 | 0 | RefPtr<nsPrintData> printData = mPrt; |
2851 | 0 |
|
2852 | 0 | PR_PL(("-----------------------------------\n")); |
2853 | 0 | PR_PL(("------ In DV::PrintPage PO: %p (%s)\n", aPO, gFrameTypesStr[aPO->mFrameType])); |
2854 | 0 |
|
2855 | 0 | // Check setting to see if someone request it be cancelled |
2856 | 0 | bool isCancelled = false; |
2857 | 0 | printData->mPrintSettings->GetIsCancelled(&isCancelled); |
2858 | 0 | if (isCancelled || printData->mIsAborted) { |
2859 | 0 | return true; |
2860 | 0 | } |
2861 | 0 | |
2862 | 0 | int32_t pageNum, numPages, endPage; |
2863 | 0 | nsIPageSequenceFrame* pageSeqFrame = do_QueryFrame(mPageSeqFrame.GetFrame()); |
2864 | 0 | pageSeqFrame->GetCurrentPageNum(&pageNum); |
2865 | 0 | pageSeqFrame->GetNumPages(&numPages); |
2866 | 0 |
|
2867 | 0 | bool donePrinting; |
2868 | 0 | bool isDoingPrintRange; |
2869 | 0 | pageSeqFrame->IsDoingPrintRange(&isDoingPrintRange); |
2870 | 0 | if (isDoingPrintRange) { |
2871 | 0 | int32_t fromPage; |
2872 | 0 | int32_t toPage; |
2873 | 0 | pageSeqFrame->GetPrintRange(&fromPage, &toPage); |
2874 | 0 |
|
2875 | 0 | if (fromPage > numPages) { |
2876 | 0 | return true; |
2877 | 0 | } |
2878 | 0 | if (toPage > numPages) { |
2879 | 0 | toPage = numPages; |
2880 | 0 | } |
2881 | 0 |
|
2882 | 0 | PR_PL(("****** Printing Page %d printing from %d to page %d\n", pageNum, fromPage, toPage)); |
2883 | 0 |
|
2884 | 0 | donePrinting = pageNum >= toPage; |
2885 | 0 | aInRange = pageNum >= fromPage && pageNum <= toPage; |
2886 | 0 | endPage = (toPage - fromPage)+1; |
2887 | 0 | } else { |
2888 | 0 | PR_PL(("****** Printing Page %d of %d page(s)\n", pageNum, numPages)); |
2889 | 0 |
|
2890 | 0 | donePrinting = pageNum >= numPages; |
2891 | 0 | endPage = numPages; |
2892 | 0 | aInRange = true; |
2893 | 0 | } |
2894 | 0 |
|
2895 | 0 | // XXX This is wrong, but the actual behavior in the presence of a print |
2896 | 0 | // range sucks. |
2897 | 0 | if (printData->mPrintFrameType == nsIPrintSettings::kEachFrameSep) { |
2898 | 0 | endPage = printData->mNumPrintablePages; |
2899 | 0 | } |
2900 | 0 |
|
2901 | 0 | printData->DoOnProgressChange(++printData->mNumPagesPrinted, |
2902 | 0 | endPage, false, 0); |
2903 | 0 | if (NS_WARN_IF(mPrt != printData)) { |
2904 | 0 | // If current printing is canceled or new print is started, let's return |
2905 | 0 | // true to notify the caller of current printing is done. |
2906 | 0 | return true; |
2907 | 0 | } |
2908 | 0 | |
2909 | 0 | if (XRE_IsParentProcess() && !printData->mPrintDC->IsSyncPagePrinting()) { |
2910 | 0 | mPagePrintTimer->WaitForRemotePrint(); |
2911 | 0 | } |
2912 | 0 |
|
2913 | 0 | // Print the Page |
2914 | 0 | // if a print job was cancelled externally, an EndPage or BeginPage may |
2915 | 0 | // fail and the failure is passed back here. |
2916 | 0 | // Returning true means we are done printing. |
2917 | 0 | // |
2918 | 0 | // When rv == NS_ERROR_ABORT, it means we want out of the |
2919 | 0 | // print job without displaying any error messages |
2920 | 0 | nsresult rv = pageSeqFrame->PrintNextPage(); |
2921 | 0 | if (NS_FAILED(rv)) { |
2922 | 0 | if (rv != NS_ERROR_ABORT) { |
2923 | 0 | FirePrintingErrorEvent(rv); |
2924 | 0 | printData->mIsAborted = true; |
2925 | 0 | } |
2926 | 0 | return true; |
2927 | 0 | } |
2928 | 0 |
|
2929 | 0 | pageSeqFrame->DoPageEnd(); |
2930 | 0 |
|
2931 | 0 | return donePrinting; |
2932 | 0 | } |
2933 | | |
2934 | | void |
2935 | | nsPrintJob::PageDone(nsresult aResult) |
2936 | 0 | { |
2937 | 0 | MOZ_ASSERT(mIsDoingPrinting); |
2938 | 0 |
|
2939 | 0 | // mPagePrintTimer might be released during RemotePrintFinished, keep a |
2940 | 0 | // reference here to make sure it lives long enough. |
2941 | 0 | RefPtr<nsPagePrintTimer> timer = mPagePrintTimer; |
2942 | 0 | timer->RemotePrintFinished(); |
2943 | 0 | } |
2944 | | |
2945 | | //----------------------------------------------------------------- |
2946 | | //-- Done: Printing Methods |
2947 | | //----------------------------------------------------------------- |
2948 | | |
2949 | | |
2950 | | //----------------------------------------------------------------- |
2951 | | //-- Section: Misc Support Methods |
2952 | | //----------------------------------------------------------------- |
2953 | | |
2954 | | //--------------------------------------------------------------------- |
2955 | | void |
2956 | | nsPrintJob::SetIsPrinting(bool aIsPrinting) |
2957 | 0 | { |
2958 | 0 | mIsDoingPrinting = aIsPrinting; |
2959 | 0 | // Calling SetIsPrinting while in print preview confuses the document viewer |
2960 | 0 | // This is safe because we prevent exiting print preview while printing |
2961 | 0 | if (!mIsDoingPrintPreview && mDocViewerPrint) { |
2962 | 0 | mDocViewerPrint->SetIsPrinting(aIsPrinting); |
2963 | 0 | } |
2964 | 0 | if (mPrt && aIsPrinting) { |
2965 | 0 | mPrt->mPreparingForPrint = true; |
2966 | 0 | } |
2967 | 0 | } |
2968 | | |
2969 | | //--------------------------------------------------------------------- |
2970 | | void |
2971 | | nsPrintJob::SetIsPrintPreview(bool aIsPrintPreview) |
2972 | 0 | { |
2973 | 0 | mIsDoingPrintPreview = aIsPrintPreview; |
2974 | 0 |
|
2975 | 0 | if (mDocViewerPrint) { |
2976 | 0 | mDocViewerPrint->SetIsPrintPreview(aIsPrintPreview); |
2977 | 0 | } |
2978 | 0 | } |
2979 | | |
2980 | | //--------------------------------------------------------------------- |
2981 | | void |
2982 | | nsPrintJob::CleanupDocTitleArray(char16_t**& aArray, int32_t& aCount) |
2983 | 0 | { |
2984 | 0 | for (int32_t i = aCount - 1; i >= 0; i--) { |
2985 | 0 | free(aArray[i]); |
2986 | 0 | } |
2987 | 0 | free(aArray); |
2988 | 0 | aArray = nullptr; |
2989 | 0 | aCount = 0; |
2990 | 0 | } |
2991 | | |
2992 | | /** --------------------------------------------------- |
2993 | | * Get the Focused Frame for a documentviewer |
2994 | | */ |
2995 | | already_AddRefed<nsPIDOMWindowOuter> |
2996 | | nsPrintJob::FindFocusedDOMWindow() |
2997 | 0 | { |
2998 | 0 | nsIFocusManager* fm = nsFocusManager::GetFocusManager(); |
2999 | 0 | NS_ENSURE_TRUE(fm, nullptr); |
3000 | 0 |
|
3001 | 0 | nsPIDOMWindowOuter* window = mDocument->GetWindow(); |
3002 | 0 | NS_ENSURE_TRUE(window, nullptr); |
3003 | 0 |
|
3004 | 0 | nsCOMPtr<nsPIDOMWindowOuter> rootWindow = window->GetPrivateRoot(); |
3005 | 0 | NS_ENSURE_TRUE(rootWindow, nullptr); |
3006 | 0 |
|
3007 | 0 | nsCOMPtr<nsPIDOMWindowOuter> focusedWindow; |
3008 | 0 | nsFocusManager::GetFocusedDescendant(rootWindow, |
3009 | 0 | nsFocusManager::eIncludeAllDescendants, |
3010 | 0 | getter_AddRefs(focusedWindow)); |
3011 | 0 | NS_ENSURE_TRUE(focusedWindow, nullptr); |
3012 | 0 |
|
3013 | 0 | if (IsWindowsInOurSubTree(focusedWindow)) { |
3014 | 0 | return focusedWindow.forget(); |
3015 | 0 | } |
3016 | 0 | |
3017 | 0 | return nullptr; |
3018 | 0 | } |
3019 | | |
3020 | | //--------------------------------------------------------------------- |
3021 | | bool |
3022 | | nsPrintJob::IsWindowsInOurSubTree(nsPIDOMWindowOuter* window) |
3023 | 0 | { |
3024 | 0 | bool found = false; |
3025 | 0 |
|
3026 | 0 | // now check to make sure it is in "our" tree of docshells |
3027 | 0 | if (window) { |
3028 | 0 | nsCOMPtr<nsIDocShell> docShell = window->GetDocShell(); |
3029 | 0 |
|
3030 | 0 | if (docShell) { |
3031 | 0 | // get this DocViewer docshell |
3032 | 0 | nsCOMPtr<nsIDocShell> thisDVDocShell(do_QueryReferent(mContainer)); |
3033 | 0 | while (!found) { |
3034 | 0 | if (docShell) { |
3035 | 0 | if (docShell == thisDVDocShell) { |
3036 | 0 | found = true; |
3037 | 0 | break; |
3038 | 0 | } |
3039 | 0 | } else { |
3040 | 0 | break; // at top of tree |
3041 | 0 | } |
3042 | 0 | nsCOMPtr<nsIDocShellTreeItem> docShellItemParent; |
3043 | 0 | docShell->GetSameTypeParent(getter_AddRefs(docShellItemParent)); |
3044 | 0 | docShell = do_QueryInterface(docShellItemParent); |
3045 | 0 | } // while |
3046 | 0 | } |
3047 | 0 | } // scriptobj |
3048 | 0 |
|
3049 | 0 | return found; |
3050 | 0 | } |
3051 | | |
3052 | | //------------------------------------------------------- |
3053 | | bool |
3054 | | nsPrintJob::DonePrintingPages(nsPrintObject* aPO, nsresult aResult) |
3055 | 0 | { |
3056 | 0 | //NS_ASSERTION(aPO, "Pointer is null!"); |
3057 | 0 | PR_PL(("****** In DV::DonePrintingPages PO: %p (%s)\n", aPO, aPO?gFrameTypesStr[aPO->mFrameType]:"")); |
3058 | 0 |
|
3059 | 0 | // If there is a pageSeqFrame, make sure there are no more printCanvas active |
3060 | 0 | // that might call |Notify| on the pagePrintTimer after things are cleaned up |
3061 | 0 | // and printing was marked as being done. |
3062 | 0 | if (mPageSeqFrame.IsAlive()) { |
3063 | 0 | nsIPageSequenceFrame* pageSeqFrame = do_QueryFrame(mPageSeqFrame.GetFrame()); |
3064 | 0 | pageSeqFrame->ResetPrintCanvasList(); |
3065 | 0 | } |
3066 | 0 |
|
3067 | 0 | // Guarantee that mPrt and mPrt->mPrintObject won't be deleted during a |
3068 | 0 | // call of PrintDocContent() and FirePrintCompletionEvent(). |
3069 | 0 | RefPtr<nsPrintData> printData = mPrt; |
3070 | 0 |
|
3071 | 0 | if (aPO && !printData->mIsAborted) { |
3072 | 0 | aPO->mHasBeenPrinted = true; |
3073 | 0 | nsresult rv; |
3074 | 0 | bool didPrint = PrintDocContent(printData->mPrintObject, rv); |
3075 | 0 | if (NS_SUCCEEDED(rv) && didPrint) { |
3076 | 0 | PR_PL(("****** In DV::DonePrintingPages PO: %p (%s) didPrint:%s (Not Done Printing)\n", aPO, gFrameTypesStr[aPO->mFrameType], PRT_YESNO(didPrint))); |
3077 | 0 | return false; |
3078 | 0 | } |
3079 | 0 | } |
3080 | 0 |
|
3081 | 0 | printData->mPrintDC->UnregisterPageDoneCallback(); |
3082 | 0 |
|
3083 | 0 | if (NS_SUCCEEDED(aResult)) { |
3084 | 0 | FirePrintCompletionEvent(); |
3085 | 0 | // XXX mPrt may be cleared or replaced with new instance here. |
3086 | 0 | // However, the following methods will clean up with new mPrt or will |
3087 | 0 | // do nothing due to no proper nsPrintData instance. |
3088 | 0 | } |
3089 | 0 |
|
3090 | 0 | TurnScriptingOn(true); |
3091 | 0 | SetIsPrinting(false); |
3092 | 0 |
|
3093 | 0 | // Release reference to mPagePrintTimer; the timer object destroys itself |
3094 | 0 | // after this returns true |
3095 | 0 | DisconnectPagePrintTimer(); |
3096 | 0 |
|
3097 | 0 | return true; |
3098 | 0 | } |
3099 | | |
3100 | | //------------------------------------------------------- |
3101 | | nsresult |
3102 | | nsPrintJob::EnablePOsForPrinting() |
3103 | 0 | { |
3104 | 0 | // Guarantee that mPrt and the objects it owns won't be deleted. |
3105 | 0 | RefPtr<nsPrintData> printData = mPrt; |
3106 | 0 |
|
3107 | 0 | // NOTE: All POs have been "turned off" for printing |
3108 | 0 | // this is where we decided which POs get printed. |
3109 | 0 |
|
3110 | 0 | if (!printData->mPrintSettings) { |
3111 | 0 | return NS_ERROR_FAILURE; |
3112 | 0 | } |
3113 | 0 | |
3114 | 0 | printData->mPrintFrameType = nsIPrintSettings::kNoFrames; |
3115 | 0 | printData->mPrintSettings->GetPrintFrameType(&printData->mPrintFrameType); |
3116 | 0 |
|
3117 | 0 | int16_t printHowEnable = nsIPrintSettings::kFrameEnableNone; |
3118 | 0 | printData->mPrintSettings->GetHowToEnableFrameUI(&printHowEnable); |
3119 | 0 |
|
3120 | 0 | int16_t printRangeType = nsIPrintSettings::kRangeAllPages; |
3121 | 0 | printData->mPrintSettings->GetPrintRange(&printRangeType); |
3122 | 0 |
|
3123 | 0 | PR_PL(("\n")); |
3124 | 0 | PR_PL(("********* nsPrintJob::EnablePOsForPrinting *********\n")); |
3125 | 0 | PR_PL(("PrintFrameType: %s \n", |
3126 | 0 | gPrintFrameTypeStr[printData->mPrintFrameType])); |
3127 | 0 | PR_PL(("HowToEnableFrameUI: %s \n", gFrameHowToEnableStr[printHowEnable])); |
3128 | 0 | PR_PL(("PrintRange: %s \n", gPrintRangeStr[printRangeType])); |
3129 | 0 | PR_PL(("----\n")); |
3130 | 0 |
|
3131 | 0 | // ***** This is the ultimate override ***** |
3132 | 0 | // if we are printing the selection (either an IFrame or selection range) |
3133 | 0 | // then set the mPrintFrameType as if it were the selected frame |
3134 | 0 | if (printRangeType == nsIPrintSettings::kRangeSelection) { |
3135 | 0 | printData->mPrintFrameType = nsIPrintSettings::kSelectedFrame; |
3136 | 0 | printHowEnable = nsIPrintSettings::kFrameEnableNone; |
3137 | 0 | } |
3138 | 0 |
|
3139 | 0 | // This tells us that the "Frame" UI has turned off, |
3140 | 0 | // so therefore there are no FrameSets/Frames/IFrames to be printed |
3141 | 0 | // |
3142 | 0 | // This means there are not FrameSets, |
3143 | 0 | // but the document could contain an IFrame |
3144 | 0 | if (printHowEnable == nsIPrintSettings::kFrameEnableNone) { |
3145 | 0 | // Print all the pages or a sub range of pages |
3146 | 0 | if (printRangeType == nsIPrintSettings::kRangeAllPages || |
3147 | 0 | printRangeType == nsIPrintSettings::kRangeSpecifiedPageRange) { |
3148 | 0 | SetPrintPO(printData->mPrintObject.get(), true); |
3149 | 0 |
|
3150 | 0 | // Set the children so they are PrinAsIs |
3151 | 0 | // In this case, the children are probably IFrames |
3152 | 0 | if (printData->mPrintObject->mKids.Length() > 0) { |
3153 | 0 | for (const UniquePtr<nsPrintObject>& po : |
3154 | 0 | printData->mPrintObject->mKids) { |
3155 | 0 | NS_ASSERTION(po, "nsPrintObject can't be null!"); |
3156 | 0 | SetPrintAsIs(po.get()); |
3157 | 0 | } |
3158 | 0 |
|
3159 | 0 | // ***** Another override ***** |
3160 | 0 | printData->mPrintFrameType = nsIPrintSettings::kFramesAsIs; |
3161 | 0 | } |
3162 | 0 | PR_PL(("PrintFrameType: %s \n", |
3163 | 0 | gPrintFrameTypeStr[printData->mPrintFrameType])); |
3164 | 0 | PR_PL(("HowToEnableFrameUI: %s \n", |
3165 | 0 | gFrameHowToEnableStr[printHowEnable])); |
3166 | 0 | PR_PL(("PrintRange: %s \n", gPrintRangeStr[printRangeType])); |
3167 | 0 | return NS_OK; |
3168 | 0 | } |
3169 | 0 |
|
3170 | 0 | // This means we are either printed a selected IFrame or |
3171 | 0 | // we are printing the current selection |
3172 | 0 | if (printRangeType == nsIPrintSettings::kRangeSelection) { |
3173 | 0 | // If the currentFocusDOMWin can'r be null if something is selected |
3174 | 0 | if (printData->mCurrentFocusWin) { |
3175 | 0 | // Find the selected IFrame |
3176 | 0 | nsPrintObject* po = |
3177 | 0 | FindPrintObjectByDOMWin(printData->mPrintObject.get(), |
3178 | 0 | printData->mCurrentFocusWin); |
3179 | 0 | if (po) { |
3180 | 0 | // Makes sure all of its children are be printed "AsIs" |
3181 | 0 | SetPrintAsIs(po); |
3182 | 0 |
|
3183 | 0 | // Now, only enable this POs (the selected PO) and all of its children |
3184 | 0 | SetPrintPO(po, true); |
3185 | 0 |
|
3186 | 0 | // check to see if we have a range selection, |
3187 | 0 | // as oppose to a insert selection |
3188 | 0 | // this means if the user just clicked on the IFrame then |
3189 | 0 | // there will not be a selection so we want the entire page to print |
3190 | 0 | // |
3191 | 0 | // XXX this is sort of a hack right here to make the page |
3192 | 0 | // not try to reposition itself when printing selection |
3193 | 0 | nsPIDOMWindowOuter* domWin = |
3194 | 0 | po->mDocument->GetOriginalDocument()->GetWindow(); |
3195 | 0 | if (!IsThereARangeSelection(domWin)) { |
3196 | 0 | printRangeType = nsIPrintSettings::kRangeAllPages; |
3197 | 0 | printData->mPrintSettings->SetPrintRange(printRangeType); |
3198 | 0 | } |
3199 | 0 | PR_PL(("PrintFrameType: %s \n", |
3200 | 0 | gPrintFrameTypeStr[printData->mPrintFrameType])); |
3201 | 0 | PR_PL(("HowToEnableFrameUI: %s \n", |
3202 | 0 | gFrameHowToEnableStr[printHowEnable])); |
3203 | 0 | PR_PL(("PrintRange: %s \n", |
3204 | 0 | gPrintRangeStr[printRangeType])); |
3205 | 0 | return NS_OK; |
3206 | 0 | } |
3207 | 0 | } else { |
3208 | 0 | for (uint32_t i = 0; i < printData->mPrintDocList.Length(); i++) { |
3209 | 0 | nsPrintObject* po = printData->mPrintDocList.ElementAt(i); |
3210 | 0 | NS_ASSERTION(po, "nsPrintObject can't be null!"); |
3211 | 0 | nsCOMPtr<nsPIDOMWindowOuter> domWin = po->mDocShell->GetWindow(); |
3212 | 0 | if (IsThereARangeSelection(domWin)) { |
3213 | 0 | printData->mCurrentFocusWin = domWin.forget(); |
3214 | 0 | SetPrintPO(po, true); |
3215 | 0 | break; |
3216 | 0 | } |
3217 | 0 | } |
3218 | 0 | return NS_OK; |
3219 | 0 | } |
3220 | 0 | } |
3221 | 0 | } |
3222 | 0 |
|
3223 | 0 | // check to see if there is a selection when a FrameSet is present |
3224 | 0 | if (printRangeType == nsIPrintSettings::kRangeSelection) { |
3225 | 0 | // If the currentFocusDOMWin can'r be null if something is selected |
3226 | 0 | if (printData->mCurrentFocusWin) { |
3227 | 0 | // Find the selected IFrame |
3228 | 0 | nsPrintObject* po = |
3229 | 0 | FindPrintObjectByDOMWin(printData->mPrintObject.get(), |
3230 | 0 | printData->mCurrentFocusWin); |
3231 | 0 | if (po) { |
3232 | 0 | // Makes sure all of its children are be printed "AsIs" |
3233 | 0 | SetPrintAsIs(po); |
3234 | 0 |
|
3235 | 0 | // Now, only enable this POs (the selected PO) and all of its children |
3236 | 0 | SetPrintPO(po, true); |
3237 | 0 |
|
3238 | 0 | // check to see if we have a range selection, |
3239 | 0 | // as oppose to a insert selection |
3240 | 0 | // this means if the user just clicked on the IFrame then |
3241 | 0 | // there will not be a selection so we want the entire page to print |
3242 | 0 | // |
3243 | 0 | // XXX this is sort of a hack right here to make the page |
3244 | 0 | // not try to reposition itself when printing selection |
3245 | 0 | nsCOMPtr<nsPIDOMWindowOuter> domWin = po->mDocument->GetOriginalDocument()->GetWindow(); |
3246 | 0 | if (!IsThereARangeSelection(domWin)) { |
3247 | 0 | printRangeType = nsIPrintSettings::kRangeAllPages; |
3248 | 0 | printData->mPrintSettings->SetPrintRange(printRangeType); |
3249 | 0 | } |
3250 | 0 | PR_PL(("PrintFrameType: %s \n", |
3251 | 0 | gPrintFrameTypeStr[printData->mPrintFrameType])); |
3252 | 0 | PR_PL(("HowToEnableFrameUI: %s \n", |
3253 | 0 | gFrameHowToEnableStr[printHowEnable])); |
3254 | 0 | PR_PL(("PrintRange: %s \n", gPrintRangeStr[printRangeType])); |
3255 | 0 | return NS_OK; |
3256 | 0 | } |
3257 | 0 | } |
3258 | 0 | } |
3259 | 0 |
|
3260 | 0 | // If we are printing "AsIs" then sets all the POs to be printed as is |
3261 | 0 | if (printData->mPrintFrameType == nsIPrintSettings::kFramesAsIs) { |
3262 | 0 | SetPrintAsIs(printData->mPrintObject.get()); |
3263 | 0 | SetPrintPO(printData->mPrintObject.get(), true); |
3264 | 0 | return NS_OK; |
3265 | 0 | } |
3266 | 0 | |
3267 | 0 | // If we are printing the selected Frame then |
3268 | 0 | // find that PO for that selected DOMWin and set it all of its |
3269 | 0 | // children to be printed |
3270 | 0 | if (printData->mPrintFrameType == nsIPrintSettings::kSelectedFrame) { |
3271 | 0 | if ((printData->mIsParentAFrameSet && printData->mCurrentFocusWin) || |
3272 | 0 | printData->mIsIFrameSelected) { |
3273 | 0 | nsPrintObject* po = |
3274 | 0 | FindPrintObjectByDOMWin(printData->mPrintObject.get(), |
3275 | 0 | printData->mCurrentFocusWin); |
3276 | 0 | if (po) { |
3277 | 0 | // NOTE: Calling this sets the "po" and |
3278 | 0 | // we don't want to do this for documents that have no children, |
3279 | 0 | // because then the "DoEndPage" gets called and it shouldn't |
3280 | 0 | if (po->mKids.Length() > 0) { |
3281 | 0 | // Makes sure that itself, and all of its children are printed "AsIs" |
3282 | 0 | SetPrintAsIs(po); |
3283 | 0 | } |
3284 | 0 |
|
3285 | 0 | // Now, only enable this POs (the selected PO) and all of its children |
3286 | 0 | SetPrintPO(po, true); |
3287 | 0 | } |
3288 | 0 | } |
3289 | 0 | return NS_OK; |
3290 | 0 | } |
3291 | 0 |
|
3292 | 0 | // If we are print each subdoc separately, |
3293 | 0 | // then don't print any of the FraneSet Docs |
3294 | 0 | if (printData->mPrintFrameType == nsIPrintSettings::kEachFrameSep) { |
3295 | 0 | SetPrintPO(printData->mPrintObject.get(), true); |
3296 | 0 | int32_t cnt = printData->mPrintDocList.Length(); |
3297 | 0 | for (int32_t i=0;i<cnt;i++) { |
3298 | 0 | nsPrintObject* po = printData->mPrintDocList.ElementAt(i); |
3299 | 0 | NS_ASSERTION(po, "nsPrintObject can't be null!"); |
3300 | 0 | if (po->mFrameType == eFrameSet) { |
3301 | 0 | po->mDontPrint = true; |
3302 | 0 | } |
3303 | 0 | } |
3304 | 0 | } |
3305 | 0 |
|
3306 | 0 | return NS_OK; |
3307 | 0 | } |
3308 | | |
3309 | | //------------------------------------------------------- |
3310 | | // Return the nsPrintObject with that is XMost (The widest frameset frame) AND |
3311 | | // contains the XMost (widest) layout frame |
3312 | | nsPrintObject* |
3313 | | nsPrintJob::FindSmallestSTF() |
3314 | 0 | { |
3315 | 0 | float smallestRatio = 1.0f; |
3316 | 0 | nsPrintObject* smallestPO = nullptr; |
3317 | 0 |
|
3318 | 0 | for (uint32_t i=0;i<mPrt->mPrintDocList.Length();i++) { |
3319 | 0 | nsPrintObject* po = mPrt->mPrintDocList.ElementAt(i); |
3320 | 0 | NS_ASSERTION(po, "nsPrintObject can't be null!"); |
3321 | 0 | if (po->mFrameType != eFrameSet && po->mFrameType != eIFrame) { |
3322 | 0 | if (po->mShrinkRatio < smallestRatio) { |
3323 | 0 | smallestRatio = po->mShrinkRatio; |
3324 | 0 | smallestPO = po; |
3325 | 0 | } |
3326 | 0 | } |
3327 | 0 | } |
3328 | 0 |
|
3329 | | #ifdef EXTENDED_DEBUG_PRINTING |
3330 | | if (smallestPO) printf("*PO: %p Type: %d %10.3f\n", smallestPO, smallestPO->mFrameType, smallestPO->mShrinkRatio); |
3331 | | #endif |
3332 | | return smallestPO; |
3333 | 0 | } |
3334 | | |
3335 | | //------------------------------------------------------- |
3336 | | void |
3337 | | nsPrintJob::TurnScriptingOn(bool aDoTurnOn) |
3338 | 0 | { |
3339 | 0 | if (mIsDoingPrinting && aDoTurnOn && mDocViewerPrint && |
3340 | 0 | mDocViewerPrint->GetIsPrintPreview()) { |
3341 | 0 | // We don't want to turn scripting on if print preview is shown still after |
3342 | 0 | // printing. |
3343 | 0 | return; |
3344 | 0 | } |
3345 | 0 | |
3346 | 0 | // The following for loop uses nsPrintObject instances that are owned by |
3347 | 0 | // mPrt or mPrtPreview. Therefore, this method needs to guarantee that |
3348 | 0 | // they won't be deleted in this method. |
3349 | 0 | RefPtr<nsPrintData> printData = mPrt ? mPrt : mPrtPreview; |
3350 | 0 | if (!printData) { |
3351 | 0 | return; |
3352 | 0 | } |
3353 | 0 | |
3354 | 0 | NS_ASSERTION(mDocument, "We MUST have a document."); |
3355 | 0 | // First, get the script global object from the document... |
3356 | 0 |
|
3357 | 0 | for (uint32_t i = 0; i < printData->mPrintDocList.Length(); i++) { |
3358 | 0 | nsPrintObject* po = printData->mPrintDocList.ElementAt(i); |
3359 | 0 | MOZ_ASSERT(po); |
3360 | 0 |
|
3361 | 0 | nsIDocument* doc = po->mDocument; |
3362 | 0 | if (!doc) { |
3363 | 0 | continue; |
3364 | 0 | } |
3365 | 0 | |
3366 | 0 | if (nsCOMPtr<nsPIDOMWindowInner> window = doc->GetInnerWindow()) { |
3367 | 0 | nsCOMPtr<nsIGlobalObject> go = window->AsGlobal(); |
3368 | 0 | NS_WARNING_ASSERTION(go->GetGlobalJSObject(), "Can't get global"); |
3369 | 0 | nsresult propThere = NS_PROPTABLE_PROP_NOT_THERE; |
3370 | 0 | doc->GetProperty(nsGkAtoms::scriptEnabledBeforePrintOrPreview, |
3371 | 0 | &propThere); |
3372 | 0 | if (aDoTurnOn) { |
3373 | 0 | if (propThere != NS_PROPTABLE_PROP_NOT_THERE) { |
3374 | 0 | doc->DeleteProperty(nsGkAtoms::scriptEnabledBeforePrintOrPreview); |
3375 | 0 | if (go->GetGlobalJSObject()) { |
3376 | 0 | xpc::Scriptability::Get(go->GetGlobalJSObject()).Unblock(); |
3377 | 0 | } |
3378 | 0 | window->Resume(); |
3379 | 0 | } |
3380 | 0 | } else { |
3381 | 0 | // Have to be careful, because people call us over and over again with |
3382 | 0 | // aDoTurnOn == false. So don't set the property if it's already |
3383 | 0 | // set, since in that case we'd set it to the wrong value. |
3384 | 0 | if (propThere == NS_PROPTABLE_PROP_NOT_THERE) { |
3385 | 0 | // Stash the current value of IsScriptEnabled on the document, so |
3386 | 0 | // that layout code running in print preview doesn't get confused. |
3387 | 0 | doc->SetProperty(nsGkAtoms::scriptEnabledBeforePrintOrPreview, |
3388 | 0 | NS_INT32_TO_PTR(doc->IsScriptEnabled())); |
3389 | 0 | if (go && go->GetGlobalJSObject()) { |
3390 | 0 | xpc::Scriptability::Get(go->GetGlobalJSObject()).Block(); |
3391 | 0 | } |
3392 | 0 | window->Suspend(); |
3393 | 0 | } |
3394 | 0 | } |
3395 | 0 | } |
3396 | 0 | } |
3397 | 0 | } |
3398 | | |
3399 | | //----------------------------------------------------------------- |
3400 | | //-- Done: Misc Support Methods |
3401 | | //----------------------------------------------------------------- |
3402 | | |
3403 | | |
3404 | | //----------------------------------------------------------------- |
3405 | | //-- Section: Finishing up or Cleaning up |
3406 | | //----------------------------------------------------------------- |
3407 | | |
3408 | | //----------------------------------------------------------------- |
3409 | | void |
3410 | | nsPrintJob::CloseProgressDialog(nsIWebProgressListener* aWebProgressListener) |
3411 | 0 | { |
3412 | 0 | if (aWebProgressListener) { |
3413 | 0 | aWebProgressListener->OnStateChange(nullptr, nullptr, nsIWebProgressListener::STATE_STOP|nsIWebProgressListener::STATE_IS_DOCUMENT, NS_OK); |
3414 | 0 | } |
3415 | 0 | } |
3416 | | |
3417 | | //----------------------------------------------------------------- |
3418 | | nsresult |
3419 | | nsPrintJob::FinishPrintPreview() |
3420 | 0 | { |
3421 | 0 | nsresult rv = NS_OK; |
3422 | 0 |
|
3423 | 0 | #ifdef NS_PRINT_PREVIEW |
3424 | 0 |
|
3425 | 0 | if (!mPrt) { |
3426 | 0 | /* we're already finished with print preview */ |
3427 | 0 | return rv; |
3428 | 0 | } |
3429 | 0 | |
3430 | 0 | rv = DocumentReadyForPrinting(); |
3431 | 0 |
|
3432 | 0 | // Note that this method may be called while the instance is being |
3433 | 0 | // initialized. Some methods which initialize the instance (e.g., |
3434 | 0 | // DoCommonPrint) may need to stop initializing and return error if |
3435 | 0 | // this is called. Therefore it's important to set mIsCreatingPrintPreview |
3436 | 0 | // state to false here. If you need to stop setting that here, you need to |
3437 | 0 | // keep them being able to check whether the owner stopped using this |
3438 | 0 | // instance. |
3439 | 0 | mIsCreatingPrintPreview = false; |
3440 | 0 |
|
3441 | 0 | // mPrt may be cleared during a call of nsPrintData::OnEndPrinting() |
3442 | 0 | // because that method invokes some arbitrary listeners. |
3443 | 0 | RefPtr<nsPrintData> printData = mPrt; |
3444 | 0 | if (NS_FAILED(rv)) { |
3445 | 0 | /* cleanup done, let's fire-up an error dialog to notify the user |
3446 | 0 | * what went wrong... |
3447 | 0 | */ |
3448 | 0 | printData->OnEndPrinting(); |
3449 | 0 | // XXX mPrt may be nullptr here. So, Shouldn't TurnScriptingOn() take |
3450 | 0 | // nsPrintData as an argument? |
3451 | 0 | TurnScriptingOn(true); |
3452 | 0 |
|
3453 | 0 | return rv; |
3454 | 0 | } |
3455 | 0 | |
3456 | 0 | // At this point we are done preparing everything |
3457 | 0 | // before it is to be created |
3458 | 0 | |
3459 | 0 | if (mIsDoingPrintPreview && mOldPrtPreview) { |
3460 | 0 | mOldPrtPreview = nullptr; |
3461 | 0 | } |
3462 | 0 |
|
3463 | 0 | printData->OnEndPrinting(); |
3464 | 0 | // XXX If mPrt becomes nullptr or different instance here, what should we |
3465 | 0 | // do? |
3466 | 0 |
|
3467 | 0 | // PrintPreview was built using the mPrt (code reuse) |
3468 | 0 | // then we assign it over |
3469 | 0 | mPrtPreview = std::move(mPrt); |
3470 | 0 |
|
3471 | 0 | #endif // NS_PRINT_PREVIEW |
3472 | 0 |
|
3473 | 0 | return NS_OK; |
3474 | 0 | } |
3475 | | |
3476 | | //----------------------------------------------------------------- |
3477 | | //-- Done: Finishing up or Cleaning up |
3478 | | //----------------------------------------------------------------- |
3479 | | |
3480 | | |
3481 | | /*=============== Timer Related Code ======================*/ |
3482 | | nsresult |
3483 | | nsPrintJob::StartPagePrintTimer(const UniquePtr<nsPrintObject>& aPO) |
3484 | 0 | { |
3485 | 0 | if (!mPagePrintTimer) { |
3486 | 0 | // Get the delay time in between the printing of each page |
3487 | 0 | // this gives the user more time to press cancel |
3488 | 0 | int32_t printPageDelay = 50; |
3489 | 0 | mPrt->mPrintSettings->GetPrintPageDelay(&printPageDelay); |
3490 | 0 |
|
3491 | 0 | nsCOMPtr<nsIContentViewer> cv = do_QueryInterface(mDocViewerPrint); |
3492 | 0 | NS_ENSURE_TRUE(cv, NS_ERROR_FAILURE); |
3493 | 0 | nsCOMPtr<nsIDocument> doc = cv->GetDocument(); |
3494 | 0 | NS_ENSURE_TRUE(doc, NS_ERROR_FAILURE); |
3495 | 0 |
|
3496 | 0 | RefPtr<nsPagePrintTimer> timer = |
3497 | 0 | new nsPagePrintTimer(this, mDocViewerPrint, doc, printPageDelay); |
3498 | 0 | timer.forget(&mPagePrintTimer); |
3499 | 0 |
|
3500 | 0 | nsCOMPtr<nsIPrintSession> printSession; |
3501 | 0 | nsresult rv = mPrt->mPrintSettings->GetPrintSession(getter_AddRefs(printSession)); |
3502 | 0 | if (NS_SUCCEEDED(rv) && printSession) { |
3503 | 0 | RefPtr<mozilla::layout::RemotePrintJobChild> remotePrintJob; |
3504 | 0 | printSession->GetRemotePrintJob(getter_AddRefs(remotePrintJob)); |
3505 | 0 | if (NS_SUCCEEDED(rv) && remotePrintJob) { |
3506 | 0 | remotePrintJob->SetPagePrintTimer(mPagePrintTimer); |
3507 | 0 | remotePrintJob->SetPrintJob(this); |
3508 | 0 | } |
3509 | 0 | } |
3510 | 0 | } |
3511 | 0 |
|
3512 | 0 | return mPagePrintTimer->Start(aPO.get()); |
3513 | 0 | } |
3514 | | |
3515 | | /*=============== nsIObserver Interface ======================*/ |
3516 | | NS_IMETHODIMP |
3517 | | nsPrintJob::Observe(nsISupports* aSubject, const char* aTopic, const char16_t* aData) |
3518 | 0 | { |
3519 | 0 | // Only process a null topic which means the progress dialog is open. |
3520 | 0 | if (aTopic) { |
3521 | 0 | return NS_OK; |
3522 | 0 | } |
3523 | 0 | |
3524 | 0 | nsresult rv = InitPrintDocConstruction(true); |
3525 | 0 | if (!mIsDoingPrinting && mPrtPreview) { |
3526 | 0 | RefPtr<nsPrintData> printDataOfPrintPreview = mPrtPreview; |
3527 | 0 | printDataOfPrintPreview->OnEndPrinting(); |
3528 | 0 | } |
3529 | 0 |
|
3530 | 0 | return rv; |
3531 | 0 | } |
3532 | | |
3533 | | //--------------------------------------------------------------- |
3534 | | //-- PLEvent Notification |
3535 | | //--------------------------------------------------------------- |
3536 | | class nsPrintCompletionEvent : public Runnable { |
3537 | | public: |
3538 | | explicit nsPrintCompletionEvent(nsIDocumentViewerPrint* docViewerPrint) |
3539 | | : mozilla::Runnable("nsPrintCompletionEvent") |
3540 | | , mDocViewerPrint(docViewerPrint) |
3541 | 0 | { |
3542 | 0 | NS_ASSERTION(mDocViewerPrint, "mDocViewerPrint is null."); |
3543 | 0 | } |
3544 | | |
3545 | 0 | NS_IMETHOD Run() override { |
3546 | 0 | if (mDocViewerPrint) |
3547 | 0 | mDocViewerPrint->OnDonePrinting(); |
3548 | 0 | return NS_OK; |
3549 | 0 | } |
3550 | | |
3551 | | private: |
3552 | | nsCOMPtr<nsIDocumentViewerPrint> mDocViewerPrint; |
3553 | | }; |
3554 | | |
3555 | | //----------------------------------------------------------- |
3556 | | void |
3557 | | nsPrintJob::FirePrintCompletionEvent() |
3558 | 0 | { |
3559 | 0 | MOZ_ASSERT(NS_IsMainThread()); |
3560 | 0 | nsCOMPtr<nsIRunnable> event = new nsPrintCompletionEvent(mDocViewerPrint); |
3561 | 0 | nsCOMPtr<nsIContentViewer> cv = do_QueryInterface(mDocViewerPrint); |
3562 | 0 | NS_ENSURE_TRUE_VOID(cv); |
3563 | 0 | nsCOMPtr<nsIDocument> doc = cv->GetDocument(); |
3564 | 0 | NS_ENSURE_TRUE_VOID(doc); |
3565 | 0 |
|
3566 | 0 | NS_ENSURE_SUCCESS_VOID(doc->Dispatch(TaskCategory::Other, event.forget())); |
3567 | 0 | } |
3568 | | |
3569 | | void |
3570 | | nsPrintJob::DisconnectPagePrintTimer() |
3571 | 0 | { |
3572 | 0 | if (mPagePrintTimer) { |
3573 | 0 | mPagePrintTimer->Disconnect(); |
3574 | 0 | NS_RELEASE(mPagePrintTimer); |
3575 | 0 | } |
3576 | 0 | } |
3577 | | |
3578 | | //--------------------------------------------------------------- |
3579 | | //--------------------------------------------------------------- |
3580 | | //-- Debug helper routines |
3581 | | //--------------------------------------------------------------- |
3582 | | //--------------------------------------------------------------- |
3583 | | #if defined(XP_WIN) && defined(EXTENDED_DEBUG_PRINTING) |
3584 | | #include "windows.h" |
3585 | | #include "process.h" |
3586 | | #include "direct.h" |
3587 | | |
3588 | | #define MY_FINDFIRST(a,b) FindFirstFile(a,b) |
3589 | | #define MY_FINDNEXT(a,b) FindNextFile(a,b) |
3590 | | #define ISDIR(a) (a.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) |
3591 | | #define MY_FINDCLOSE(a) FindClose(a) |
3592 | | #define MY_FILENAME(a) a.cFileName |
3593 | | #define MY_FILESIZE(a) (a.nFileSizeHigh * MAXDWORD) + a.nFileSizeLow |
3594 | | |
3595 | | int RemoveFilesInDir(const char * aDir) |
3596 | | { |
3597 | | WIN32_FIND_DATA data_ptr; |
3598 | | HANDLE find_handle; |
3599 | | |
3600 | | char path[MAX_PATH]; |
3601 | | |
3602 | | strcpy(path, aDir); |
3603 | | |
3604 | | // Append slash to the end of the directory names if not there |
3605 | | if (path[strlen(path)-1] != '\\') |
3606 | | strcat(path, "\\"); |
3607 | | |
3608 | | char findPath[MAX_PATH]; |
3609 | | strcpy(findPath, path); |
3610 | | strcat(findPath, "*.*"); |
3611 | | |
3612 | | find_handle = MY_FINDFIRST(findPath, &data_ptr); |
3613 | | |
3614 | | if (find_handle != INVALID_HANDLE_VALUE) { |
3615 | | do { |
3616 | | if (ISDIR(data_ptr) |
3617 | | && (stricmp(MY_FILENAME(data_ptr),".")) |
3618 | | && (stricmp(MY_FILENAME(data_ptr),".."))) { |
3619 | | // skip |
3620 | | } |
3621 | | else if (!ISDIR(data_ptr)) { |
3622 | | if (!strncmp(MY_FILENAME(data_ptr), "print_dump", 10)) { |
3623 | | char fileName[MAX_PATH]; |
3624 | | strcpy(fileName, aDir); |
3625 | | strcat(fileName, "\\"); |
3626 | | strcat(fileName, MY_FILENAME(data_ptr)); |
3627 | | printf("Removing %s\n", fileName); |
3628 | | remove(fileName); |
3629 | | } |
3630 | | } |
3631 | | } while(MY_FINDNEXT(find_handle,&data_ptr)); |
3632 | | MY_FINDCLOSE(find_handle); |
3633 | | } |
3634 | | return TRUE; |
3635 | | } |
3636 | | #endif |
3637 | | |
3638 | | #ifdef EXTENDED_DEBUG_PRINTING |
3639 | | |
3640 | | /** --------------------------------------------------- |
3641 | | * Dumps Frames for Printing |
3642 | | */ |
3643 | | static void RootFrameList(nsPresContext* aPresContext, FILE* out, |
3644 | | const char* aPrefix) |
3645 | | { |
3646 | | if (!aPresContext || !out) |
3647 | | return; |
3648 | | |
3649 | | nsIPresShell *shell = aPresContext->GetPresShell(); |
3650 | | if (shell) { |
3651 | | nsIFrame* frame = shell->GetRootFrame(); |
3652 | | if (frame) { |
3653 | | frame->List(out, aPrefix); |
3654 | | } |
3655 | | } |
3656 | | } |
3657 | | |
3658 | | /** --------------------------------------------------- |
3659 | | * Dumps Frames for Printing |
3660 | | */ |
3661 | | static void DumpFrames(FILE* out, |
3662 | | nsPresContext* aPresContext, |
3663 | | gfxContext * aRendContext, |
3664 | | nsIFrame * aFrame, |
3665 | | int32_t aLevel) |
3666 | | { |
3667 | | NS_ASSERTION(out, "Pointer is null!"); |
3668 | | NS_ASSERTION(aPresContext, "Pointer is null!"); |
3669 | | NS_ASSERTION(aRendContext, "Pointer is null!"); |
3670 | | NS_ASSERTION(aFrame, "Pointer is null!"); |
3671 | | |
3672 | | nsIFrame* child = aFrame->PrincipalChildList().FirstChild(); |
3673 | | while (child != nullptr) { |
3674 | | for (int32_t i=0;i<aLevel;i++) { |
3675 | | fprintf(out, " "); |
3676 | | } |
3677 | | nsAutoString tmp; |
3678 | | child->GetFrameName(tmp); |
3679 | | fputs(NS_LossyConvertUTF16toASCII(tmp).get(), out); |
3680 | | bool isSelected; |
3681 | | if (child->IsVisibleForPainting()) { |
3682 | | fprintf(out, " %p %s", child, isSelected?"VIS":"UVS"); |
3683 | | nsRect rect = child->GetRect(); |
3684 | | fprintf(out, "[%d,%d,%d,%d] ", rect.x, rect.y, rect.width, rect.height); |
3685 | | fprintf(out, "v: %p ", (void*)child->GetView()); |
3686 | | fprintf(out, "\n"); |
3687 | | DumpFrames(out, aPresContext, aRendContext, child, aLevel+1); |
3688 | | child = child->GetNextSibling(); |
3689 | | } |
3690 | | } |
3691 | | } |
3692 | | |
3693 | | |
3694 | | /** --------------------------------------------------- |
3695 | | * Dumps the Views from the DocShell |
3696 | | */ |
3697 | | static void |
3698 | | DumpViews(nsIDocShell* aDocShell, FILE* out) |
3699 | | { |
3700 | | NS_ASSERTION(aDocShell, "Pointer is null!"); |
3701 | | NS_ASSERTION(out, "Pointer is null!"); |
3702 | | |
3703 | | if (nullptr != aDocShell) { |
3704 | | fprintf(out, "docshell=%p \n", aDocShell); |
3705 | | nsIPresShell* shell = aDocShell->GetPresShell(); |
3706 | | if (shell) { |
3707 | | nsViewManager* vm = shell->GetViewManager(); |
3708 | | if (vm) { |
3709 | | nsView* root = vm->GetRootView(); |
3710 | | if (root) { |
3711 | | root->List(out); |
3712 | | } |
3713 | | } |
3714 | | } |
3715 | | else { |
3716 | | fputs("null pres shell\n", out); |
3717 | | } |
3718 | | |
3719 | | // dump the views of the sub documents |
3720 | | int32_t i, n; |
3721 | | aDocShell->GetChildCount(&n); |
3722 | | for (i = 0; i < n; i++) { |
3723 | | nsCOMPtr<nsIDocShellTreeItem> child; |
3724 | | aDocShell->GetChildAt(i, getter_AddRefs(child)); |
3725 | | nsCOMPtr<nsIDocShell> childAsShell(do_QueryInterface(child)); |
3726 | | if (childAsShell) { |
3727 | | DumpViews(childAsShell, out); |
3728 | | } |
3729 | | } |
3730 | | } |
3731 | | } |
3732 | | |
3733 | | /** --------------------------------------------------- |
3734 | | * Dumps the Views and Frames |
3735 | | */ |
3736 | | void DumpLayoutData(const char* aTitleStr, |
3737 | | const char* aURLStr, |
3738 | | nsPresContext* aPresContext, |
3739 | | nsDeviceContext* aDC, |
3740 | | nsIFrame* aRootFrame, |
3741 | | nsIDocShell* aDocShell, |
3742 | | FILE* aFD = nullptr) |
3743 | | { |
3744 | | if (!MOZ_LOG_TEST(gPrintingLog, DUMP_LAYOUT_LEVEL)) { |
3745 | | return; |
3746 | | } |
3747 | | |
3748 | | if (aPresContext == nullptr || aDC == nullptr) { |
3749 | | return; |
3750 | | } |
3751 | | |
3752 | | #ifdef NS_PRINT_PREVIEW |
3753 | | if (aPresContext->Type() == nsPresContext::eContext_PrintPreview) { |
3754 | | return; |
3755 | | } |
3756 | | #endif |
3757 | | |
3758 | | NS_ASSERTION(aRootFrame, "Pointer is null!"); |
3759 | | NS_ASSERTION(aDocShell, "Pointer is null!"); |
3760 | | |
3761 | | // Dump all the frames and view to a a file |
3762 | | char filename[256]; |
3763 | | sprintf(filename, "print_dump_layout_%d.txt", gDumpLOFileNameCnt++); |
3764 | | FILE * fd = aFD?aFD:fopen(filename, "w"); |
3765 | | if (fd) { |
3766 | | fprintf(fd, "Title: %s\n", aTitleStr?aTitleStr:""); |
3767 | | fprintf(fd, "URL: %s\n", aURLStr?aURLStr:""); |
3768 | | fprintf(fd, "--------------- Frames ----------------\n"); |
3769 | | fprintf(fd, "--------------- Frames ----------------\n"); |
3770 | | //RefPtr<gfxContext> renderingContext = |
3771 | | // aDC->CreateRenderingContext(); |
3772 | | RootFrameList(aPresContext, fd, ""); |
3773 | | //DumpFrames(fd, aPresContext, renderingContext, aRootFrame, 0); |
3774 | | fprintf(fd, "---------------------------------------\n\n"); |
3775 | | fprintf(fd, "--------------- Views From Root Frame----------------\n"); |
3776 | | nsView* v = aRootFrame->GetView(); |
3777 | | if (v) { |
3778 | | v->List(fd); |
3779 | | } else { |
3780 | | printf("View is null!\n"); |
3781 | | } |
3782 | | if (aDocShell) { |
3783 | | fprintf(fd, "--------------- All Views ----------------\n"); |
3784 | | DumpViews(aDocShell, fd); |
3785 | | fprintf(fd, "---------------------------------------\n\n"); |
3786 | | } |
3787 | | if (aFD == nullptr) { |
3788 | | fclose(fd); |
3789 | | } |
3790 | | } |
3791 | | } |
3792 | | |
3793 | | //------------------------------------------------------------- |
3794 | | static void DumpPrintObjectsList(const nsTArray<nsPrintObject*>& aDocList) |
3795 | | { |
3796 | | if (!MOZ_LOG_TEST(gPrintingLog, DUMP_LAYOUT_LEVEL)) { |
3797 | | return; |
3798 | | } |
3799 | | |
3800 | | const char types[][3] = {"DC", "FR", "IF", "FS"}; |
3801 | | PR_PL(("Doc List\n***************************************************\n")); |
3802 | | PR_PL(("T P A H PO DocShell Seq Page Root Page# Rect\n")); |
3803 | | for (nsPrintObject* po : aDocList) { |
3804 | | NS_ASSERTION(po, "nsPrintObject can't be null!"); |
3805 | | nsIFrame* rootFrame = nullptr; |
3806 | | if (po->mPresShell) { |
3807 | | rootFrame = po->mPresShell->GetRootFrame(); |
3808 | | while (rootFrame != nullptr) { |
3809 | | nsIPageSequenceFrame * sqf = do_QueryFrame(rootFrame); |
3810 | | if (sqf) { |
3811 | | break; |
3812 | | } |
3813 | | rootFrame = rootFrame->PrincipalChildList().FirstChild(); |
3814 | | } |
3815 | | } |
3816 | | |
3817 | | PR_PL(("%s %d %d %d %p %p %p\n", types[po->mFrameType], |
3818 | | po->IsPrintable(), po->mPrintAsIs, po->mHasBeenPrinted, po, |
3819 | | po->mDocShell.get(), rootFrame)); |
3820 | | } |
3821 | | } |
3822 | | |
3823 | | //------------------------------------------------------------- |
3824 | | static void DumpPrintObjectsTree(nsPrintObject * aPO, int aLevel, FILE* aFD) |
3825 | | { |
3826 | | if (!MOZ_LOG_TEST(gPrintingLog, DUMP_LAYOUT_LEVEL)) { |
3827 | | return; |
3828 | | } |
3829 | | |
3830 | | NS_ASSERTION(aPO, "Pointer is null!"); |
3831 | | |
3832 | | FILE * fd = aFD?aFD:stdout; |
3833 | | const char types[][3] = {"DC", "FR", "IF", "FS"}; |
3834 | | if (aLevel == 0) { |
3835 | | fprintf(fd, "DocTree\n***************************************************\n"); |
3836 | | fprintf(fd, "T PO DocShell Seq Page Page# Rect\n"); |
3837 | | } |
3838 | | for (const auto& po : aPO->mKids) { |
3839 | | NS_ASSERTION(po, "nsPrintObject can't be null!"); |
3840 | | for (int32_t k=0;k<aLevel;k++) fprintf(fd, " "); |
3841 | | fprintf(fd, "%s %p %p\n", types[po->mFrameType], po.get(), |
3842 | | po->mDocShell.get()); |
3843 | | } |
3844 | | } |
3845 | | |
3846 | | //------------------------------------------------------------- |
3847 | | static void GetDocTitleAndURL(const UniquePtr<nsPrintObject>& aPO, |
3848 | | nsACString& aDocStr, |
3849 | | nsACString& aURLStr) |
3850 | | { |
3851 | | nsAutoString docTitleStr; |
3852 | | nsAutoString docURLStr; |
3853 | | GetDocumentTitleAndURL(aPO->mDocument, docTitleStr, docURLStr); |
3854 | | aDocStr = NS_ConvertUTF16toUTF8(docTitleStr); |
3855 | | aURLStr = NS_ConvertUTF16toUTF8(docURLStr); |
3856 | | } |
3857 | | |
3858 | | //------------------------------------------------------------- |
3859 | | static void DumpPrintObjectsTreeLayout(const UniquePtr<nsPrintObject>& aPO, |
3860 | | nsDeviceContext * aDC, |
3861 | | int aLevel, FILE * aFD) |
3862 | | { |
3863 | | if (!MOZ_LOG_TEST(gPrintingLog, DUMP_LAYOUT_LEVEL)) { |
3864 | | return; |
3865 | | } |
3866 | | |
3867 | | NS_ASSERTION(aPO, "Pointer is null!"); |
3868 | | NS_ASSERTION(aDC, "Pointer is null!"); |
3869 | | |
3870 | | const char types[][3] = {"DC", "FR", "IF", "FS"}; |
3871 | | FILE * fd = nullptr; |
3872 | | if (aLevel == 0) { |
3873 | | fd = fopen("tree_layout.txt", "w"); |
3874 | | fprintf(fd, "DocTree\n***************************************************\n"); |
3875 | | fprintf(fd, "***************************************************\n"); |
3876 | | fprintf(fd, "T PO DocShell Seq Page Page# Rect\n"); |
3877 | | } else { |
3878 | | fd = aFD; |
3879 | | } |
3880 | | if (fd) { |
3881 | | nsIFrame* rootFrame = nullptr; |
3882 | | if (aPO->mPresShell) { |
3883 | | rootFrame = aPO->mPresShell->GetRootFrame(); |
3884 | | } |
3885 | | for (int32_t k=0;k<aLevel;k++) fprintf(fd, " "); |
3886 | | fprintf(fd, "%s %p %p\n", types[aPO->mFrameType], aPO.get(), |
3887 | | aPO->mDocShell.get()); |
3888 | | if (aPO->IsPrintable()) { |
3889 | | nsAutoCString docStr; |
3890 | | nsAutoCString urlStr; |
3891 | | GetDocTitleAndURL(aPO, docStr, urlStr); |
3892 | | DumpLayoutData(docStr.get(), urlStr.get(), aPO->mPresContext, aDC, rootFrame, aPO->mDocShell, fd); |
3893 | | } |
3894 | | fprintf(fd, "<***************************************************>\n"); |
3895 | | |
3896 | | for (const auto& po : aPO->mKids) { |
3897 | | NS_ASSERTION(po, "nsPrintObject can't be null!"); |
3898 | | DumpPrintObjectsTreeLayout(po, aDC, aLevel+1, fd); |
3899 | | } |
3900 | | } |
3901 | | if (aLevel == 0 && fd) { |
3902 | | fclose(fd); |
3903 | | } |
3904 | | } |
3905 | | |
3906 | | //------------------------------------------------------------- |
3907 | | static void DumpPrintObjectsListStart(const char * aStr, |
3908 | | const nsTArray<nsPrintObject*>& aDocList) |
3909 | | { |
3910 | | if (!MOZ_LOG_TEST(gPrintingLog, DUMP_LAYOUT_LEVEL)) { |
3911 | | return; |
3912 | | } |
3913 | | |
3914 | | NS_ASSERTION(aStr, "Pointer is null!"); |
3915 | | |
3916 | | PR_PL(("%s\n", aStr)); |
3917 | | DumpPrintObjectsList(aDocList); |
3918 | | } |
3919 | | |
3920 | | #endif |
3921 | | |
3922 | | //--------------------------------------------------------------- |
3923 | | //--------------------------------------------------------------- |
3924 | | //-- End of debug helper routines |
3925 | | //--------------------------------------------------------------- |