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