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/. */
6 #include "nsPrintEngine.h"
8 #include "nsIStringBundle.h"
9 #include "nsReadableUtils.h"
12 #include "mozilla/AsyncEventDispatcher.h"
13 #include "mozilla/dom/Selection.h"
14 #include "nsIScriptGlobalObject.h"
15 #include "nsPIDOMWindow.h"
16 #include "nsIDocShell.h"
19 #include "nsITextToSubURI.h"
26 #include "nsIPrintSettings.h"
27 #include "nsIPrintSettingsService.h"
28 #include "nsIPrintOptions.h"
29 #include "nsIPrintSession.h"
30 #include "nsGfxCIID.h"
31 #include "nsIServiceManager.h"
32 #include "nsGkAtoms.h"
34 #include "nsISupportsPrimitives.h"
36 static const char sPrintSettingsServiceContractID
[] = "@mozilla.org/gfx/printsettings-service;1";
39 #include "nsPrintPreviewListener.h"
40 #include "nsThreadUtils.h"
43 #include "nsIWebBrowserPrint.h"
44 #include "nsIDOMHTMLFrameElement.h"
45 #include "nsIDOMHTMLFrameSetElement.h"
46 #include "nsIDOMHTMLIFrameElement.h"
47 #include "nsIDOMHTMLObjectElement.h"
48 #include "nsIDOMHTMLEmbedElement.h"
51 #include "imgIContainer.h" // image animation mode constants
52 #include "nsIWebBrowserPrint.h" // needed for PrintPreview Navigation constants
55 #include "nsIPrintProgress.h"
56 #include "nsIPrintProgressParams.h"
57 #include "nsIObserver.h"
60 #include "nsIPrompt.h"
61 #include "nsIWindowWatcher.h"
64 #include "nsIPrintingPromptService.h"
65 static const char kPrintingPromptService
[] = "@mozilla.org/embedcomp/printingprompt-service;1";
68 #include "nsPagePrintTimer.h"
71 #include "nsIDocument.h"
74 #include "nsISelectionController.h"
77 #include "nsISupportsUtils.h"
78 #include "nsIScriptContext.h"
79 #include "nsIDOMDocument.h"
80 #include "nsISelectionListener.h"
81 #include "nsISelectionPrivate.h"
82 #include "nsIDOMRange.h"
83 #include "nsContentCID.h"
84 #include "nsLayoutCID.h"
85 #include "nsContentUtils.h"
86 #include "nsIPresShell.h"
87 #include "nsLayoutUtils.h"
88 #include "mozilla/Preferences.h"
90 #include "nsWidgetsCID.h"
91 #include "nsIDeviceContextSpec.h"
92 #include "nsViewManager.h"
94 #include "nsRenderingContext.h"
96 #include "nsIPageSequenceFrame.h"
98 #include "nsIContentViewerEdit.h"
99 #include "nsIContentViewerFile.h"
100 #include "nsIInterfaceRequestor.h"
101 #include "nsIInterfaceRequestorUtils.h"
102 #include "nsIDocShellTreeOwner.h"
103 #include "nsIWebBrowserChrome.h"
104 #include "nsIBaseWindow.h"
105 #include "nsILayoutHistoryState.h"
106 #include "nsFrameManager.h"
107 #include "nsHTMLReflowState.h"
108 #include "nsIDOMHTMLAnchorElement.h"
109 #include "nsIDOMHTMLAreaElement.h"
110 #include "nsIDOMHTMLLinkElement.h"
111 #include "nsIDOMHTMLImageElement.h"
112 #include "nsIContentViewerContainer.h"
113 #include "nsIContentViewer.h"
114 #include "nsIDocumentViewerPrint.h"
116 #include "nsFocusManager.h"
118 #include "nsCDefaultURIFixup.h"
119 #include "nsIURIFixup.h"
120 #include "mozilla/dom/Element.h"
121 #include "nsContentList.h"
122 #include "nsIChannel.h"
123 #include "xpcpublic.h"
125 using namespace mozilla
;
126 using namespace mozilla::dom
;
128 //-----------------------------------------------------
131 #define FORCE_PR_LOG /* Allow logging in the release build */
139 // PR_LOGGING is force to always be on (even in release builds)
140 // but we only want some of it on,
141 //#define EXTENDED_DEBUG_PRINTING
144 #define DUMP_LAYOUT_LEVEL 9 // this turns on the dumping of each doucment's layout info
147 static PRLogModuleInfo
*
150 static PRLogModuleInfo
*sLog
;
152 sLog
= PR_NewLogModule("printing");
155 #define PR_PL(_p1) PR_LOG(GetPrintingLog(), PR_LOG_DEBUG, _p1);
158 #ifdef EXTENDED_DEBUG_PRINTING
159 static uint32_t gDumpFileNameCnt
= 0;
160 static uint32_t gDumpLOFileNameCnt
= 0;
163 #define PRT_YESNO(_p) ((_p)?"YES":"NO")
164 static const char * gFrameTypesStr
[] = {"eDoc", "eFrame", "eIFrame", "eFrameSet"};
165 static const char * gPrintFrameTypeStr
[] = {"kNoFrames", "kFramesAsIs", "kSelectedFrame", "kEachFrameSep"};
166 static const char * gFrameHowToEnableStr
[] = {"kFrameEnableNone", "kFrameEnableAll", "kFrameEnableAsIsAndEach"};
167 static const char * gPrintRangeStr
[] = {"kRangeAllPages", "kRangeSpecifiedPageRange", "kRangeSelection", "kRangeFocusFrame"};
169 #define PRT_YESNO(_p)
173 #ifdef EXTENDED_DEBUG_PRINTING
174 // Forward Declarations
175 static void DumpPrintObjectsListStart(const char * aStr
, nsTArray
<nsPrintObject
*> * aDocList
);
176 static void DumpPrintObjectsTree(nsPrintObject
* aPO
, int aLevel
= 0, FILE* aFD
= nullptr);
177 static void DumpPrintObjectsTreeLayout(nsPrintObject
* aPO
,nsDeviceContext
* aDC
, int aLevel
= 0, FILE * aFD
= nullptr);
179 #define DUMP_DOC_LIST(_title) DumpPrintObjectsListStart((_title), mPrt->mPrintDocList);
180 #define DUMP_DOC_TREE DumpPrintObjectsTree(mPrt->mPrintObject);
181 #define DUMP_DOC_TREELAYOUT DumpPrintObjectsTreeLayout(mPrt->mPrintObject, mPrt->mPrintDC);
183 #define DUMP_DOC_LIST(_title)
184 #define DUMP_DOC_TREE
185 #define DUMP_DOC_TREELAYOUT
188 class nsScriptSuppressor
191 explicit nsScriptSuppressor(nsPrintEngine
* aPrintEngine
)
192 : mPrintEngine(aPrintEngine
), mSuppressed(false) {}
194 ~nsScriptSuppressor() { Unsuppress(); }
200 mPrintEngine
->TurnScriptingOn(false);
206 if (mPrintEngine
&& mSuppressed
) {
207 mPrintEngine
->TurnScriptingOn(true);
212 void Disconnect() { mPrintEngine
= nullptr; }
214 nsRefPtr
<nsPrintEngine
> mPrintEngine
;
218 NS_IMPL_ISUPPORTS(nsPrintEngine
, nsIWebProgressListener
,
219 nsISupportsWeakReference
, nsIObserver
)
221 //---------------------------------------------------
222 //-- nsPrintEngine Class Impl
223 //---------------------------------------------------
224 nsPrintEngine::nsPrintEngine() :
225 mIsCreatingPrintPreview(false),
226 mIsDoingPrinting(false),
227 mIsDoingPrintPreview(false),
228 mProgressDialogIsShown(false),
231 mPagePrintTimer(nullptr),
232 mPageSeqFrame(nullptr),
233 mPrtPreview(nullptr),
234 mOldPrtPreview(nullptr),
237 mDidLoadDataForPrinting(false),
238 mIsDestroying(false),
239 mDisallowSelectionPrint(false),
240 mNoMarginBoxes(false)
244 //-------------------------------------------------------
245 nsPrintEngine::~nsPrintEngine()
247 Destroy(); // for insurance
250 //-------------------------------------------------------
251 void nsPrintEngine::Destroy()
256 mIsDestroying
= true;
263 #ifdef NS_PRINT_PREVIEW
266 mPrtPreview
= nullptr;
270 if (mOldPrtPreview
) {
271 delete mOldPrtPreview
;
272 mOldPrtPreview
= nullptr;
276 mDocViewerPrint
= nullptr;
279 //-------------------------------------------------------
280 void nsPrintEngine::DestroyPrintingData()
283 nsPrintData
* data
= mPrt
;
289 //---------------------------------------------------------------------------------
290 //-- Section: Methods needed by the DocViewer
291 //---------------------------------------------------------------------------------
293 //--------------------------------------------------------
294 nsresult
nsPrintEngine::Initialize(nsIDocumentViewerPrint
* aDocViewerPrint
,
295 nsIDocShell
* aContainer
,
296 nsIDocument
* aDocument
,
300 NS_ENSURE_ARG_POINTER(aDocViewerPrint
);
301 NS_ENSURE_ARG_POINTER(aContainer
);
302 NS_ENSURE_ARG_POINTER(aDocument
);
304 mDocViewerPrint
= aDocViewerPrint
;
305 mContainer
= do_GetWeakReference(aContainer
);
306 mDocument
= aDocument
;
307 mScreenDPI
= aScreenDPI
;
309 mDebugFile
= aDebugFile
; // ok to be nullptr
314 //-------------------------------------------------------
316 nsPrintEngine::CheckBeforeDestroy()
318 if (mPrt
&& mPrt
->mPreparingForPrint
) {
319 mPrt
->mDocWasToBeDestroyed
= true;
325 //-------------------------------------------------------
327 nsPrintEngine::Cancelled()
329 if (mPrt
&& mPrt
->mPrintSettings
) {
330 return mPrt
->mPrintSettings
->SetIsCancelled(true);
332 return NS_ERROR_FAILURE
;
335 //-------------------------------------------------------
336 // Install our event listeners on the document to prevent
337 // some events from being processed while in PrintPreview
339 // No return code - if this fails, there isn't much we can do
341 nsPrintEngine::InstallPrintPreviewListener()
343 if (!mPrt
->mPPEventListeners
) {
344 nsCOMPtr
<nsIDocShell
> docShell
= do_QueryReferent(mContainer
);
349 nsCOMPtr
<nsPIDOMWindow
> win(docShell
->GetWindow());
351 nsCOMPtr
<EventTarget
> target
= win
->GetFrameElementInternal();
352 mPrt
->mPPEventListeners
= new nsPrintPreviewListener(target
);
353 mPrt
->mPPEventListeners
->AddListeners();
358 //----------------------------------------------------------------------
360 nsPrintEngine::GetSeqFrameAndCountPagesInternal(nsPrintObject
* aPO
,
361 nsIFrame
*& aSeqFrame
,
364 NS_ENSURE_ARG_POINTER(aPO
);
366 // Finds the SimplePageSequencer frame
367 nsIPageSequenceFrame
* seqFrame
= aPO
->mPresShell
->GetPageSequenceFrame();
368 aSeqFrame
= do_QueryFrame(seqFrame
);
370 return NS_ERROR_FAILURE
;
373 // first count the total number of pages
375 nsIFrame
* pageFrame
= aSeqFrame
->GetFirstPrincipalChild();
376 while (pageFrame
!= nullptr) {
378 pageFrame
= pageFrame
->GetNextSibling();
385 //-----------------------------------------------------------------
386 nsresult
nsPrintEngine::GetSeqFrameAndCountPages(nsIFrame
*& aSeqFrame
, int32_t& aCount
)
388 NS_ASSERTION(mPrtPreview
, "mPrtPreview can't be null!");
389 return GetSeqFrameAndCountPagesInternal(mPrtPreview
->mPrintObject
, aSeqFrame
, aCount
);
391 //---------------------------------------------------------------------------------
392 //-- Done: Methods needed by the DocViewer
393 //---------------------------------------------------------------------------------
396 //---------------------------------------------------------------------------------
397 //-- Section: nsIWebBrowserPrint
398 //---------------------------------------------------------------------------------
400 // Foward decl for Debug Helper Functions
401 #ifdef EXTENDED_DEBUG_PRINTING
402 static int RemoveFilesInDir(const char * aDir
);
403 static void GetDocTitleAndURL(nsPrintObject
* aPO
, char *& aDocStr
, char *& aURLStr
);
404 static void DumpPrintObjectsTree(nsPrintObject
* aPO
, int aLevel
, FILE* aFD
);
405 static void DumpPrintObjectsList(nsTArray
<nsPrintObject
*> * aDocList
);
406 static void RootFrameList(nsPresContext
* aPresContext
, FILE* out
, int32_t aIndent
);
407 static void DumpViews(nsIDocShell
* aDocShell
, FILE* out
);
408 static void DumpLayoutData(char* aTitleStr
, char* aURLStr
,
409 nsPresContext
* aPresContext
,
410 nsDeviceContext
* aDC
, nsIFrame
* aRootFrame
,
411 nsIDocShell
* aDocShell
, FILE* aFD
);
414 //--------------------------------------------------------------------------------
417 nsPrintEngine::CommonPrint(bool aIsPrintPreview
,
418 nsIPrintSettings
* aPrintSettings
,
419 nsIWebProgressListener
* aWebProgressListener
,
420 nsIDOMDocument
* aDoc
) {
421 nsRefPtr
<nsPrintEngine
> kungfuDeathGrip
= this;
422 nsresult rv
= DoCommonPrint(aIsPrintPreview
, aPrintSettings
,
423 aWebProgressListener
, aDoc
);
425 if (aIsPrintPreview
) {
426 SetIsCreatingPrintPreview(false);
427 SetIsPrintPreview(false);
429 SetIsPrinting(false);
431 if (mProgressDialogIsShown
)
432 CloseProgressDialog(aWebProgressListener
);
433 if (rv
!= NS_ERROR_ABORT
&& rv
!= NS_ERROR_OUT_OF_MEMORY
)
434 ShowPrintErrorDialog(rv
, !aIsPrintPreview
);
443 nsPrintEngine::DoCommonPrint(bool aIsPrintPreview
,
444 nsIPrintSettings
* aPrintSettings
,
445 nsIWebProgressListener
* aWebProgressListener
,
446 nsIDOMDocument
* aDoc
)
450 if (aIsPrintPreview
) {
451 // The WebProgressListener can be QI'ed to nsIPrintingPromptService
452 // then that means the progress dialog is already being shown.
453 nsCOMPtr
<nsIPrintingPromptService
> pps(do_QueryInterface(aWebProgressListener
));
454 mProgressDialogIsShown
= pps
!= nullptr;
456 if (mIsDoingPrintPreview
) {
457 mOldPrtPreview
= mPrtPreview
;
458 mPrtPreview
= nullptr;
461 mProgressDialogIsShown
= false;
464 mPrt
= new nsPrintData(aIsPrintPreview
? nsPrintData::eIsPrintPreview
:
465 nsPrintData::eIsPrinting
);
466 NS_ENSURE_TRUE(mPrt
, NS_ERROR_OUT_OF_MEMORY
);
468 // if they don't pass in a PrintSettings, then get the Global PS
469 mPrt
->mPrintSettings
= aPrintSettings
;
470 if (!mPrt
->mPrintSettings
) {
471 rv
= GetGlobalPrintSettings(getter_AddRefs(mPrt
->mPrintSettings
));
472 NS_ENSURE_SUCCESS(rv
, rv
);
475 rv
= CheckForPrinters(mPrt
->mPrintSettings
);
476 NS_ENSURE_SUCCESS(rv
, rv
);
478 mPrt
->mPrintSettings
->SetIsCancelled(false);
479 mPrt
->mPrintSettings
->GetShrinkToFit(&mPrt
->mShrinkToFit
);
481 // In the case the margin boxes are not printed store the print settings for
482 // the footer/header to be used as default print setting for follow up prints.
483 mPrt
->mPrintSettings
->SetPersistMarginBoxSettings(!mNoMarginBoxes
);
485 if (mNoMarginBoxes
) {
486 // Set the footer/header to blank.
487 const char16_t
* emptyString
= EmptyString().get();
488 mPrt
->mPrintSettings
->SetHeaderStrLeft(emptyString
);
489 mPrt
->mPrintSettings
->SetHeaderStrCenter(emptyString
);
490 mPrt
->mPrintSettings
->SetHeaderStrRight(emptyString
);
491 mPrt
->mPrintSettings
->SetFooterStrLeft(emptyString
);
492 mPrt
->mPrintSettings
->SetFooterStrCenter(emptyString
);
493 mPrt
->mPrintSettings
->SetFooterStrRight(emptyString
);
496 if (aIsPrintPreview
) {
497 SetIsCreatingPrintPreview(true);
498 SetIsPrintPreview(true);
499 nsCOMPtr
<nsIContentViewer
> viewer
=
500 do_QueryInterface(mDocViewerPrint
);
502 viewer
->SetTextZoom(1.0f
);
503 viewer
->SetFullZoom(1.0f
);
504 viewer
->SetMinFontSize(0);
508 // Create a print session and let the print settings know about it.
509 // The print settings hold an nsWeakPtr to the session so it does not
510 // need to be cleared from the settings at the end of the job.
511 // XXX What lifetime does the printSession need to have?
512 nsCOMPtr
<nsIPrintSession
> printSession
;
513 if (!aIsPrintPreview
) {
514 printSession
= do_CreateInstance("@mozilla.org/gfx/printsession;1", &rv
);
515 NS_ENSURE_SUCCESS(rv
, rv
);
516 mPrt
->mPrintSettings
->SetPrintSession(printSession
);
519 if (aWebProgressListener
!= nullptr) {
520 mPrt
->mPrintProgressListeners
.AppendObject(aWebProgressListener
);
523 // Get the currently focused window and cache it
524 // because the Print Dialog will "steal" focus and later when you try
525 // to get the currently focused windows it will be nullptr
526 mPrt
->mCurrentFocusWin
= FindFocusedDOMWindow();
528 // Check to see if there is a "regular" selection
529 bool isSelection
= IsThereARangeSelection(mPrt
->mCurrentFocusWin
);
531 // Get the docshell for this documentviewer
532 nsCOMPtr
<nsIDocShell
> webContainer(do_QueryReferent(mContainer
, &rv
));
533 NS_ENSURE_SUCCESS(rv
, rv
);
536 if (aIsPrintPreview
) {
537 nsCOMPtr
<nsIContentViewer
> viewer
;
538 webContainer
->GetContentViewer(getter_AddRefs(viewer
));
539 if (viewer
&& viewer
->GetDocument() && viewer
->GetDocument()->IsShowing()) {
540 viewer
->GetDocument()->OnPageHide(false, nullptr);
544 nsAutoScriptBlocker scriptBlocker
;
545 mPrt
->mPrintObject
= new nsPrintObject();
546 NS_ENSURE_TRUE(mPrt
->mPrintObject
, NS_ERROR_OUT_OF_MEMORY
);
547 rv
= mPrt
->mPrintObject
->Init(webContainer
, aDoc
, aIsPrintPreview
);
548 NS_ENSURE_SUCCESS(rv
, rv
);
550 NS_ENSURE_TRUE(mPrt
->mPrintDocList
.AppendElement(mPrt
->mPrintObject
),
551 NS_ERROR_OUT_OF_MEMORY
);
553 mPrt
->mIsParentAFrameSet
= IsParentAFrameSet(webContainer
);
554 mPrt
->mPrintObject
->mFrameType
= mPrt
->mIsParentAFrameSet
? eFrameSet
: eDoc
;
556 // Build the "tree" of PrintObjects
557 BuildDocTree(mPrt
->mPrintObject
->mDocShell
, &mPrt
->mPrintDocList
,
561 if (!aIsPrintPreview
) {
565 // XXX This isn't really correct...
566 if (!mPrt
->mPrintObject
->mDocument
||
567 !mPrt
->mPrintObject
->mDocument
->GetRootElement())
568 return NS_ERROR_GFX_PRINTER_STARTDOC
;
570 // Create the linkage from the sub-docs back to the content element
571 // in the parent document
572 MapContentToWebShells(mPrt
->mPrintObject
, mPrt
->mPrintObject
);
574 mPrt
->mIsIFrameSelected
= IsThereAnIFrameSelected(webContainer
, mPrt
->mCurrentFocusWin
, mPrt
->mIsParentAFrameSet
);
576 // Setup print options for UI
577 if (mPrt
->mIsParentAFrameSet
) {
578 if (mPrt
->mCurrentFocusWin
) {
579 mPrt
->mPrintSettings
->SetHowToEnableFrameUI(nsIPrintSettings::kFrameEnableAll
);
581 mPrt
->mPrintSettings
->SetHowToEnableFrameUI(nsIPrintSettings::kFrameEnableAsIsAndEach
);
584 mPrt
->mPrintSettings
->SetHowToEnableFrameUI(nsIPrintSettings::kFrameEnableNone
);
586 // Now determine how to set up the Frame print UI
587 mPrt
->mPrintSettings
->SetPrintOptions(nsIPrintSettings::kEnableSelectionRB
,
588 isSelection
|| mPrt
->mIsIFrameSelected
);
590 nsCOMPtr
<nsIDeviceContextSpec
> devspec
591 (do_CreateInstance("@mozilla.org/gfx/devicecontextspec;1", &rv
));
592 NS_ENSURE_SUCCESS(rv
, rv
);
594 nsScriptSuppressor
scriptSuppressor(this);
595 if (!aIsPrintPreview
) {
597 mPrt
->mDebugFilePtr
= mDebugFile
;
600 scriptSuppressor
.Suppress();
602 mPrt
->mPrintSettings
->GetPrintSilent(&printSilently
);
604 // Check prefs for a default setting as to whether we should print silently
606 Preferences::GetBool("print.always_print_silent", printSilently
);
608 // Ask dialog to be Print Shown via the Plugable Printing Dialog Service
609 // This service is for the Print Dialog and the Print Progress Dialog
610 // If printing silently or you can't get the service continue on
611 if (!printSilently
) {
612 nsCOMPtr
<nsIPrintingPromptService
> printPromptService(do_GetService(kPrintingPromptService
));
613 if (printPromptService
) {
614 nsIDOMWindow
*domWin
= mDocument
->GetWindow();
615 NS_ENSURE_TRUE(domWin
, NS_ERROR_FAILURE
);
617 // Platforms not implementing a given dialog for the service may
618 // return NS_ERROR_NOT_IMPLEMENTED or an error code.
620 // NS_ERROR_NOT_IMPLEMENTED indicates they want default behavior
621 // Any other error code means we must bail out
623 nsCOMPtr
<nsIWebBrowserPrint
> wbp(do_QueryInterface(mDocViewerPrint
));
624 rv
= printPromptService
->ShowPrintDialog(domWin
, wbp
,
625 mPrt
->mPrintSettings
);
627 // ShowPrintDialog triggers an event loop which means we can't assume
628 // that the state of this->{anything} matches the state we've checked
629 // above. Including that a given {thing} is non null.
631 return NS_ERROR_FAILURE
;
634 if (NS_SUCCEEDED(rv
)) {
635 // since we got the dialog and it worked then make sure we
636 // are telling GFX we want to print silent
637 printSilently
= true;
639 if (mPrt
->mPrintSettings
) {
640 // The user might have changed shrink-to-fit in the print dialog, so update our copy of its state
641 mPrt
->mPrintSettings
->GetShrinkToFit(&mPrt
->mShrinkToFit
);
643 } else if (rv
== NS_ERROR_NOT_IMPLEMENTED
) {
644 // This means the Dialog service was there,
645 // but they choose not to implement this dialog and
646 // are looking for default behavior from the toolkit
650 // No dialog service available
651 rv
= NS_ERROR_NOT_IMPLEMENTED
;
654 // Call any code that requires a run of the event loop.
655 rv
= mPrt
->mPrintSettings
->SetupSilentPrinting();
657 // Check explicitly for abort because it's expected
658 if (rv
== NS_ERROR_ABORT
)
660 NS_ENSURE_SUCCESS(rv
, rv
);
663 rv
= devspec
->Init(nullptr, mPrt
->mPrintSettings
, aIsPrintPreview
);
664 NS_ENSURE_SUCCESS(rv
, rv
);
666 mPrt
->mPrintDC
= new nsDeviceContext();
667 rv
= mPrt
->mPrintDC
->InitForPrinting(devspec
);
668 NS_ENSURE_SUCCESS(rv
, rv
);
670 if (aIsPrintPreview
) {
671 mPrt
->mPrintSettings
->SetPrintFrameType(nsIPrintSettings::kFramesAsIs
);
673 // override any UI that wants to PrintPreview any selection or page range
674 // we want to view every page in PrintPreview each time
675 mPrt
->mPrintSettings
->SetPrintRange(nsIPrintSettings::kRangeAllPages
);
677 // Always check and set the print settings first and then fall back
678 // onto the PrintService if there isn't a PrintSettings
680 // Posiible Usage values:
681 // nsIPrintSettings::kUseInternalDefault
682 // nsIPrintSettings::kUseSettingWhenPossible
684 // NOTE: The consts are the same for PrintSettings and PrintSettings
685 int16_t printFrameTypeUsage
= nsIPrintSettings::kUseSettingWhenPossible
;
686 mPrt
->mPrintSettings
->GetPrintFrameTypeUsage(&printFrameTypeUsage
);
688 // Ok, see if we are going to use our value and override the default
689 if (printFrameTypeUsage
== nsIPrintSettings::kUseSettingWhenPossible
) {
690 // Get the Print Options/Settings PrintFrameType to see what is preferred
691 int16_t printFrameType
= nsIPrintSettings::kEachFrameSep
;
692 mPrt
->mPrintSettings
->GetPrintFrameType(&printFrameType
);
694 // Don't let anybody do something stupid like try to set it to
695 // kNoFrames when we are printing a FrameSet
696 if (printFrameType
== nsIPrintSettings::kNoFrames
) {
697 mPrt
->mPrintFrameType
= nsIPrintSettings::kEachFrameSep
;
698 mPrt
->mPrintSettings
->SetPrintFrameType(mPrt
->mPrintFrameType
);
700 // First find out from the PrinService what options are available
701 // to us for Printing FrameSets
702 int16_t howToEnableFrameUI
;
703 mPrt
->mPrintSettings
->GetHowToEnableFrameUI(&howToEnableFrameUI
);
704 if (howToEnableFrameUI
!= nsIPrintSettings::kFrameEnableNone
) {
705 switch (howToEnableFrameUI
) {
706 case nsIPrintSettings::kFrameEnableAll
:
707 mPrt
->mPrintFrameType
= printFrameType
;
710 case nsIPrintSettings::kFrameEnableAsIsAndEach
:
711 if (printFrameType
!= nsIPrintSettings::kSelectedFrame
) {
712 mPrt
->mPrintFrameType
= printFrameType
;
713 } else { // revert back to a good value
714 mPrt
->mPrintFrameType
= nsIPrintSettings::kEachFrameSep
;
718 mPrt
->mPrintSettings
->SetPrintFrameType(mPrt
->mPrintFrameType
);
722 mPrt
->mPrintSettings
->GetPrintFrameType(&mPrt
->mPrintFrameType
);
726 if (mPrt
->mPrintFrameType
== nsIPrintSettings::kEachFrameSep
) {
727 CheckForChildFrameSets(mPrt
->mPrintObject
);
730 if (NS_FAILED(EnablePOsForPrinting())) {
731 return NS_ERROR_FAILURE
;
734 // Attach progressListener to catch network requests.
735 nsCOMPtr
<nsIWebProgress
> webProgress
= do_QueryInterface(mPrt
->mPrintObject
->mDocShell
);
736 webProgress
->AddProgressListener(
737 static_cast<nsIWebProgressListener
*>(this),
738 nsIWebProgress::NOTIFY_STATE_REQUEST
);
741 mDidLoadDataForPrinting
= false;
743 if (aIsPrintPreview
) {
744 bool notifyOnInit
= false;
745 ShowPrintProgress(false, notifyOnInit
);
747 // Very important! Turn Off scripting
748 TurnScriptingOn(false);
751 InstallPrintPreviewListener();
752 rv
= InitPrintDocConstruction(false);
758 ShowPrintProgress(true, doNotify
);
760 // Print listener setup...
761 mPrt
->OnStartPrinting();
763 rv
= InitPrintDocConstruction(false);
767 // We will enable scripting later after printing has finished.
768 scriptSuppressor
.Disconnect();
773 //---------------------------------------------------------------------------------
775 nsPrintEngine::Print(nsIPrintSettings
* aPrintSettings
,
776 nsIWebProgressListener
* aWebProgressListener
)
778 // If we have a print preview document, use that instead of the original
779 // mDocument. That way animated images etc. get printed using the same state
780 // as in print preview.
781 nsCOMPtr
<nsIDOMDocument
> doc
=
782 do_QueryInterface(mPrtPreview
&& mPrtPreview
->mPrintObject
?
783 mPrtPreview
->mPrintObject
->mDocument
: mDocument
);
785 return CommonPrint(false, aPrintSettings
, aWebProgressListener
, doc
);
789 nsPrintEngine::PrintPreview(nsIPrintSettings
* aPrintSettings
,
790 nsIDOMWindow
*aChildDOMWin
,
791 nsIWebProgressListener
* aWebProgressListener
)
793 // Get the DocShell and see if it is busy
794 // (We can't Print Preview this document if it is still busy)
795 nsCOMPtr
<nsIDocShell
> docShell(do_QueryReferent(mContainer
));
796 NS_ENSURE_STATE(docShell
);
798 uint32_t busyFlags
= nsIDocShell::BUSY_FLAGS_NONE
;
799 if (NS_FAILED(docShell
->GetBusyFlags(&busyFlags
)) ||
800 busyFlags
!= nsIDocShell::BUSY_FLAGS_NONE
) {
801 CloseProgressDialog(aWebProgressListener
);
802 ShowPrintErrorDialog(NS_ERROR_GFX_PRINTER_DOC_IS_BUSY
, false);
803 return NS_ERROR_FAILURE
;
806 NS_ENSURE_STATE(aChildDOMWin
);
807 nsCOMPtr
<nsIDOMDocument
> doc
;
808 aChildDOMWin
->GetDocument(getter_AddRefs(doc
));
809 NS_ENSURE_STATE(doc
);
811 // Document is not busy -- go ahead with the Print Preview
812 return CommonPrint(true, aPrintSettings
, aWebProgressListener
, doc
);
815 //----------------------------------------------------------------------------------
816 /* readonly attribute boolean isFramesetDocument; */
818 nsPrintEngine::GetIsFramesetDocument(bool *aIsFramesetDocument
)
820 nsCOMPtr
<nsIDocShell
> webContainer(do_QueryReferent(mContainer
));
821 *aIsFramesetDocument
= IsParentAFrameSet(webContainer
);
825 //----------------------------------------------------------------------------------
826 /* readonly attribute boolean isIFrameSelected; */
828 nsPrintEngine::GetIsIFrameSelected(bool *aIsIFrameSelected
)
830 *aIsIFrameSelected
= false;
832 // Get the docshell for this documentviewer
833 nsCOMPtr
<nsIDocShell
> webContainer(do_QueryReferent(mContainer
));
834 // Get the currently focused window
835 nsCOMPtr
<nsIDOMWindow
> currentFocusWin
= FindFocusedDOMWindow();
836 if (currentFocusWin
&& webContainer
) {
837 // Get whether the doc contains a frameset
838 // Also, check to see if the currently focus docshell
839 // is a child of this docshell
840 bool isParentFrameSet
;
841 *aIsIFrameSelected
= IsThereAnIFrameSelected(webContainer
, currentFocusWin
, isParentFrameSet
);
846 //----------------------------------------------------------------------------------
847 /* readonly attribute boolean isRangeSelection; */
849 nsPrintEngine::GetIsRangeSelection(bool *aIsRangeSelection
)
851 // Get the currently focused window
852 nsCOMPtr
<nsIDOMWindow
> currentFocusWin
= FindFocusedDOMWindow();
853 *aIsRangeSelection
= IsThereARangeSelection(currentFocusWin
);
857 //----------------------------------------------------------------------------------
858 /* readonly attribute boolean isFramesetFrameSelected; */
860 nsPrintEngine::GetIsFramesetFrameSelected(bool *aIsFramesetFrameSelected
)
862 // Get the currently focused window
863 nsCOMPtr
<nsIDOMWindow
> currentFocusWin
= FindFocusedDOMWindow();
864 *aIsFramesetFrameSelected
= currentFocusWin
!= nullptr;
868 //----------------------------------------------------------------------------------
869 /* readonly attribute long printPreviewNumPages; */
871 nsPrintEngine::GetPrintPreviewNumPages(int32_t *aPrintPreviewNumPages
)
873 NS_ENSURE_ARG_POINTER(aPrintPreviewNumPages
);
875 nsPrintData
* prt
= nullptr;
876 nsIFrame
* seqFrame
= nullptr;
877 *aPrintPreviewNumPages
= 0;
879 // When calling this function, the FinishPrintPreview() function might not
880 // been called as there are still some
887 NS_FAILED(GetSeqFrameAndCountPagesInternal(prt
->mPrintObject
, seqFrame
, *aPrintPreviewNumPages
))) {
888 return NS_ERROR_FAILURE
;
893 //----------------------------------------------------------------------------------
894 // Enumerate all the documents for their titles
896 nsPrintEngine::EnumerateDocumentNames(uint32_t* aCount
,
899 NS_ENSURE_ARG(aCount
);
900 NS_ENSURE_ARG_POINTER(aResult
);
905 int32_t numDocs
= mPrt
->mPrintDocList
.Length();
906 char16_t
** array
= (char16_t
**) nsMemory::Alloc(numDocs
* sizeof(char16_t
*));
908 return NS_ERROR_OUT_OF_MEMORY
;
910 for (int32_t i
=0;i
<numDocs
;i
++) {
911 nsPrintObject
* po
= mPrt
->mPrintDocList
.ElementAt(i
);
912 NS_ASSERTION(po
, "nsPrintObject can't be null!");
913 nsAutoString docTitleStr
;
914 nsAutoString docURLStr
;
915 GetDocumentTitleAndURL(po
->mDocument
, docTitleStr
, docURLStr
);
917 // Use the URL if the doc is empty
918 if (docTitleStr
.IsEmpty() && !docURLStr
.IsEmpty()) {
919 docTitleStr
= docURLStr
;
921 array
[i
] = ToNewUnicode(docTitleStr
);
930 //----------------------------------------------------------------------------------
931 /* readonly attribute nsIPrintSettings globalPrintSettings; */
933 nsPrintEngine::GetGlobalPrintSettings(nsIPrintSettings
**aGlobalPrintSettings
)
935 NS_ENSURE_ARG_POINTER(aGlobalPrintSettings
);
937 nsresult rv
= NS_ERROR_FAILURE
;
938 nsCOMPtr
<nsIPrintSettingsService
> printSettingsService
=
939 do_GetService(sPrintSettingsServiceContractID
, &rv
);
940 if (NS_SUCCEEDED(rv
)) {
941 rv
= printSettingsService
->GetGlobalPrintSettings(aGlobalPrintSettings
);
946 //----------------------------------------------------------------------------------
947 /* readonly attribute boolean doingPrint; */
949 nsPrintEngine::GetDoingPrint(bool *aDoingPrint
)
951 NS_ENSURE_ARG_POINTER(aDoingPrint
);
952 *aDoingPrint
= mIsDoingPrinting
;
956 //----------------------------------------------------------------------------------
957 /* readonly attribute boolean doingPrintPreview; */
959 nsPrintEngine::GetDoingPrintPreview(bool *aDoingPrintPreview
)
961 NS_ENSURE_ARG_POINTER(aDoingPrintPreview
);
962 *aDoingPrintPreview
= mIsDoingPrintPreview
;
966 //----------------------------------------------------------------------------------
967 /* readonly attribute nsIPrintSettings currentPrintSettings; */
969 nsPrintEngine::GetCurrentPrintSettings(nsIPrintSettings
* *aCurrentPrintSettings
)
971 NS_ENSURE_ARG_POINTER(aCurrentPrintSettings
);
974 *aCurrentPrintSettings
= mPrt
->mPrintSettings
;
976 } else if (mPrtPreview
) {
977 *aCurrentPrintSettings
= mPrtPreview
->mPrintSettings
;
980 *aCurrentPrintSettings
= nullptr;
982 NS_IF_ADDREF(*aCurrentPrintSettings
);
986 //-----------------------------------------------------------------
987 //-- Section: Pre-Reflow Methods
988 //-----------------------------------------------------------------
990 //---------------------------------------------------------------------
991 // This method checks to see if there is at least one printer defined
992 // and if so, it sets the first printer in the list as the default name
993 // in the PrintSettings which is then used for Printer Preview
995 nsPrintEngine::CheckForPrinters(nsIPrintSettings
* aPrintSettings
)
997 #if defined(XP_MACOSX) || defined(ANDROID)
998 // Mac doesn't support retrieving a printer list.
1001 NS_ENSURE_ARG_POINTER(aPrintSettings
);
1003 // See if aPrintSettings already has a printer
1004 nsXPIDLString printerName
;
1005 nsresult rv
= aPrintSettings
->GetPrinterName(getter_Copies(printerName
));
1006 if (NS_SUCCEEDED(rv
) && !printerName
.IsEmpty()) {
1010 // aPrintSettings doesn't have a printer set. Try to fetch the default.
1011 nsCOMPtr
<nsIPrintSettingsService
> printSettingsService
=
1012 do_GetService(sPrintSettingsServiceContractID
, &rv
);
1013 NS_ENSURE_SUCCESS(rv
, rv
);
1015 rv
= printSettingsService
->GetDefaultPrinterName(getter_Copies(printerName
));
1016 if (NS_SUCCEEDED(rv
) && !printerName
.IsEmpty()) {
1017 rv
= aPrintSettings
->SetPrinterName(printerName
.get());
1023 //----------------------------------------------------------------------
1024 // Set up to use the "pluggable" Print Progress Dialog
1026 nsPrintEngine::ShowPrintProgress(bool aIsForPrinting
, bool& aDoNotify
)
1028 // default to not notifying, that if something here goes wrong
1029 // or we aren't going to show the progress dialog we can straight into
1030 // reflowing the doc for printing.
1033 // Assume we can't do progress and then see if we can
1034 bool showProgresssDialog
= false;
1036 // if it is already being shown then don't bother to find out if it should be
1037 // so skip this and leave mShowProgressDialog set to FALSE
1038 if (!mProgressDialogIsShown
) {
1039 showProgresssDialog
= Preferences::GetBool("print.show_print_progress");
1042 // Turning off the showing of Print Progress in Prefs overrides
1043 // whether the calling PS desire to have it on or off, so only check PS if
1044 // prefs says it's ok to be on.
1045 if (showProgresssDialog
) {
1046 mPrt
->mPrintSettings
->GetShowPrintProgress(&showProgresssDialog
);
1049 // Now open the service to get the progress dialog
1050 // If we don't get a service, that's ok, then just don't show progress
1051 if (showProgresssDialog
) {
1052 nsCOMPtr
<nsIPrintingPromptService
> printPromptService(do_GetService(kPrintingPromptService
));
1053 if (printPromptService
) {
1054 nsPIDOMWindow
*domWin
= mDocument
->GetWindow();
1055 if (!domWin
) return;
1057 nsCOMPtr
<nsIDocShell
> docShell
= domWin
->GetDocShell();
1058 if (!docShell
) return;
1059 nsCOMPtr
<nsIDocShellTreeOwner
> owner
;
1060 docShell
->GetTreeOwner(getter_AddRefs(owner
));
1061 nsCOMPtr
<nsIWebBrowserChrome
> browserChrome
= do_GetInterface(owner
);
1062 if (!browserChrome
) return;
1063 bool isModal
= true;
1064 browserChrome
->IsWindowModal(&isModal
);
1066 // Showing a print progress dialog when printing a modal window
1067 // isn't supported. See bug 301560.
1071 nsCOMPtr
<nsIWebProgressListener
> printProgressListener
;
1073 nsCOMPtr
<nsIWebBrowserPrint
> wbp(do_QueryInterface(mDocViewerPrint
));
1074 nsresult rv
= printPromptService
->ShowProgress(domWin
, wbp
, mPrt
->mPrintSettings
, this, aIsForPrinting
,
1075 getter_AddRefs(printProgressListener
),
1076 getter_AddRefs(mPrt
->mPrintProgressParams
),
1078 if (NS_SUCCEEDED(rv
)) {
1079 if (printProgressListener
&& mPrt
->mPrintProgressParams
) {
1080 mPrt
->mPrintProgressListeners
.AppendObject(printProgressListener
);
1081 SetDocAndURLIntoProgress(mPrt
->mPrintObject
, mPrt
->mPrintProgressParams
);
1088 //---------------------------------------------------------------------
1090 nsPrintEngine::IsThereARangeSelection(nsIDOMWindow
* aDOMWin
)
1092 if (mDisallowSelectionPrint
)
1095 nsCOMPtr
<nsIPresShell
> presShell
;
1097 nsCOMPtr
<nsPIDOMWindow
> window(do_QueryInterface(aDOMWin
));
1098 presShell
= window
->GetDocShell()->GetPresShell();
1104 // check here to see if there is a range selection
1105 // so we know whether to turn on the "Selection" radio button
1106 Selection
* selection
=
1107 presShell
->GetCurrentSelection(nsISelectionController::SELECTION_NORMAL
);
1112 int32_t rangeCount
= selection
->GetRangeCount();
1117 if (rangeCount
> 1) {
1121 // check to make sure it isn't an insertion selection
1122 return selection
->GetRangeAt(0) && !selection
->IsCollapsed();
1125 //---------------------------------------------------------------------
1127 nsPrintEngine::IsParentAFrameSet(nsIDocShell
* aParent
)
1129 // See if the incoming doc is the root document
1130 if (!aParent
) return false;
1132 // When it is the top level document we need to check
1133 // to see if it contains a frameset. If it does, then
1134 // we only want to print the doc's children and not the document itself
1135 // For anything else we always print all the children and the document
1136 // for example, if the doc contains an IFRAME we eant to print the child
1137 // document (the IFRAME) and then the rest of the document.
1139 // XXX we really need to search the frame tree, and not the content
1140 // but there is no way to distinguish between IFRAMEs and FRAMEs
1141 // with the GetFrameType call.
1142 // Bug 53459 has been files so we can eventually distinguish
1143 // between IFRAME frames and FRAME frames
1144 bool isFrameSet
= false;
1145 // only check to see if there is a frameset if there is
1146 // NO parent doc for this doc. meaning this parent is the root doc
1147 nsCOMPtr
<nsIDocument
> doc
= aParent
->GetDocument();
1149 nsIContent
*rootElement
= doc
->GetRootElement();
1151 isFrameSet
= HasFramesetChild(rootElement
);
1158 //---------------------------------------------------------------------
1159 // Recursively build a list of sub documents to be printed
1160 // that mirrors the document tree
1162 nsPrintEngine::BuildDocTree(nsIDocShell
* aParentNode
,
1163 nsTArray
<nsPrintObject
*> * aDocList
,
1164 nsPrintObject
* aPO
)
1166 NS_ASSERTION(aParentNode
, "Pointer is null!");
1167 NS_ASSERTION(aDocList
, "Pointer is null!");
1168 NS_ASSERTION(aPO
, "Pointer is null!");
1170 int32_t childWebshellCount
;
1171 aParentNode
->GetChildCount(&childWebshellCount
);
1172 if (childWebshellCount
> 0) {
1173 for (int32_t i
=0;i
<childWebshellCount
;i
++) {
1174 nsCOMPtr
<nsIDocShellTreeItem
> child
;
1175 aParentNode
->GetChildAt(i
, getter_AddRefs(child
));
1176 nsCOMPtr
<nsIDocShell
> childAsShell(do_QueryInterface(child
));
1178 nsCOMPtr
<nsIContentViewer
> viewer
;
1179 childAsShell
->GetContentViewer(getter_AddRefs(viewer
));
1181 nsCOMPtr
<nsIContentViewerFile
> viewerFile(do_QueryInterface(viewer
));
1183 nsCOMPtr
<nsIDOMDocument
> doc
= do_GetInterface(childAsShell
);
1184 nsPrintObject
* po
= new nsPrintObject();
1186 nsresult rv
= po
->Init(childAsShell
, doc
, aPO
->mPrintPreview
);
1188 NS_NOTREACHED("Init failed?");
1189 aPO
->mKids
.AppendElement(po
);
1190 aDocList
->AppendElement(po
);
1191 BuildDocTree(childAsShell
, aDocList
, po
);
1198 //---------------------------------------------------------------------
1200 nsPrintEngine::GetDocumentTitleAndURL(nsIDocument
* aDoc
,
1204 NS_ASSERTION(aDoc
, "Pointer is null!");
1209 nsCOMPtr
<nsIDOMDocument
> doc
= do_QueryInterface(aDoc
);
1210 doc
->GetTitle(aTitle
);
1212 nsIURI
* url
= aDoc
->GetDocumentURI();
1215 nsCOMPtr
<nsIURIFixup
> urifixup(do_GetService(NS_URIFIXUP_CONTRACTID
));
1216 if (!urifixup
) return;
1218 nsCOMPtr
<nsIURI
> exposableURI
;
1219 urifixup
->CreateExposableURI(url
, getter_AddRefs(exposableURI
));
1221 if (!exposableURI
) return;
1223 nsAutoCString urlCStr
;
1224 exposableURI
->GetSpec(urlCStr
);
1227 nsCOMPtr
<nsITextToSubURI
> textToSubURI
=
1228 do_GetService(NS_ITEXTTOSUBURI_CONTRACTID
, &rv
);
1229 if (NS_FAILED(rv
)) return;
1231 textToSubURI
->UnEscapeURIForUI(NS_LITERAL_CSTRING("UTF-8"),
1235 //---------------------------------------------------------------------
1236 // The walks the PO tree and for each document it walks the content
1237 // tree looking for any content that are sub-shells
1239 // It then sets the mContent pointer in the "found" PO object back to the
1240 // the document that contained it.
1242 nsPrintEngine::MapContentToWebShells(nsPrintObject
* aRootPO
,
1245 NS_ASSERTION(aRootPO
, "Pointer is null!");
1246 NS_ASSERTION(aPO
, "Pointer is null!");
1248 // Recursively walk the content from the root item
1249 // XXX Would be faster to enumerate the subdocuments, although right now
1250 // nsIDocument doesn't expose quite what would be needed.
1251 nsCOMPtr
<nsIContentViewer
> viewer
;
1252 aPO
->mDocShell
->GetContentViewer(getter_AddRefs(viewer
));
1253 if (!viewer
) return;
1255 nsCOMPtr
<nsIDOMDocument
> domDoc
;
1256 viewer
->GetDOMDocument(getter_AddRefs(domDoc
));
1257 nsCOMPtr
<nsIDocument
> doc
= do_QueryInterface(domDoc
);
1260 Element
* rootElement
= doc
->GetRootElement();
1262 MapContentForPO(aPO
, rootElement
);
1264 NS_WARNING("Null root content on (sub)document.");
1267 // Continue recursively walking the chilren of this PO
1268 for (uint32_t i
=0;i
<aPO
->mKids
.Length();i
++) {
1269 MapContentToWebShells(aRootPO
, aPO
->mKids
[i
]);
1274 //-------------------------------------------------------
1275 // A Frame's sub-doc may contain content or a FrameSet
1276 // When it contains a FrameSet the mFrameType for the PrintObject
1277 // is always set to an eFrame. Which is fine when printing "AsIs"
1278 // but is incorrect when when printing "Each Frame Separately".
1279 // When printing "Each Frame Separately" the Frame really acts like
1282 // This method walks the PO tree and checks to see if the PrintObject is
1283 // an eFrame and has children that are eFrames (meaning it's a Frame containing a FrameSet)
1284 // If so, then the mFrameType need to be changed to eFrameSet
1286 // Also note: We only want to call this we are printing "Each Frame Separately"
1287 // when printing "As Is" leave it as an eFrame
1289 nsPrintEngine::CheckForChildFrameSets(nsPrintObject
* aPO
)
1291 NS_ASSERTION(aPO
, "Pointer is null!");
1293 // Continue recursively walking the chilren of this PO
1294 bool hasChildFrames
= false;
1295 for (uint32_t i
=0;i
<aPO
->mKids
.Length();i
++) {
1296 nsPrintObject
* po
= aPO
->mKids
[i
];
1297 if (po
->mFrameType
== eFrame
) {
1298 hasChildFrames
= true;
1299 CheckForChildFrameSets(po
);
1303 if (hasChildFrames
&& aPO
->mFrameType
== eFrame
) {
1304 aPO
->mFrameType
= eFrameSet
;
1308 //---------------------------------------------------------------------
1309 // This method is key to the entire print mechanism.
1311 // This "maps" or figures out which sub-doc represents a
1312 // given Frame or IFrame in its parent sub-doc.
1314 // So the Mcontent pointer in the child sub-doc points to the
1315 // content in the its parent document, that caused it to be printed.
1316 // This is used later to (after reflow) to find the absolute location
1317 // of the sub-doc on its parent's page frame so it can be
1318 // printed in the correct location.
1320 // This method recursvely "walks" the content for a document finding
1321 // all the Frames and IFrames, then sets the "mFrameType" data member
1322 // which tells us what type of PO we have
1324 nsPrintEngine::MapContentForPO(nsPrintObject
* aPO
,
1325 nsIContent
* aContent
)
1327 NS_PRECONDITION(aPO
&& aContent
, "Null argument");
1329 nsIDocument
* doc
= aContent
->GetComposedDoc();
1331 NS_ASSERTION(doc
, "Content without a document from a document tree?");
1333 nsIDocument
* subDoc
= doc
->GetSubDocumentFor(aContent
);
1336 nsCOMPtr
<nsIDocShell
> docShell(subDoc
->GetDocShell());
1339 nsPrintObject
* po
= nullptr;
1340 int32_t cnt
= aPO
->mKids
.Length();
1341 for (int32_t i
=0;i
<cnt
;i
++) {
1342 nsPrintObject
* kid
= aPO
->mKids
.ElementAt(i
);
1343 if (kid
->mDocument
== subDoc
) {
1349 // XXX If a subdocument has no onscreen presentation, there will be no PO
1350 // This is even if there should be a print presentation
1353 nsCOMPtr
<nsIDOMHTMLFrameElement
> frame(do_QueryInterface(aContent
));
1354 // "frame" elements not in a frameset context should be treated
1356 if (frame
&& po
->mParent
->mFrameType
== eFrameSet
) {
1357 po
->mFrameType
= eFrame
;
1359 // Assume something iframe-like, i.e. iframe, object, or embed
1360 po
->mFrameType
= eIFrame
;
1361 SetPrintAsIs(po
, true);
1362 NS_ASSERTION(po
->mParent
, "The root must be a parent");
1363 po
->mParent
->mPrintAsIs
= true;
1369 // walk children content
1370 for (nsIContent
* child
= aContent
->GetFirstChild();
1372 child
= child
->GetNextSibling()) {
1373 MapContentForPO(aPO
, child
);
1377 //---------------------------------------------------------------------
1379 nsPrintEngine::IsThereAnIFrameSelected(nsIDocShell
* aDocShell
,
1380 nsIDOMWindow
* aDOMWin
,
1381 bool& aIsParentFrameSet
)
1383 aIsParentFrameSet
= IsParentAFrameSet(aDocShell
);
1384 bool iFrameIsSelected
= false;
1385 if (mPrt
&& mPrt
->mPrintObject
) {
1386 nsPrintObject
* po
= FindPrintObjectByDOMWin(mPrt
->mPrintObject
, aDOMWin
);
1387 iFrameIsSelected
= po
&& po
->mFrameType
== eIFrame
;
1389 // First, check to see if we are a frameset
1390 if (!aIsParentFrameSet
) {
1391 // Check to see if there is a currenlt focused frame
1392 // if so, it means the selected frame is either the main docshell
1395 // Get the main docshell's DOMWin to see if it matches
1396 // the frame that is selected
1397 nsCOMPtr
<nsIDOMWindow
> domWin
=
1398 aDocShell
? aDocShell
->GetWindow() : nullptr;
1399 if (domWin
!= aDOMWin
) {
1400 iFrameIsSelected
= true; // we have a selected IFRAME
1406 return iFrameIsSelected
;
1409 //---------------------------------------------------------------------
1410 // Recursively sets all the PO items to be printed
1411 // from the given item down into the tree
1413 nsPrintEngine::SetPrintPO(nsPrintObject
* aPO
, bool aPrint
)
1415 NS_ASSERTION(aPO
, "Pointer is null!");
1417 // Set whether to print flag
1418 aPO
->mDontPrint
= !aPrint
;
1420 for (uint32_t i
=0;i
<aPO
->mKids
.Length();i
++) {
1421 SetPrintPO(aPO
->mKids
[i
], aPrint
);
1425 //---------------------------------------------------------------------
1426 // This will first use a Title and/or URL from the PrintSettings
1427 // if one isn't set then it uses the one from the document
1428 // then if not title is there we will make sure we send something back
1429 // depending on the situation.
1431 nsPrintEngine::GetDisplayTitleAndURL(nsPrintObject
* aPO
,
1434 eDocTitleDefault aDefType
)
1436 NS_ASSERTION(aPO
, "Pointer is null!");
1444 // First check to see if the PrintSettings has defined an alternate title
1445 // and use that if it did
1446 if (mPrt
->mPrintSettings
) {
1447 char16_t
* docTitleStrPS
= nullptr;
1448 char16_t
* docURLStrPS
= nullptr;
1449 mPrt
->mPrintSettings
->GetTitle(&docTitleStrPS
);
1450 mPrt
->mPrintSettings
->GetDocURL(&docURLStrPS
);
1452 if (docTitleStrPS
) {
1453 aTitle
= docTitleStrPS
;
1457 aURLStr
= docURLStrPS
;
1460 nsMemory::Free(docTitleStrPS
);
1461 nsMemory::Free(docURLStrPS
);
1464 nsAutoString docTitle
;
1465 nsAutoString docUrl
;
1466 GetDocumentTitleAndURL(aPO
->mDocument
, docTitle
, docUrl
);
1468 if (aURLStr
.IsEmpty() && !docUrl
.IsEmpty()) {
1472 if (aTitle
.IsEmpty()) {
1473 if (!docTitle
.IsEmpty()) {
1476 if (aDefType
== eDocTitleDefURLDoc
) {
1477 if (!aURLStr
.IsEmpty()) {
1479 } else if (mPrt
->mBrandName
) {
1480 aTitle
= mPrt
->mBrandName
;
1487 //---------------------------------------------------------------------
1488 nsresult
nsPrintEngine::DocumentReadyForPrinting()
1490 if (mPrt
->mPrintFrameType
== nsIPrintSettings::kEachFrameSep
) {
1491 CheckForChildFrameSets(mPrt
->mPrintObject
);
1495 // Send the document to the printer...
1497 nsresult rv
= SetupToPrintContent();
1498 if (NS_FAILED(rv
)) {
1499 // The print job was canceled or there was a problem
1500 // So remove all other documents from the print list
1501 DonePrintingPages(nullptr, rv
);
1506 /** ---------------------------------------------------
1507 * Cleans up when an error occurred
1509 nsresult
nsPrintEngine::CleanupOnFailure(nsresult aResult
, bool aIsPrinting
)
1511 PR_PL(("**** Failed %s - rv 0x%X", aIsPrinting
?"Printing":"Print Preview", aResult
));
1514 if (mPagePrintTimer
) {
1515 mPagePrintTimer
->Stop();
1516 NS_RELEASE(mPagePrintTimer
);
1520 SetIsPrinting(false);
1522 SetIsPrintPreview(false);
1523 SetIsCreatingPrintPreview(false);
1526 /* cleanup done, let's fire-up an error dialog to notify the user
1527 * what went wrong...
1529 * When rv == NS_ERROR_ABORT, it means we want out of the
1530 * print job without displaying any error messages
1532 if (aResult
!= NS_ERROR_ABORT
) {
1533 ShowPrintErrorDialog(aResult
, aIsPrinting
);
1536 FirePrintCompletionEvent();
1542 //---------------------------------------------------------------------
1544 nsPrintEngine::ShowPrintErrorDialog(nsresult aPrintError
, bool aIsPrinting
)
1546 nsAutoCString stringName
;
1547 nsXPIDLString msg
, title
;
1548 nsresult rv
= NS_OK
;
1552 #define ENTITY_FOR_ERROR(label) \
1553 case NS_ERROR_##label: stringName.AssignLiteral("PERR_" #label); break
1555 ENTITY_FOR_ERROR(GFX_PRINTER_NO_PRINTER_AVAILABLE
);
1556 ENTITY_FOR_ERROR(GFX_PRINTER_NAME_NOT_FOUND
);
1557 ENTITY_FOR_ERROR(GFX_PRINTER_COULD_NOT_OPEN_FILE
);
1558 ENTITY_FOR_ERROR(GFX_PRINTER_STARTDOC
);
1559 ENTITY_FOR_ERROR(GFX_PRINTER_ENDDOC
);
1560 ENTITY_FOR_ERROR(GFX_PRINTER_STARTPAGE
);
1561 ENTITY_FOR_ERROR(GFX_PRINTER_DOC_IS_BUSY
);
1563 ENTITY_FOR_ERROR(ABORT
);
1564 ENTITY_FOR_ERROR(NOT_AVAILABLE
);
1565 ENTITY_FOR_ERROR(NOT_IMPLEMENTED
);
1566 ENTITY_FOR_ERROR(OUT_OF_MEMORY
);
1567 ENTITY_FOR_ERROR(UNEXPECTED
);
1570 ENTITY_FOR_ERROR(FAILURE
);
1572 #undef ENTITY_FOR_ERROR
1576 // Try first with _PP suffix.
1577 stringName
.AppendLiteral("_PP");
1578 rv
= nsContentUtils::GetLocalizedString(
1579 nsContentUtils::ePRINTING_PROPERTIES
, stringName
.get(), msg
);
1580 if (NS_FAILED(rv
)) {
1581 stringName
.Truncate(stringName
.Length() - 3);
1584 if (aIsPrinting
|| NS_FAILED(rv
)) {
1585 rv
= nsContentUtils::GetLocalizedString(
1586 nsContentUtils::ePRINTING_PROPERTIES
, stringName
.get(), msg
);
1588 if (NS_FAILED(rv
)) {
1592 rv
= nsContentUtils::GetLocalizedString(
1593 nsContentUtils::ePRINTING_PROPERTIES
,
1594 aIsPrinting
? "print_error_dialog_title"
1595 : "printpreview_error_dialog_title",
1597 if (NS_FAILED(rv
)) {
1601 nsCOMPtr
<nsIWindowWatcher
> wwatch
=
1602 do_GetService(NS_WINDOWWATCHER_CONTRACTID
, &rv
);
1603 if (NS_FAILED(rv
)) {
1607 nsCOMPtr
<nsIDOMWindow
> active
;
1608 wwatch
->GetActiveWindow(getter_AddRefs(active
));
1610 nsCOMPtr
<nsIPrompt
> dialog
;
1611 /* |GetNewPrompter| allows that |active| is |nullptr|
1612 * (see bug 234982 ("nsPrintEngine::ShowPrintErrorDialog() fails in many cases")) */
1613 wwatch
->GetNewPrompter(active
, getter_AddRefs(dialog
));
1618 dialog
->Alert(title
.get(), msg
.get());
1621 //-----------------------------------------------------------------
1622 //-- Section: Reflow Methods
1623 //-----------------------------------------------------------------
1626 nsPrintEngine::ReconstructAndReflow(bool doSetPixelScale
)
1628 #if defined(XP_WIN) && defined(EXTENDED_DEBUG_PRINTING)
1629 // We need to clear all the output files here
1630 // because they will be re-created with second reflow of the docs
1631 if (kPrintingLogMod
&& kPrintingLogMod
->level
== DUMP_LAYOUT_LEVEL
) {
1632 RemoveFilesInDir(".\\");
1633 gDumpFileNameCnt
= 0;
1634 gDumpLOFileNameCnt
= 0;
1638 for (uint32_t i
= 0; i
< mPrt
->mPrintDocList
.Length(); ++i
) {
1639 nsPrintObject
* po
= mPrt
->mPrintDocList
.ElementAt(i
);
1640 NS_ASSERTION(po
, "nsPrintObject can't be null!");
1642 if (po
->mDontPrint
|| po
->mInvisible
) {
1646 UpdateZoomRatio(po
, doSetPixelScale
);
1648 po
->mPresContext
->SetPageScale(po
->mZoomRatio
);
1650 // Calculate scale factor from printer to screen
1651 float printDPI
= float(mPrt
->mPrintDC
->AppUnitsPerCSSInch()) /
1652 float(mPrt
->mPrintDC
->AppUnitsPerDevPixel());
1653 po
->mPresContext
->SetPrintPreviewScale(mScreenDPI
/ printDPI
);
1655 po
->mPresShell
->ReconstructFrames();
1657 // For all views except the first one, setup the root view.
1658 // ??? Can there be multiple po for the top-level-document?
1659 bool documentIsTopLevel
= true;
1663 nsresult rv
= SetRootView(po
, doReturn
, documentIsTopLevel
, adjSize
);
1665 MOZ_ASSERT(!documentIsTopLevel
, "How could this happen?");
1667 if (NS_FAILED(rv
) || doReturn
) {
1672 po
->mPresShell
->FlushPendingNotifications(Flush_Layout
);
1674 nsresult rv
= UpdateSelectionAndShrinkPrintObject(po
, documentIsTopLevel
);
1675 NS_ENSURE_SUCCESS(rv
, rv
);
1680 //-------------------------------------------------------
1682 nsPrintEngine::SetupToPrintContent()
1686 bool didReconstruction
= false;
1688 // If some new content got loaded since the initial reflow rebuild
1690 if (mDidLoadDataForPrinting
) {
1691 rv
= ReconstructAndReflow(DoSetPixelScale());
1692 didReconstruction
= true;
1693 NS_ENSURE_SUCCESS(rv
, rv
);
1696 // Here is where we figure out if extra reflow for shrinking the content
1698 // But skip this step if we are in PrintPreview
1699 bool ppIsShrinkToFit
= mPrtPreview
&& mPrtPreview
->mShrinkToFit
;
1700 if (mPrt
->mShrinkToFit
&& !ppIsShrinkToFit
) {
1701 // Now look for the PO that has the smallest percent for shrink to fit
1702 if (mPrt
->mPrintDocList
.Length() > 1 && mPrt
->mPrintObject
->mFrameType
== eFrameSet
) {
1703 nsPrintObject
* smallestPO
= FindSmallestSTF();
1704 NS_ASSERTION(smallestPO
, "There must always be an XMost PO!");
1706 // Calc the shrinkage based on the entire content area
1707 mPrt
->mShrinkRatio
= smallestPO
->mShrinkRatio
;
1710 // Single document so use the Shrink as calculated for the PO
1711 mPrt
->mShrinkRatio
= mPrt
->mPrintObject
->mShrinkRatio
;
1714 if (mPrt
->mShrinkRatio
< 0.998f
) {
1715 rv
= ReconstructAndReflow(true);
1716 didReconstruction
= true;
1717 NS_ENSURE_SUCCESS(rv
, rv
);
1721 float calcRatio
= 0.0f
;
1722 if (mPrt
->mPrintDocList
.Length() > 1 && mPrt
->mPrintObject
->mFrameType
== eFrameSet
) {
1723 nsPrintObject
* smallestPO
= FindSmallestSTF();
1724 NS_ASSERTION(smallestPO
, "There must always be an XMost PO!");
1726 // Calc the shrinkage based on the entire content area
1727 calcRatio
= smallestPO
->mShrinkRatio
;
1730 // Single document so use the Shrink as calculated for the PO
1731 calcRatio
= mPrt
->mPrintObject
->mShrinkRatio
;
1733 PR_PL(("**************************************************************************\n"));
1734 PR_PL(("STF Ratio is: %8.5f Effective Ratio: %8.5f Diff: %8.5f\n", mPrt
->mShrinkRatio
, calcRatio
, mPrt
->mShrinkRatio
-calcRatio
));
1735 PR_PL(("**************************************************************************\n"));
1739 // If the frames got reconstructed and reflowed the number of pages might
1741 if (didReconstruction
) {
1742 FirePrintPreviewUpdateEvent();
1745 DUMP_DOC_LIST(("\nAfter Reflow------------------------------------------"));
1747 PR_PL(("-------------------------------------------------------\n"));
1750 CalcNumPrintablePages(mPrt
->mNumPrintablePages
);
1752 PR_PL(("--- Printing %d pages\n", mPrt
->mNumPrintablePages
));
1753 DUMP_DOC_TREELAYOUT
;
1755 // Print listener setup...
1756 if (mPrt
!= nullptr) {
1757 mPrt
->OnStartPrinting();
1760 char16_t
* fileName
= nullptr;
1761 // check to see if we are printing to a file
1762 bool isPrintToFile
= false;
1763 mPrt
->mPrintSettings
->GetPrintToFile(&isPrintToFile
);
1764 if (isPrintToFile
) {
1765 // On some platforms The BeginDocument needs to know the name of the file
1766 // and it uses the PrintService to get it, so we need to set it into the PrintService here
1767 mPrt
->mPrintSettings
->GetToFileName(&fileName
);
1770 nsAutoString docTitleStr
;
1771 nsAutoString docURLStr
;
1772 GetDisplayTitleAndURL(mPrt
->mPrintObject
, docTitleStr
, docURLStr
, eDocTitleDefURLDoc
);
1774 int32_t startPage
= 1;
1775 int32_t endPage
= mPrt
->mNumPrintablePages
;
1777 int16_t printRangeType
= nsIPrintSettings::kRangeAllPages
;
1778 mPrt
->mPrintSettings
->GetPrintRange(&printRangeType
);
1779 if (printRangeType
== nsIPrintSettings::kRangeSpecifiedPageRange
) {
1780 mPrt
->mPrintSettings
->GetStartPageRange(&startPage
);
1781 mPrt
->mPrintSettings
->GetEndPageRange(&endPage
);
1782 if (endPage
> mPrt
->mNumPrintablePages
) {
1783 endPage
= mPrt
->mNumPrintablePages
;
1788 // BeginDocument may pass back a FAILURE code
1789 // i.e. On Windows, if you are printing to a file and hit "Cancel"
1790 // to the "File Name" dialog, this comes back as an error
1791 // Don't start printing when regression test are executed
1792 if (!mPrt
->mDebugFilePtr
&& mIsDoingPrinting
) {
1793 rv
= mPrt
->mPrintDC
->BeginDocument(docTitleStr
, fileName
, startPage
, endPage
);
1796 if (mIsCreatingPrintPreview
) {
1797 // Copy docTitleStr and docURLStr to the pageSequenceFrame, to be displayed
1799 nsIPageSequenceFrame
*seqFrame
= mPrt
->mPrintObject
->mPresShell
->GetPageSequenceFrame();
1801 seqFrame
->StartPrint(mPrt
->mPrintObject
->mPresContext
,
1802 mPrt
->mPrintSettings
, docTitleStr
, docURLStr
);
1806 PR_PL(("****************** Begin Document ************************\n"));
1808 NS_ENSURE_SUCCESS(rv
, rv
);
1810 // This will print the docshell document
1811 // when it completes asynchronously in the DonePrintingPages method
1812 // it will check to see if there are more docshells to be printed and
1813 // then PrintDocContent will be called again.
1815 if (mIsDoingPrinting
) {
1816 PrintDocContent(mPrt
->mPrintObject
, rv
); // ignore return value
1822 //-------------------------------------------------------
1823 // Recursively reflow each sub-doc and then calc
1824 // all the frame locations of the sub-docs
1826 nsPrintEngine::ReflowDocList(nsPrintObject
* aPO
, bool aSetPixelScale
)
1828 NS_ENSURE_ARG_POINTER(aPO
);
1830 // Check to see if the subdocument's element has been hidden by the parent document
1831 if (aPO
->mParent
&& aPO
->mParent
->mPresShell
) {
1832 nsIFrame
* frame
= aPO
->mContent
? aPO
->mContent
->GetPrimaryFrame() : nullptr;
1833 if (!frame
|| !frame
->StyleVisibility()->IsVisible()) {
1834 SetPrintPO(aPO
, false);
1835 aPO
->mInvisible
= true;
1840 UpdateZoomRatio(aPO
, aSetPixelScale
);
1844 rv
= ReflowPrintObject(aPO
);
1845 NS_ENSURE_SUCCESS(rv
, rv
);
1847 int32_t cnt
= aPO
->mKids
.Length();
1848 for (int32_t i
=0;i
<cnt
;i
++) {
1849 rv
= ReflowDocList(aPO
->mKids
[i
], aSetPixelScale
);
1850 NS_ENSURE_SUCCESS(rv
, rv
);
1856 nsPrintEngine::FirePrintPreviewUpdateEvent()
1858 // Dispatch the event only while in PrintPreview. When printing, there is no
1859 // listener bound to this event and therefore no need to dispatch it.
1860 if (mIsDoingPrintPreview
&& !mIsDoingPrinting
) {
1861 nsCOMPtr
<nsIContentViewer
> cv
= do_QueryInterface(mDocViewerPrint
);
1862 (new AsyncEventDispatcher(
1863 cv
->GetDocument(), NS_LITERAL_STRING("printPreviewUpdate"), true, true)
1864 )->RunDOMEventWhenSafe();
1869 nsPrintEngine::InitPrintDocConstruction(bool aHandleError
)
1872 rv
= ReflowDocList(mPrt
->mPrintObject
, DoSetPixelScale());
1873 NS_ENSURE_SUCCESS(rv
, rv
);
1875 FirePrintPreviewUpdateEvent();
1877 if (mLoadCounter
== 0) {
1878 AfterNetworkPrint(aHandleError
);
1884 nsPrintEngine::AfterNetworkPrint(bool aHandleError
)
1886 nsCOMPtr
<nsIWebProgress
> webProgress
= do_QueryInterface(mPrt
->mPrintObject
->mDocShell
);
1888 webProgress
->RemoveProgressListener(
1889 static_cast<nsIWebProgressListener
*>(this));
1892 if (mIsDoingPrinting
) {
1893 rv
= DocumentReadyForPrinting();
1895 rv
= FinishPrintPreview();
1898 /* cleaup on failure + notify user */
1899 if (aHandleError
&& NS_FAILED(rv
)) {
1900 CleanupOnFailure(rv
, !mIsDoingPrinting
);
1906 ////////////////////////////////////////////////////////////////////////////////
1907 // nsIWebProgressListener
1910 nsPrintEngine::OnStateChange(nsIWebProgress
* aWebProgress
,
1911 nsIRequest
* aRequest
,
1912 uint32_t aStateFlags
,
1916 aRequest
->GetName(name
);
1917 if (name
.EqualsLiteral("about:document-onload-blocker")) {
1920 if (aStateFlags
& STATE_START
) {
1921 nsCOMPtr
<nsIChannel
> channel
= do_QueryInterface(aRequest
);
1924 } else if (aStateFlags
& STATE_STOP
) {
1925 mDidLoadDataForPrinting
= true;
1928 // If all resources are loaded, then do a small timeout and if there
1929 // are still no new requests, then another reflow.
1930 if (mLoadCounter
== 0) {
1931 AfterNetworkPrint(true);
1940 nsPrintEngine::OnProgressChange(nsIWebProgress
* aWebProgress
,
1941 nsIRequest
* aRequest
,
1942 int32_t aCurSelfProgress
,
1943 int32_t aMaxSelfProgress
,
1944 int32_t aCurTotalProgress
,
1945 int32_t aMaxTotalProgress
)
1947 NS_NOTREACHED("notification excluded in AddProgressListener(...)");
1952 nsPrintEngine::OnLocationChange(nsIWebProgress
* aWebProgress
,
1953 nsIRequest
* aRequest
,
1957 NS_NOTREACHED("notification excluded in AddProgressListener(...)");
1962 nsPrintEngine::OnStatusChange(nsIWebProgress
*aWebProgress
,
1963 nsIRequest
*aRequest
,
1965 const char16_t
*aMessage
)
1967 NS_NOTREACHED("notification excluded in AddProgressListener(...)");
1972 nsPrintEngine::OnSecurityChange(nsIWebProgress
*aWebProgress
,
1973 nsIRequest
*aRequest
,
1976 NS_NOTREACHED("notification excluded in AddProgressListener(...)");
1980 //-------------------------------------------------------
1983 nsPrintEngine::UpdateZoomRatio(nsPrintObject
* aPO
, bool aSetPixelScale
)
1985 // Here is where we set the shrinkage value into the DC
1986 // and this is what actually makes it shrink
1987 if (aSetPixelScale
&& aPO
->mFrameType
!= eIFrame
) {
1989 if (mPrt
->mPrintFrameType
== nsIPrintSettings::kFramesAsIs
|| mPrt
->mPrintFrameType
== nsIPrintSettings::kNoFrames
) {
1990 ratio
= mPrt
->mShrinkRatio
- 0.005f
; // round down
1992 ratio
= aPO
->mShrinkRatio
- 0.005f
; // round down
1994 aPO
->mZoomRatio
= ratio
;
1995 } else if (!mPrt
->mShrinkToFit
) {
1997 mPrt
->mPrintSettings
->GetScaling(&scaling
);
1998 aPO
->mZoomRatio
= float(scaling
);
2003 nsPrintEngine::UpdateSelectionAndShrinkPrintObject(nsPrintObject
* aPO
,
2004 bool aDocumentIsTopLevel
)
2006 nsCOMPtr
<nsIPresShell
> displayShell
= aPO
->mDocShell
->GetPresShell();
2007 // Transfer Selection Ranges to the new Print PresShell
2008 nsRefPtr
<Selection
> selection
, selectionPS
;
2009 // It's okay if there is no display shell, just skip copying the selection
2011 selection
= displayShell
->GetCurrentSelection(nsISelectionController::SELECTION_NORMAL
);
2013 selectionPS
= aPO
->mPresShell
->GetCurrentSelection(nsISelectionController::SELECTION_NORMAL
);
2015 // Reset all existing selection ranges that might have been added by calling
2016 // this function before.
2018 selectionPS
->RemoveAllRanges();
2020 if (selection
&& selectionPS
) {
2021 int32_t cnt
= selection
->GetRangeCount();
2023 for (inx
= 0; inx
< cnt
; ++inx
) {
2024 selectionPS
->AddRange(selection
->GetRangeAt(inx
));
2028 // If we are trying to shrink the contents to fit on the page
2029 // we must first locate the "pageContent" frame
2030 // Then we walk the frame tree and look for the "xmost" frame
2031 // this is the frame where the right-hand side of the frame extends
2033 if (mPrt
->mShrinkToFit
&& aDocumentIsTopLevel
) {
2034 nsIPageSequenceFrame
* pageSequence
= aPO
->mPresShell
->GetPageSequenceFrame();
2035 NS_ENSURE_STATE(pageSequence
);
2036 pageSequence
->GetSTFPercent(aPO
->mShrinkRatio
);
2037 // Limit the shrink-to-fit scaling for some text-ish type of documents.
2038 nsAutoString contentType
;
2039 aPO
->mPresShell
->GetDocument()->GetContentType(contentType
);
2040 if (contentType
.EqualsLiteral("application/xhtml+xml") ||
2041 StringBeginsWith(contentType
, NS_LITERAL_STRING("text/"))) {
2042 int32_t limitPercent
=
2043 Preferences::GetInt("print.shrink-to-fit.scale-limit-percent", 20);
2044 limitPercent
= std::max(0, limitPercent
);
2045 limitPercent
= std::min(100, limitPercent
);
2046 float minShrinkRatio
= float(limitPercent
) / 100;
2047 aPO
->mShrinkRatio
= std::max(aPO
->mShrinkRatio
, minShrinkRatio
);
2054 nsPrintEngine::DoSetPixelScale()
2056 // This is an Optimization
2057 // If we are in PP then we already know all the shrinkage information
2058 // so just transfer it to the PrintData and we will skip the extra shrinkage reflow
2060 // doSetPixelScale tells Reflow whether to set the shrinkage value into the DC
2061 // The first time we do not want to do this, the second time through we do
2062 bool doSetPixelScale
= false;
2063 bool ppIsShrinkToFit
= mPrtPreview
&& mPrtPreview
->mShrinkToFit
;
2064 if (ppIsShrinkToFit
) {
2065 mPrt
->mShrinkRatio
= mPrtPreview
->mShrinkRatio
;
2066 doSetPixelScale
= true;
2068 return doSetPixelScale
;
2072 nsPrintEngine::GetParentViewForRoot()
2074 if (mIsCreatingPrintPreview
) {
2075 nsCOMPtr
<nsIContentViewer
> cv
= do_QueryInterface(mDocViewerPrint
);
2077 return cv
->FindContainerView();
2084 nsPrintEngine::SetRootView(
2087 bool& documentIsTopLevel
,
2091 bool canCreateScrollbars
= true;
2094 nsView
* parentView
= nullptr;
2098 if (aPO
->mParent
&& aPO
->mParent
->IsPrintable()) {
2099 nsIFrame
* frame
= aPO
->mContent
? aPO
->mContent
->GetPrimaryFrame() : nullptr;
2100 // Without a frame, this document can't be displayed; therefore, there is no
2101 // point to reflowing it
2103 SetPrintPO(aPO
, false);
2108 //XXX If printing supported printing document hierarchies with non-constant
2109 // zoom this would be wrong as we use the same mPrt->mPrintDC for all
2111 adjSize
= frame
->GetContentRect().Size();
2112 documentIsTopLevel
= false;
2113 // presshell exists because parent is printable
2115 // the top nsPrintObject's widget will always have scrollbars
2116 if (frame
&& frame
->GetType() == nsGkAtoms::subDocumentFrame
) {
2117 nsView
* view
= frame
->GetView();
2118 NS_ENSURE_TRUE(view
, NS_ERROR_FAILURE
);
2119 view
= view
->GetFirstChild();
2120 NS_ENSURE_TRUE(view
, NS_ERROR_FAILURE
);
2122 canCreateScrollbars
= false;
2125 nscoord pageWidth
, pageHeight
;
2126 mPrt
->mPrintDC
->GetDeviceSurfaceDimensions(pageWidth
, pageHeight
);
2127 adjSize
= nsSize(pageWidth
, pageHeight
);
2128 documentIsTopLevel
= true;
2129 parentView
= GetParentViewForRoot();
2132 if (aPO
->mViewManager
->GetRootView()) {
2133 // Reuse the root view that is already on the root frame.
2134 rootView
= aPO
->mViewManager
->GetRootView();
2135 // Remove it from its existing parent if necessary
2136 aPO
->mViewManager
->RemoveChild(rootView
);
2137 rootView
->SetParent(parentView
);
2139 // Create a child window of the parent that is our "root view/window"
2140 nsRect tbounds
= nsRect(nsPoint(0, 0), adjSize
);
2141 rootView
= aPO
->mViewManager
->CreateView(tbounds
, parentView
);
2142 NS_ENSURE_TRUE(rootView
, NS_ERROR_OUT_OF_MEMORY
);
2145 if (mIsCreatingPrintPreview
&& documentIsTopLevel
) {
2146 aPO
->mPresContext
->SetPaginatedScrolling(canCreateScrollbars
);
2149 // Setup hierarchical relationship in view manager
2150 aPO
->mViewManager
->SetRootView(rootView
);
2155 // Reflow a nsPrintObject
2157 nsPrintEngine::ReflowPrintObject(nsPrintObject
* aPO
)
2159 NS_ENSURE_STATE(aPO
);
2161 if (!aPO
->IsPrintable()) {
2165 NS_ASSERTION(!aPO
->mPresContext
, "Recreating prescontext");
2167 // create the PresContext
2168 nsPresContext::nsPresContextType type
=
2169 mIsCreatingPrintPreview
? nsPresContext::eContext_PrintPreview
:
2170 nsPresContext::eContext_Print
;
2171 nsView
* parentView
=
2172 aPO
->mParent
&& aPO
->mParent
->IsPrintable() ? nullptr : GetParentViewForRoot();
2173 aPO
->mPresContext
= parentView
?
2174 new nsPresContext(aPO
->mDocument
, type
) :
2175 new nsRootPresContext(aPO
->mDocument
, type
);
2176 NS_ENSURE_TRUE(aPO
->mPresContext
, NS_ERROR_OUT_OF_MEMORY
);
2177 aPO
->mPresContext
->SetPrintSettings(mPrt
->mPrintSettings
);
2179 // set the presentation context to the value in the print settings
2181 mPrt
->mPrintSettings
->GetPrintBGColors(&printBGColors
);
2182 aPO
->mPresContext
->SetBackgroundColorDraw(printBGColors
);
2183 mPrt
->mPrintSettings
->GetPrintBGImages(&printBGColors
);
2184 aPO
->mPresContext
->SetBackgroundImageDraw(printBGColors
);
2186 // init it with the DC
2187 nsresult rv
= aPO
->mPresContext
->Init(mPrt
->mPrintDC
);
2188 NS_ENSURE_SUCCESS(rv
, rv
);
2190 aPO
->mViewManager
= new nsViewManager();
2192 rv
= aPO
->mViewManager
->Init(mPrt
->mPrintDC
);
2193 NS_ENSURE_SUCCESS(rv
,rv
);
2195 nsStyleSet
* styleSet
;
2196 rv
= mDocViewerPrint
->CreateStyleSet(aPO
->mDocument
, &styleSet
);
2197 NS_ENSURE_SUCCESS(rv
, rv
);
2199 aPO
->mPresShell
= aPO
->mDocument
->CreateShell(aPO
->mPresContext
,
2200 aPO
->mViewManager
, styleSet
);
2201 if (!aPO
->mPresShell
) {
2203 return NS_ERROR_FAILURE
;
2206 styleSet
->EndUpdate();
2208 // The pres shell now owns the style set object.
2211 bool doReturn
= false;;
2212 bool documentIsTopLevel
= false;
2215 rv
= SetRootView(aPO
, doReturn
, documentIsTopLevel
, adjSize
);
2217 if (NS_FAILED(rv
) || doReturn
) {
2221 PR_PL(("In DV::ReflowPrintObject PO: %p pS: %p (%9s) Setting w,h to %d,%d\n", aPO
, aPO
->mPresShell
.get(),
2222 gFrameTypesStr
[aPO
->mFrameType
], adjSize
.width
, adjSize
.height
));
2225 // This docshell stuff is weird; will go away when we stop having multiple
2226 // presentations per document
2227 aPO
->mPresContext
->SetContainer(aPO
->mDocShell
);
2229 aPO
->mPresShell
->BeginObservingDocument();
2231 aPO
->mPresContext
->SetPageSize(adjSize
);
2232 aPO
->mPresContext
->SetIsRootPaginatedDocument(documentIsTopLevel
);
2233 aPO
->mPresContext
->SetPageScale(aPO
->mZoomRatio
);
2234 // Calculate scale factor from printer to screen
2235 float printDPI
= float(mPrt
->mPrintDC
->AppUnitsPerCSSInch()) /
2236 float(mPrt
->mPrintDC
->AppUnitsPerDevPixel());
2237 aPO
->mPresContext
->SetPrintPreviewScale(mScreenDPI
/ printDPI
);
2239 if (mIsCreatingPrintPreview
&& documentIsTopLevel
) {
2240 mDocViewerPrint
->SetPrintPreviewPresentation(aPO
->mViewManager
,
2245 rv
= aPO
->mPresShell
->Initialize(adjSize
.width
, adjSize
.height
);
2247 NS_ENSURE_SUCCESS(rv
, rv
);
2248 NS_ASSERTION(aPO
->mPresShell
, "Presshell should still be here");
2250 // Process the reflow event Initialize posted
2251 aPO
->mPresShell
->FlushPendingNotifications(Flush_Layout
);
2253 rv
= UpdateSelectionAndShrinkPrintObject(aPO
, documentIsTopLevel
);
2254 NS_ENSURE_SUCCESS(rv
, rv
);
2256 #ifdef EXTENDED_DEBUG_PRINTING
2257 if (kPrintingLogMod
&& kPrintingLogMod
->level
== DUMP_LAYOUT_LEVEL
) {
2258 nsAutoCString docStr
;
2259 nsAutoCString urlStr
;
2260 GetDocTitleAndURL(aPO
, docStr
, urlStr
);
2262 sprintf(filename
, "print_dump_%d.txt", gDumpFileNameCnt
++);
2263 // Dump all the frames and view to a a file
2264 FILE * fd
= fopen(filename
, "w");
2266 nsIFrame
*theRootFrame
=
2267 aPO
->mPresShell
->FrameManager()->GetRootFrame();
2268 fprintf(fd
, "Title: %s\n", docStr
.get());
2269 fprintf(fd
, "URL: %s\n", urlStr
.get());
2270 fprintf(fd
, "--------------- Frames ----------------\n");
2271 nsRefPtr
<nsRenderingContext
> renderingContext
=
2272 mPrt
->mPrintDocDC
->CreateRenderingContext();
2273 RootFrameList(aPO
->mPresContext
, fd
, 0);
2274 //DumpFrames(fd, aPO->mPresContext, renderingContext, theRootFrame, 0);
2275 fprintf(fd
, "---------------------------------------\n\n");
2276 fprintf(fd
, "--------------- Views From Root Frame----------------\n");
2277 nsView
* v
= theRootFrame
->GetView();
2281 printf("View is null!\n");
2284 fprintf(fd
, "--------------- All Views ----------------\n");
2285 DumpViews(docShell
, fd
);
2286 fprintf(fd
, "---------------------------------------\n\n");
2296 //-------------------------------------------------------
2297 // Figure out how many documents and how many total pages we are printing
2299 nsPrintEngine::CalcNumPrintablePages(int32_t& aNumPages
)
2302 // Count the number of printable documents
2303 // and printable pages
2304 for (uint32_t i
=0; i
<mPrt
->mPrintDocList
.Length(); i
++) {
2305 nsPrintObject
* po
= mPrt
->mPrintDocList
.ElementAt(i
);
2306 NS_ASSERTION(po
, "nsPrintObject can't be null!");
2307 if (po
->mPresContext
&& po
->mPresContext
->IsRootPaginatedDocument()) {
2308 nsIPageSequenceFrame
* pageSequence
= po
->mPresShell
->GetPageSequenceFrame();
2309 nsIFrame
* seqFrame
= do_QueryFrame(pageSequence
);
2311 nsIFrame
* frame
= seqFrame
->GetFirstPrincipalChild();
2314 frame
= frame
->GetNextSibling();
2321 //-----------------------------------------------------------------
2322 //-- Done: Reflow Methods
2323 //-----------------------------------------------------------------
2325 //-----------------------------------------------------------------
2326 //-- Section: Printing Methods
2327 //-----------------------------------------------------------------
2329 //-------------------------------------------------------
2330 // Called for each DocShell that needs to be printed
2332 nsPrintEngine::PrintDocContent(nsPrintObject
* aPO
, nsresult
& aStatus
)
2334 NS_ASSERTION(aPO
, "Pointer is null!");
2337 if (!aPO
->mHasBeenPrinted
&& aPO
->IsPrintable()) {
2338 aStatus
= DoPrint(aPO
);
2342 // If |aPO->mPrintAsIs| and |aPO->mHasBeenPrinted| are true,
2343 // the kids frames are already processed in |PrintPage|.
2344 if (!aPO
->mInvisible
&& !(aPO
->mPrintAsIs
&& aPO
->mHasBeenPrinted
)) {
2345 for (uint32_t i
=0;i
<aPO
->mKids
.Length();i
++) {
2346 nsPrintObject
* po
= aPO
->mKids
[i
];
2347 bool printed
= PrintDocContent(po
, aStatus
);
2348 if (printed
|| NS_FAILED(aStatus
)) {
2356 static already_AddRefed
<nsIDOMNode
>
2357 GetEqualNodeInCloneTree(nsIDOMNode
* aNode
, nsIDocument
* aDoc
)
2359 nsCOMPtr
<nsIContent
> content
= do_QueryInterface(aNode
);
2360 // Selections in anonymous subtrees aren't supported.
2361 if (content
&& content
->IsInAnonymousSubtree()) {
2365 nsCOMPtr
<nsINode
> node
= do_QueryInterface(aNode
);
2366 NS_ENSURE_TRUE(node
, nullptr);
2368 nsTArray
<int32_t> indexArray
;
2369 nsINode
* current
= node
;
2370 NS_ENSURE_TRUE(current
, nullptr);
2372 nsINode
* parent
= current
->GetParentNode();
2376 int32_t index
= parent
->IndexOf(current
);
2377 NS_ENSURE_TRUE(index
>= 0, nullptr);
2378 indexArray
.AppendElement(index
);
2381 NS_ENSURE_TRUE(current
->IsNodeOfType(nsINode::eDOCUMENT
), nullptr);
2384 for (int32_t i
= indexArray
.Length() - 1; i
>= 0; --i
) {
2385 current
= current
->GetChildAt(indexArray
[i
]);
2386 NS_ENSURE_TRUE(current
, nullptr);
2388 nsCOMPtr
<nsIDOMNode
> result
= do_QueryInterface(current
);
2389 return result
.forget();
2393 CloneRangeToSelection(nsRange
* aRange
, nsIDocument
* aDoc
,
2394 Selection
* aSelection
)
2396 if (aRange
->Collapsed()) {
2400 nsCOMPtr
<nsIDOMNode
> startContainer
, endContainer
;
2401 aRange
->GetStartContainer(getter_AddRefs(startContainer
));
2402 int32_t startOffset
= aRange
->StartOffset();
2403 aRange
->GetEndContainer(getter_AddRefs(endContainer
));
2404 int32_t endOffset
= aRange
->EndOffset();
2405 NS_ENSURE_TRUE_VOID(startContainer
&& endContainer
);
2407 nsCOMPtr
<nsIDOMNode
> newStart
= GetEqualNodeInCloneTree(startContainer
, aDoc
);
2408 nsCOMPtr
<nsIDOMNode
> newEnd
= GetEqualNodeInCloneTree(endContainer
, aDoc
);
2409 NS_ENSURE_TRUE_VOID(newStart
&& newEnd
);
2411 nsCOMPtr
<nsINode
> newStartNode
= do_QueryInterface(newStart
);
2412 NS_ENSURE_TRUE_VOID(newStartNode
);
2414 nsRefPtr
<nsRange
> range
= new nsRange(newStartNode
);
2415 nsresult rv
= range
->SetStart(newStartNode
, startOffset
);
2416 NS_ENSURE_SUCCESS_VOID(rv
);
2417 rv
= range
->SetEnd(newEnd
, endOffset
);
2418 NS_ENSURE_SUCCESS_VOID(rv
);
2420 aSelection
->AddRange(range
);
2423 static nsresult
CloneSelection(nsIDocument
* aOrigDoc
, nsIDocument
* aDoc
)
2425 nsIPresShell
* origShell
= aOrigDoc
->GetShell();
2426 nsIPresShell
* shell
= aDoc
->GetShell();
2427 NS_ENSURE_STATE(origShell
&& shell
);
2429 nsRefPtr
<Selection
> origSelection
=
2430 origShell
->GetCurrentSelection(nsISelectionController::SELECTION_NORMAL
);
2431 nsRefPtr
<Selection
> selection
=
2432 shell
->GetCurrentSelection(nsISelectionController::SELECTION_NORMAL
);
2433 NS_ENSURE_STATE(origSelection
&& selection
);
2435 int32_t rangeCount
= origSelection
->GetRangeCount();
2436 for (int32_t i
= 0; i
< rangeCount
; ++i
) {
2437 CloneRangeToSelection(origSelection
->GetRangeAt(i
), aDoc
, selection
);
2442 //-------------------------------------------------------
2444 nsPrintEngine::DoPrint(nsPrintObject
* aPO
)
2447 PR_PL(("**************************** %s ****************************\n", gFrameTypesStr
[aPO
->mFrameType
]));
2448 PR_PL(("****** In DV::DoPrint PO: %p \n", aPO
));
2450 nsIPresShell
* poPresShell
= aPO
->mPresShell
;
2451 nsPresContext
* poPresContext
= aPO
->mPresContext
;
2453 NS_ASSERTION(poPresContext
, "PrintObject has not been reflowed");
2454 NS_ASSERTION(poPresContext
->Type() != nsPresContext::eContext_PrintPreview
,
2455 "How did this context end up here?");
2457 if (mPrt
->mPrintProgressParams
) {
2458 SetDocAndURLIntoProgress(aPO
, mPrt
->mPrintProgressParams
);
2462 int16_t printRangeType
= nsIPrintSettings::kRangeAllPages
;
2464 if (mPrt
->mPrintSettings
!= nullptr) {
2465 mPrt
->mPrintSettings
->GetPrintRange(&printRangeType
);
2468 // Ask the page sequence frame to print all the pages
2469 nsIPageSequenceFrame
* pageSequence
= poPresShell
->GetPageSequenceFrame();
2470 NS_ASSERTION(nullptr != pageSequence
, "no page sequence frame");
2472 // We are done preparing for printing, so we can turn this off
2473 mPrt
->mPreparingForPrint
= false;
2475 // mPrt->mDebugFilePtr this is onlu non-null when compiled for debugging
2476 if (nullptr != mPrt
->mDebugFilePtr
) {
2478 // output the regression test
2479 nsIFrame
* root
= poPresShell
->FrameManager()->GetRootFrame();
2480 root
->DumpRegressionData(poPresContext
, mPrt
->mDebugFilePtr
, 0);
2481 fclose(mPrt
->mDebugFilePtr
);
2482 SetIsPrinting(false);
2485 #ifdef EXTENDED_DEBUG_PRINTING
2486 nsIFrame
* rootFrame
= poPresShell
->FrameManager()->GetRootFrame();
2487 if (aPO
->IsPrintable()) {
2488 nsAutoCString docStr
;
2489 nsAutoCString urlStr
;
2490 GetDocTitleAndURL(aPO
, docStr
, urlStr
);
2491 DumpLayoutData(docStr
.get(), urlStr
.get(), poPresContext
, mPrt
->mPrintDocDC
, rootFrame
, docShell
, nullptr);
2495 if (!mPrt
->mPrintSettings
) {
2496 // not sure what to do here!
2497 SetIsPrinting(false);
2498 return NS_ERROR_FAILURE
;
2501 nsAutoString docTitleStr
;
2502 nsAutoString docURLStr
;
2503 GetDisplayTitleAndURL(aPO
, docTitleStr
, docURLStr
, eDocTitleDefBlank
);
2505 if (nsIPrintSettings::kRangeSelection
== printRangeType
) {
2506 CloneSelection(aPO
->mDocument
->GetOriginalDocument(), aPO
->mDocument
);
2508 poPresContext
->SetIsRenderingOnlySelection(true);
2509 // temporarily creating rendering context
2510 // which is needed to find the selection frames
2511 nsRefPtr
<nsRenderingContext
> rc
=
2512 mPrt
->mPrintDC
->CreateRenderingContext();
2514 // find the starting and ending page numbers
2515 // via the selection
2516 nsIFrame
* startFrame
;
2518 int32_t startPageNum
;
2523 nsRefPtr
<Selection
> selectionPS
=
2524 poPresShell
->GetCurrentSelection(nsISelectionController::SELECTION_NORMAL
);
2526 rv
= GetPageRangeForSelection(poPresShell
, poPresContext
, *rc
, selectionPS
, pageSequence
,
2527 &startFrame
, startPageNum
, startRect
,
2528 &endFrame
, endPageNum
, endRect
);
2529 if (NS_SUCCEEDED(rv
)) {
2530 mPrt
->mPrintSettings
->SetStartPageRange(startPageNum
);
2531 mPrt
->mPrintSettings
->SetEndPageRange(endPageNum
);
2532 nsIntMargin
marginTwips(0,0,0,0);
2533 nsIntMargin
unwrtMarginTwips(0,0,0,0);
2534 mPrt
->mPrintSettings
->GetMarginInTwips(marginTwips
);
2535 mPrt
->mPrintSettings
->GetUnwriteableMarginInTwips(unwrtMarginTwips
);
2536 nsMargin totalMargin
= poPresContext
->CSSTwipsToAppUnits(marginTwips
+
2538 if (startPageNum
== endPageNum
) {
2539 startRect
.y
-= totalMargin
.top
;
2540 endRect
.y
-= totalMargin
.top
;
2542 // Clip out selection regions above the top of the first page
2543 if (startRect
.y
< 0) {
2544 // Reduce height to be the height of the positive-territory
2545 // region of original rect
2546 startRect
.height
= std::max(0, startRect
.YMost());
2549 if (endRect
.y
< 0) {
2550 // Reduce height to be the height of the positive-territory
2551 // region of original rect
2552 endRect
.height
= std::max(0, endRect
.YMost());
2555 NS_ASSERTION(endRect
.y
>= startRect
.y
,
2556 "Selection end point should be after start point");
2557 NS_ASSERTION(startRect
.height
>= 0,
2558 "rect should have non-negative height.");
2559 NS_ASSERTION(endRect
.height
>= 0,
2560 "rect should have non-negative height.");
2562 nscoord selectionHgt
= endRect
.y
+ endRect
.height
- startRect
.y
;
2563 // XXX This is temporary fix for printing more than one page of a selection
2564 pageSequence
->SetSelectionHeight(startRect
.y
* aPO
->mZoomRatio
,
2565 selectionHgt
* aPO
->mZoomRatio
);
2567 // calc total pages by getting calculating the selection's height
2568 // and then dividing it by how page content frames will fit.
2569 nscoord pageWidth
, pageHeight
;
2570 mPrt
->mPrintDC
->GetDeviceSurfaceDimensions(pageWidth
, pageHeight
);
2571 pageHeight
-= totalMargin
.top
+ totalMargin
.bottom
;
2572 int32_t totalPages
= NSToIntCeil(float(selectionHgt
) * aPO
->mZoomRatio
/ float(pageHeight
));
2573 pageSequence
->SetTotalNumPages(totalPages
);
2578 nsIFrame
* seqFrame
= do_QueryFrame(pageSequence
);
2580 SetIsPrinting(false);
2581 return NS_ERROR_FAILURE
;
2584 mPageSeqFrame
= pageSequence
;
2585 mPageSeqFrame
->StartPrint(poPresContext
, mPrt
->mPrintSettings
, docTitleStr
, docURLStr
);
2587 // Schedule Page to Print
2588 PR_PL(("Scheduling Print of PO: %p (%s) \n", aPO
, gFrameTypesStr
[aPO
->mFrameType
]));
2589 StartPagePrintTimer(aPO
);
2596 //---------------------------------------------------------------------
2598 nsPrintEngine::SetDocAndURLIntoProgress(nsPrintObject
* aPO
,
2599 nsIPrintProgressParams
* aParams
)
2601 NS_ASSERTION(aPO
, "Must have valid nsPrintObject");
2602 NS_ASSERTION(aParams
, "Must have valid nsIPrintProgressParams");
2604 if (!aPO
|| !aPO
->mDocShell
|| !aParams
) {
2607 const uint32_t kTitleLength
= 64;
2609 nsAutoString docTitleStr
;
2610 nsAutoString docURLStr
;
2611 GetDisplayTitleAndURL(aPO
, docTitleStr
, docURLStr
, eDocTitleDefURLDoc
);
2613 // Make sure the Titles & URLS don't get too long for the progress dialog
2614 EllipseLongString(docTitleStr
, kTitleLength
, false);
2615 EllipseLongString(docURLStr
, kTitleLength
, true);
2617 aParams
->SetDocTitle(docTitleStr
.get());
2618 aParams
->SetDocURL(docURLStr
.get());
2621 //---------------------------------------------------------------------
2623 nsPrintEngine::EllipseLongString(nsAString
& aStr
, const uint32_t aLen
, bool aDoFront
)
2625 // Make sure the URLS don't get too long for the progress dialog
2626 if (aLen
>= 3 && aStr
.Length() > aLen
) {
2628 nsAutoString newStr
;
2629 newStr
.AppendLiteral("...");
2630 newStr
+= Substring(aStr
, aStr
.Length() - (aLen
- 3), aLen
- 3);
2633 aStr
.SetLength(aLen
- 3);
2634 aStr
.AppendLiteral("...");
2640 DocHasPrintCallbackCanvas(nsIDocument
* aDoc
, void* aData
)
2645 Element
* root
= aDoc
->GetRootElement();
2649 nsRefPtr
<nsContentList
> canvases
= NS_GetContentList(root
,
2651 NS_LITERAL_STRING("canvas"));
2652 uint32_t canvasCount
= canvases
->Length(true);
2653 for (uint32_t i
= 0; i
< canvasCount
; ++i
) {
2654 HTMLCanvasElement
* canvas
= HTMLCanvasElement::FromContentOrNull(canvases
->Item(i
, false));
2655 if (canvas
&& canvas
->GetMozPrintCallback()) {
2656 // This subdocument has a print callback. Set result and return false to
2658 *static_cast<bool*>(aData
) = true;
2666 DocHasPrintCallbackCanvas(nsIDocument
* aDoc
)
2668 bool result
= false;
2669 aDoc
->EnumerateSubDocuments(&DocHasPrintCallbackCanvas
, static_cast<void*>(&result
));
2674 * Checks to see if the document this print engine is associated with has any
2675 * canvases that have a mozPrintCallback.
2678 nsPrintEngine::HasPrintCallbackCanvas()
2683 // First check this mDocument.
2684 bool result
= false;
2685 DocHasPrintCallbackCanvas(mDocument
, static_cast<void*>(&result
));
2686 // Also check the sub documents.
2687 return result
|| DocHasPrintCallbackCanvas(mDocument
);
2690 //-------------------------------------------------------
2692 nsPrintEngine::PrePrintPage()
2694 NS_ASSERTION(mPageSeqFrame
, "mPageSeqFrame is null!");
2695 NS_ASSERTION(mPrt
, "mPrt is null!");
2697 // Although these should NEVER be nullptr
2698 // This is added insurance, to make sure we don't crash in optimized builds
2699 if (!mPrt
|| !mPageSeqFrame
) {
2700 return true; // means we are done preparing the page.
2703 // Check setting to see if someone request it be cancelled
2704 bool isCancelled
= false;
2705 mPrt
->mPrintSettings
->GetIsCancelled(&isCancelled
);
2709 // Ask mPageSeqFrame if the page is ready to be printed.
2710 // If the page doesn't get printed at all, the |done| will be |true|.
2712 nsresult rv
= mPageSeqFrame
->PrePrintNextPage(mPagePrintTimer
, &done
);
2713 if (NS_FAILED(rv
)) {
2714 // ??? ::PrintPage doesn't set |mPrt->mIsAborted = true| if rv != NS_ERROR_ABORT,
2715 // but I don't really understand why this should be the right thing to do?
2716 // Shouldn't |mPrt->mIsAborted| set to true all the time if something
2718 if (rv
!= NS_ERROR_ABORT
) {
2719 ShowPrintErrorDialog(rv
);
2720 mPrt
->mIsAborted
= true;
2728 nsPrintEngine::PrintPage(nsPrintObject
* aPO
,
2731 NS_ASSERTION(aPO
, "aPO is null!");
2732 NS_ASSERTION(mPageSeqFrame
, "mPageSeqFrame is null!");
2733 NS_ASSERTION(mPrt
, "mPrt is null!");
2735 // Although these should NEVER be nullptr
2736 // This is added insurance, to make sure we don't crash in optimized builds
2737 if (!mPrt
|| !aPO
|| !mPageSeqFrame
) {
2738 ShowPrintErrorDialog(NS_ERROR_FAILURE
);
2739 return true; // means we are done printing
2742 PR_PL(("-----------------------------------\n"));
2743 PR_PL(("------ In DV::PrintPage PO: %p (%s)\n", aPO
, gFrameTypesStr
[aPO
->mFrameType
]));
2745 // Check setting to see if someone request it be cancelled
2746 bool isCancelled
= false;
2747 mPrt
->mPrintSettings
->GetIsCancelled(&isCancelled
);
2748 if (isCancelled
|| mPrt
->mIsAborted
)
2751 int32_t pageNum
, numPages
, endPage
;
2752 mPageSeqFrame
->GetCurrentPageNum(&pageNum
);
2753 mPageSeqFrame
->GetNumPages(&numPages
);
2756 bool isDoingPrintRange
;
2757 mPageSeqFrame
->IsDoingPrintRange(&isDoingPrintRange
);
2758 if (isDoingPrintRange
) {
2761 mPageSeqFrame
->GetPrintRange(&fromPage
, &toPage
);
2763 if (fromPage
> numPages
) {
2766 if (toPage
> numPages
) {
2770 PR_PL(("****** Printing Page %d printing from %d to page %d\n", pageNum
, fromPage
, toPage
));
2772 donePrinting
= pageNum
>= toPage
;
2773 aInRange
= pageNum
>= fromPage
&& pageNum
<= toPage
;
2774 endPage
= (toPage
- fromPage
)+1;
2776 PR_PL(("****** Printing Page %d of %d page(s)\n", pageNum
, numPages
));
2778 donePrinting
= pageNum
>= numPages
;
2783 // XXX This is wrong, but the actual behavior in the presence of a print
2785 if (mPrt
->mPrintFrameType
== nsIPrintSettings::kEachFrameSep
)
2786 endPage
= mPrt
->mNumPrintablePages
;
2788 mPrt
->DoOnProgressChange(++mPrt
->mNumPagesPrinted
, endPage
, false, 0);
2791 // if a print job was cancelled externally, an EndPage or BeginPage may
2792 // fail and the failure is passed back here.
2793 // Returning true means we are done printing.
2795 // When rv == NS_ERROR_ABORT, it means we want out of the
2796 // print job without displaying any error messages
2797 nsresult rv
= mPageSeqFrame
->PrintNextPage();
2798 if (NS_FAILED(rv
)) {
2799 if (rv
!= NS_ERROR_ABORT
) {
2800 ShowPrintErrorDialog(rv
);
2801 mPrt
->mIsAborted
= true;
2806 mPageSeqFrame
->DoPageEnd();
2808 return donePrinting
;
2811 /** ---------------------------------------------------
2812 * Find by checking frames type
2815 nsPrintEngine::FindSelectionBoundsWithList(nsPresContext
* aPresContext
,
2816 nsRenderingContext
& aRC
,
2817 nsFrameList::Enumerator
& aChildFrames
,
2818 nsIFrame
* aParentFrame
,
2820 nsIFrame
*& aStartFrame
,
2822 nsIFrame
*& aEndFrame
,
2825 NS_ASSERTION(aPresContext
, "Pointer is null!");
2826 NS_ASSERTION(aParentFrame
, "Pointer is null!");
2828 aRect
+= aParentFrame
->GetPosition();
2829 for (; !aChildFrames
.AtEnd(); aChildFrames
.Next()) {
2830 nsIFrame
* child
= aChildFrames
.get();
2831 if (child
->IsSelected() && child
->IsVisibleForPainting()) {
2832 nsRect r
= child
->GetRect();
2833 if (aStartFrame
== nullptr) {
2834 aStartFrame
= child
;
2835 aStartRect
.SetRect(aRect
.x
+ r
.x
, aRect
.y
+ r
.y
, r
.width
, r
.height
);
2838 aEndRect
.SetRect(aRect
.x
+ r
.x
, aRect
.y
+ r
.y
, r
.width
, r
.height
);
2841 FindSelectionBounds(aPresContext
, aRC
, child
, aRect
, aStartFrame
, aStartRect
, aEndFrame
, aEndRect
);
2842 child
= child
->GetNextSibling();
2844 aRect
-= aParentFrame
->GetPosition();
2848 //-------------------------------------------------------
2849 // Find the Frame that is XMost
2851 nsPrintEngine::FindSelectionBounds(nsPresContext
* aPresContext
,
2852 nsRenderingContext
& aRC
,
2853 nsIFrame
* aParentFrame
,
2855 nsIFrame
*& aStartFrame
,
2857 nsIFrame
*& aEndFrame
,
2860 NS_ASSERTION(aPresContext
, "Pointer is null!");
2861 NS_ASSERTION(aParentFrame
, "Pointer is null!");
2863 // loop through named child lists
2864 nsIFrame::ChildListIterator
lists(aParentFrame
);
2865 for (; !lists
.IsDone(); lists
.Next()) {
2866 nsFrameList::Enumerator
childFrames(lists
.CurrentList());
2867 nsresult rv
= FindSelectionBoundsWithList(aPresContext
, aRC
, childFrames
, aParentFrame
, aRect
, aStartFrame
, aStartRect
, aEndFrame
, aEndRect
);
2868 NS_ENSURE_SUCCESS(rv
, rv
);
2873 /** ---------------------------------------------------
2874 * This method finds the starting and ending page numbers
2875 * of the selection and also returns rect for each where
2876 * the x,y of the rect is relative to the very top of the
2877 * frame tree (absolutely positioned)
2880 nsPrintEngine::GetPageRangeForSelection(nsIPresShell
* aPresShell
,
2881 nsPresContext
* aPresContext
,
2882 nsRenderingContext
& aRC
,
2883 nsISelection
* aSelection
,
2884 nsIPageSequenceFrame
* aPageSeqFrame
,
2885 nsIFrame
** aStartFrame
,
2886 int32_t& aStartPageNum
,
2888 nsIFrame
** aEndFrame
,
2889 int32_t& aEndPageNum
,
2892 NS_ASSERTION(aPresShell
, "Pointer is null!");
2893 NS_ASSERTION(aPresContext
, "Pointer is null!");
2894 NS_ASSERTION(aSelection
, "Pointer is null!");
2895 NS_ASSERTION(aPageSeqFrame
, "Pointer is null!");
2896 NS_ASSERTION(aStartFrame
, "Pointer is null!");
2897 NS_ASSERTION(aEndFrame
, "Pointer is null!");
2899 nsIFrame
* seqFrame
= do_QueryFrame(aPageSeqFrame
);
2901 return NS_ERROR_FAILURE
;
2904 nsIFrame
* startFrame
= nullptr;
2905 nsIFrame
* endFrame
= nullptr;
2907 // start out with the sequence frame and search the entire frame tree
2908 // capturing the starting and ending child frames of the selection
2910 nsRect r
= seqFrame
->GetRect();
2911 FindSelectionBounds(aPresContext
, aRC
, seqFrame
, r
,
2912 startFrame
, aStartRect
, endFrame
, aEndRect
);
2915 printf("Start Frame: %p\n", startFrame
);
2916 printf("End Frame: %p\n", endFrame
);
2919 // initial the page numbers here
2920 // in case we don't find and frames
2924 nsIFrame
* startPageFrame
;
2925 nsIFrame
* endPageFrame
;
2927 // check to make sure we found a starting frame
2928 if (startFrame
!= nullptr) {
2929 // Now search up the tree to find what page the
2930 // start/ending selections frames are on
2932 // Check to see if start should be same as end if
2933 // the end frame comes back null
2934 if (endFrame
== nullptr) {
2935 // XXX the "GetPageFrame" step could be integrated into
2936 // the FindSelectionBounds step, but walking up to find
2937 // the parent of a child frame isn't expensive and it makes
2938 // FindSelectionBounds a little easier to understand
2939 startPageFrame
= nsLayoutUtils::GetPageFrame(startFrame
);
2940 endPageFrame
= startPageFrame
;
2941 aEndRect
= aStartRect
;
2943 startPageFrame
= nsLayoutUtils::GetPageFrame(startFrame
);
2944 endPageFrame
= nsLayoutUtils::GetPageFrame(endFrame
);
2947 return NS_ERROR_FAILURE
;
2951 printf("Start Page: %p\n", startPageFrame
);
2952 printf("End Page: %p\n", endPageFrame
);
2954 // dump all the pages and their pointers
2956 int32_t pageNum
= 1;
2957 nsIFrame
* child
= seqFrame
->GetFirstPrincipalChild();
2958 while (child
!= nullptr) {
2959 printf("Page: %d - %p\n", pageNum
, child
);
2961 child
= child
->GetNextSibling();
2966 // Now that we have the page frames
2967 // find out what the page numbers are for each frame
2968 int32_t pageNum
= 1;
2969 nsIFrame
* page
= seqFrame
->GetFirstPrincipalChild();
2970 while (page
!= nullptr) {
2971 if (page
== startPageFrame
) {
2972 aStartPageNum
= pageNum
;
2974 if (page
== endPageFrame
) {
2975 aEndPageNum
= pageNum
;
2978 page
= page
->GetNextSibling();
2982 printf("Start Page No: %d\n", aStartPageNum
);
2983 printf("End Page No: %d\n", aEndPageNum
);
2986 *aStartFrame
= startPageFrame
;
2987 *aEndFrame
= endPageFrame
;
2992 //-----------------------------------------------------------------
2993 //-- Done: Printing Methods
2994 //-----------------------------------------------------------------
2997 //-----------------------------------------------------------------
2998 //-- Section: Misc Support Methods
2999 //-----------------------------------------------------------------
3001 //---------------------------------------------------------------------
3002 void nsPrintEngine::SetIsPrinting(bool aIsPrinting
)
3004 mIsDoingPrinting
= aIsPrinting
;
3005 // Calling SetIsPrinting while in print preview confuses the document viewer
3006 // This is safe because we prevent exiting print preview while printing
3007 if (!mIsDoingPrintPreview
&& mDocViewerPrint
) {
3008 mDocViewerPrint
->SetIsPrinting(aIsPrinting
);
3010 if (mPrt
&& aIsPrinting
) {
3011 mPrt
->mPreparingForPrint
= true;
3015 //---------------------------------------------------------------------
3016 void nsPrintEngine::SetIsPrintPreview(bool aIsPrintPreview
)
3018 mIsDoingPrintPreview
= aIsPrintPreview
;
3020 if (mDocViewerPrint
) {
3021 mDocViewerPrint
->SetIsPrintPreview(aIsPrintPreview
);
3025 //---------------------------------------------------------------------
3027 nsPrintEngine::CleanupDocTitleArray(char16_t
**& aArray
, int32_t& aCount
)
3029 for (int32_t i
= aCount
- 1; i
>= 0; i
--) {
3030 nsMemory::Free(aArray
[i
]);
3032 nsMemory::Free(aArray
);
3037 //---------------------------------------------------------------------
3039 bool nsPrintEngine::HasFramesetChild(nsIContent
* aContent
)
3045 // do a breadth search across all siblings
3046 for (nsIContent
* child
= aContent
->GetFirstChild();
3048 child
= child
->GetNextSibling()) {
3049 if (child
->IsHTML(nsGkAtoms::frameset
)) {
3059 /** ---------------------------------------------------
3060 * Get the Focused Frame for a documentviewer
3062 already_AddRefed
<nsIDOMWindow
>
3063 nsPrintEngine::FindFocusedDOMWindow()
3065 nsIFocusManager
* fm
= nsFocusManager::GetFocusManager();
3066 NS_ENSURE_TRUE(fm
, nullptr);
3068 nsCOMPtr
<nsPIDOMWindow
> window(mDocument
->GetWindow());
3069 NS_ENSURE_TRUE(window
, nullptr);
3071 nsCOMPtr
<nsPIDOMWindow
> rootWindow
= window
->GetPrivateRoot();
3072 NS_ENSURE_TRUE(rootWindow
, nullptr);
3074 nsCOMPtr
<nsPIDOMWindow
> focusedWindow
;
3075 nsFocusManager::GetFocusedDescendant(rootWindow
, true,
3076 getter_AddRefs(focusedWindow
));
3077 NS_ENSURE_TRUE(focusedWindow
, nullptr);
3079 if (IsWindowsInOurSubTree(focusedWindow
)) {
3080 return focusedWindow
.forget();
3086 //---------------------------------------------------------------------
3088 nsPrintEngine::IsWindowsInOurSubTree(nsPIDOMWindow
* window
)
3092 // now check to make sure it is in "our" tree of docshells
3094 nsCOMPtr
<nsIDocShell
> docShell
= window
->GetDocShell();
3097 // get this DocViewer docshell
3098 nsCOMPtr
<nsIDocShell
> thisDVDocShell(do_QueryReferent(mContainer
));
3101 if (docShell
== thisDVDocShell
) {
3106 break; // at top of tree
3108 nsCOMPtr
<nsIDocShellTreeItem
> docShellItemParent
;
3109 docShell
->GetSameTypeParent(getter_AddRefs(docShellItemParent
));
3110 docShell
= do_QueryInterface(docShellItemParent
);
3118 //-------------------------------------------------------
3120 nsPrintEngine::DonePrintingPages(nsPrintObject
* aPO
, nsresult aResult
)
3122 //NS_ASSERTION(aPO, "Pointer is null!");
3123 PR_PL(("****** In DV::DonePrintingPages PO: %p (%s)\n", aPO
, aPO
?gFrameTypesStr
[aPO
->mFrameType
]:""));
3125 // If there is a pageSeqFrame, make sure there are no more printCanvas active
3126 // that might call |Notify| on the pagePrintTimer after things are cleaned up
3127 // and printing was marked as being done.
3128 if (mPageSeqFrame
) {
3129 mPageSeqFrame
->ResetPrintCanvasList();
3132 if (aPO
&& !mPrt
->mIsAborted
) {
3133 aPO
->mHasBeenPrinted
= true;
3135 bool didPrint
= PrintDocContent(mPrt
->mPrintObject
, rv
);
3136 if (NS_SUCCEEDED(rv
) && didPrint
) {
3137 PR_PL(("****** In DV::DonePrintingPages PO: %p (%s) didPrint:%s (Not Done Printing)\n", aPO
, gFrameTypesStr
[aPO
->mFrameType
], PRT_YESNO(didPrint
)));
3142 if (NS_SUCCEEDED(aResult
)) {
3143 FirePrintCompletionEvent();
3146 TurnScriptingOn(true);
3147 SetIsPrinting(false);
3149 // Release reference to mPagePrintTimer; the timer object destroys itself
3150 // after this returns true
3151 NS_IF_RELEASE(mPagePrintTimer
);
3156 //-------------------------------------------------------
3157 // Recursively sets the PO items to be printed "As Is"
3158 // from the given item down into the tree
3160 nsPrintEngine::SetPrintAsIs(nsPrintObject
* aPO
, bool aAsIs
)
3162 NS_ASSERTION(aPO
, "Pointer is null!");
3164 aPO
->mPrintAsIs
= aAsIs
;
3165 for (uint32_t i
=0;i
<aPO
->mKids
.Length();i
++) {
3166 SetPrintAsIs(aPO
->mKids
[i
], aAsIs
);
3170 //-------------------------------------------------------
3171 // Given a DOMWindow it recursively finds the PO object that matches
3173 nsPrintEngine::FindPrintObjectByDOMWin(nsPrintObject
* aPO
,
3174 nsIDOMWindow
* aDOMWin
)
3176 NS_ASSERTION(aPO
, "Pointer is null!");
3178 // Often the CurFocused DOMWindow is passed in
3179 // andit is valid for it to be null, so short circut
3184 nsCOMPtr
<nsIDOMDocument
> domDoc
;
3185 aDOMWin
->GetDocument(getter_AddRefs(domDoc
));
3186 nsCOMPtr
<nsIDocument
> doc
= do_QueryInterface(domDoc
);
3187 if (aPO
->mDocument
&& aPO
->mDocument
->GetOriginalDocument() == doc
) {
3191 int32_t cnt
= aPO
->mKids
.Length();
3192 for (int32_t i
= 0; i
< cnt
; ++i
) {
3193 nsPrintObject
* po
= FindPrintObjectByDOMWin(aPO
->mKids
[i
], aDOMWin
);
3202 //-------------------------------------------------------
3204 nsPrintEngine::EnablePOsForPrinting()
3206 // NOTE: All POs have been "turned off" for printing
3207 // this is where we decided which POs get printed.
3208 mPrt
->mSelectedPO
= nullptr;
3210 if (mPrt
->mPrintSettings
== nullptr) {
3211 return NS_ERROR_FAILURE
;
3214 mPrt
->mPrintFrameType
= nsIPrintSettings::kNoFrames
;
3215 mPrt
->mPrintSettings
->GetPrintFrameType(&mPrt
->mPrintFrameType
);
3217 int16_t printHowEnable
= nsIPrintSettings::kFrameEnableNone
;
3218 mPrt
->mPrintSettings
->GetHowToEnableFrameUI(&printHowEnable
);
3220 int16_t printRangeType
= nsIPrintSettings::kRangeAllPages
;
3221 mPrt
->mPrintSettings
->GetPrintRange(&printRangeType
);
3224 PR_PL(("********* nsPrintEngine::EnablePOsForPrinting *********\n"));
3225 PR_PL(("PrintFrameType: %s \n", gPrintFrameTypeStr
[mPrt
->mPrintFrameType
]));
3226 PR_PL(("HowToEnableFrameUI: %s \n", gFrameHowToEnableStr
[printHowEnable
]));
3227 PR_PL(("PrintRange: %s \n", gPrintRangeStr
[printRangeType
]));
3230 // ***** This is the ultimate override *****
3231 // if we are printing the selection (either an IFrame or selection range)
3232 // then set the mPrintFrameType as if it were the selected frame
3233 if (printRangeType
== nsIPrintSettings::kRangeSelection
) {
3234 mPrt
->mPrintFrameType
= nsIPrintSettings::kSelectedFrame
;
3235 printHowEnable
= nsIPrintSettings::kFrameEnableNone
;
3238 // This tells us that the "Frame" UI has turned off,
3239 // so therefore there are no FrameSets/Frames/IFrames to be printed
3241 // This means there are not FrameSets,
3242 // but the document could contain an IFrame
3243 if (printHowEnable
== nsIPrintSettings::kFrameEnableNone
) {
3245 // Print all the pages or a sub range of pages
3246 if (printRangeType
== nsIPrintSettings::kRangeAllPages
||
3247 printRangeType
== nsIPrintSettings::kRangeSpecifiedPageRange
) {
3248 SetPrintPO(mPrt
->mPrintObject
, true);
3250 // Set the children so they are PrinAsIs
3251 // In this case, the children are probably IFrames
3252 if (mPrt
->mPrintObject
->mKids
.Length() > 0) {
3253 for (uint32_t i
=0;i
<mPrt
->mPrintObject
->mKids
.Length();i
++) {
3254 nsPrintObject
* po
= mPrt
->mPrintObject
->mKids
[i
];
3255 NS_ASSERTION(po
, "nsPrintObject can't be null!");
3259 // ***** Another override *****
3260 mPrt
->mPrintFrameType
= nsIPrintSettings::kFramesAsIs
;
3262 PR_PL(("PrintFrameType: %s \n", gPrintFrameTypeStr
[mPrt
->mPrintFrameType
]));
3263 PR_PL(("HowToEnableFrameUI: %s \n", gFrameHowToEnableStr
[printHowEnable
]));
3264 PR_PL(("PrintRange: %s \n", gPrintRangeStr
[printRangeType
]));
3268 // This means we are either printed a selected IFrame or
3269 // we are printing the current selection
3270 if (printRangeType
== nsIPrintSettings::kRangeSelection
) {
3272 // If the currentFocusDOMWin can'r be null if something is selected
3273 if (mPrt
->mCurrentFocusWin
) {
3274 // Find the selected IFrame
3275 nsPrintObject
* po
= FindPrintObjectByDOMWin(mPrt
->mPrintObject
, mPrt
->mCurrentFocusWin
);
3276 if (po
!= nullptr) {
3277 mPrt
->mSelectedPO
= po
;
3278 // Makes sure all of its children are be printed "AsIs"
3281 // Now, only enable this POs (the selected PO) and all of its children
3282 SetPrintPO(po
, true);
3284 // check to see if we have a range selection,
3285 // as oppose to a insert selection
3286 // this means if the user just clicked on the IFrame then
3287 // there will not be a selection so we want the entire page to print
3289 // XXX this is sort of a hack right here to make the page
3290 // not try to reposition itself when printing selection
3291 nsCOMPtr
<nsIDOMWindow
> domWin
=
3292 do_QueryInterface(po
->mDocument
->GetOriginalDocument()->GetWindow());
3293 if (!IsThereARangeSelection(domWin
)) {
3294 printRangeType
= nsIPrintSettings::kRangeAllPages
;
3295 mPrt
->mPrintSettings
->SetPrintRange(printRangeType
);
3297 PR_PL(("PrintFrameType: %s \n", gPrintFrameTypeStr
[mPrt
->mPrintFrameType
]));
3298 PR_PL(("HowToEnableFrameUI: %s \n", gFrameHowToEnableStr
[printHowEnable
]));
3299 PR_PL(("PrintRange: %s \n", gPrintRangeStr
[printRangeType
]));
3303 for (uint32_t i
=0;i
<mPrt
->mPrintDocList
.Length();i
++) {
3304 nsPrintObject
* po
= mPrt
->mPrintDocList
.ElementAt(i
);
3305 NS_ASSERTION(po
, "nsPrintObject can't be null!");
3306 nsCOMPtr
<nsIDOMWindow
> domWin
= po
->mDocShell
->GetWindow();
3307 if (IsThereARangeSelection(domWin
)) {
3308 mPrt
->mCurrentFocusWin
= domWin
;
3309 SetPrintPO(po
, true);
3318 // check to see if there is a selection when a FrameSet is present
3319 if (printRangeType
== nsIPrintSettings::kRangeSelection
) {
3320 // If the currentFocusDOMWin can'r be null if something is selected
3321 if (mPrt
->mCurrentFocusWin
) {
3322 // Find the selected IFrame
3323 nsPrintObject
* po
= FindPrintObjectByDOMWin(mPrt
->mPrintObject
, mPrt
->mCurrentFocusWin
);
3324 if (po
!= nullptr) {
3325 mPrt
->mSelectedPO
= po
;
3326 // Makes sure all of its children are be printed "AsIs"
3329 // Now, only enable this POs (the selected PO) and all of its children
3330 SetPrintPO(po
, true);
3332 // check to see if we have a range selection,
3333 // as oppose to a insert selection
3334 // this means if the user just clicked on the IFrame then
3335 // there will not be a selection so we want the entire page to print
3337 // XXX this is sort of a hack right here to make the page
3338 // not try to reposition itself when printing selection
3339 nsCOMPtr
<nsIDOMWindow
> domWin
=
3340 do_QueryInterface(po
->mDocument
->GetOriginalDocument()->GetWindow());
3341 if (!IsThereARangeSelection(domWin
)) {
3342 printRangeType
= nsIPrintSettings::kRangeAllPages
;
3343 mPrt
->mPrintSettings
->SetPrintRange(printRangeType
);
3345 PR_PL(("PrintFrameType: %s \n", gPrintFrameTypeStr
[mPrt
->mPrintFrameType
]));
3346 PR_PL(("HowToEnableFrameUI: %s \n", gFrameHowToEnableStr
[printHowEnable
]));
3347 PR_PL(("PrintRange: %s \n", gPrintRangeStr
[printRangeType
]));
3353 // If we are printing "AsIs" then sets all the POs to be printed as is
3354 if (mPrt
->mPrintFrameType
== nsIPrintSettings::kFramesAsIs
) {
3355 SetPrintAsIs(mPrt
->mPrintObject
);
3356 SetPrintPO(mPrt
->mPrintObject
, true);
3360 // If we are printing the selected Frame then
3361 // find that PO for that selected DOMWin and set it all of its
3362 // children to be printed
3363 if (mPrt
->mPrintFrameType
== nsIPrintSettings::kSelectedFrame
) {
3365 if ((mPrt
->mIsParentAFrameSet
&& mPrt
->mCurrentFocusWin
) || mPrt
->mIsIFrameSelected
) {
3366 nsPrintObject
* po
= FindPrintObjectByDOMWin(mPrt
->mPrintObject
, mPrt
->mCurrentFocusWin
);
3367 if (po
!= nullptr) {
3368 mPrt
->mSelectedPO
= po
;
3369 // NOTE: Calling this sets the "po" and
3370 // we don't want to do this for documents that have no children,
3371 // because then the "DoEndPage" gets called and it shouldn't
3372 if (po
->mKids
.Length() > 0) {
3373 // Makes sure that itself, and all of its children are printed "AsIs"
3377 // Now, only enable this POs (the selected PO) and all of its children
3378 SetPrintPO(po
, true);
3384 // If we are print each subdoc separately,
3385 // then don't print any of the FraneSet Docs
3386 if (mPrt
->mPrintFrameType
== nsIPrintSettings::kEachFrameSep
) {
3387 SetPrintPO(mPrt
->mPrintObject
, true);
3388 int32_t cnt
= mPrt
->mPrintDocList
.Length();
3389 for (int32_t i
=0;i
<cnt
;i
++) {
3390 nsPrintObject
* po
= mPrt
->mPrintDocList
.ElementAt(i
);
3391 NS_ASSERTION(po
, "nsPrintObject can't be null!");
3392 if (po
->mFrameType
== eFrameSet
) {
3393 po
->mDontPrint
= true;
3401 //-------------------------------------------------------
3402 // Return the nsPrintObject with that is XMost (The widest frameset frame) AND
3403 // contains the XMost (widest) layout frame
3405 nsPrintEngine::FindSmallestSTF()
3407 float smallestRatio
= 1.0f
;
3408 nsPrintObject
* smallestPO
= nullptr;
3410 for (uint32_t i
=0;i
<mPrt
->mPrintDocList
.Length();i
++) {
3411 nsPrintObject
* po
= mPrt
->mPrintDocList
.ElementAt(i
);
3412 NS_ASSERTION(po
, "nsPrintObject can't be null!");
3413 if (po
->mFrameType
!= eFrameSet
&& po
->mFrameType
!= eIFrame
) {
3414 if (po
->mShrinkRatio
< smallestRatio
) {
3415 smallestRatio
= po
->mShrinkRatio
;
3421 #ifdef EXTENDED_DEBUG_PRINTING
3422 if (smallestPO
) printf("*PO: %p Type: %d %10.3f\n", smallestPO
, smallestPO
->mFrameType
, smallestPO
->mShrinkRatio
);
3427 //-------------------------------------------------------
3429 nsPrintEngine::TurnScriptingOn(bool aDoTurnOn
)
3431 if (mIsDoingPrinting
&& aDoTurnOn
&& mDocViewerPrint
&&
3432 mDocViewerPrint
->GetIsPrintPreview()) {
3433 // We don't want to turn scripting on if print preview is shown still after
3438 nsPrintData
* prt
= mPrt
;
3439 #ifdef NS_PRINT_PREVIEW
3448 NS_ASSERTION(mDocument
, "We MUST have a document.");
3449 // First, get the script global object from the document...
3451 for (uint32_t i
=0;i
<prt
->mPrintDocList
.Length();i
++) {
3452 nsPrintObject
* po
= prt
->mPrintDocList
.ElementAt(i
);
3453 NS_ASSERTION(po
, "nsPrintObject can't be null!");
3455 nsIDocument
* doc
= po
->mDocument
;
3460 if (nsCOMPtr
<nsPIDOMWindow
> window
= doc
->GetInnerWindow()) {
3461 nsCOMPtr
<nsIGlobalObject
> go
= do_QueryInterface(window
);
3462 NS_WARN_IF_FALSE(go
&& go
->GetGlobalJSObject(), "Can't get global");
3463 nsresult propThere
= NS_PROPTABLE_PROP_NOT_THERE
;
3464 doc
->GetProperty(nsGkAtoms::scriptEnabledBeforePrintOrPreview
,
3467 if (propThere
!= NS_PROPTABLE_PROP_NOT_THERE
) {
3468 doc
->DeleteProperty(nsGkAtoms::scriptEnabledBeforePrintOrPreview
);
3469 if (go
&& go
->GetGlobalJSObject()) {
3470 xpc::Scriptability::Get(go
->GetGlobalJSObject()).Unblock();
3472 window
->ResumeTimeouts(false);
3475 // Have to be careful, because people call us over and over again with
3476 // aDoTurnOn == false. So don't set the property if it's already
3477 // set, since in that case we'd set it to the wrong value.
3478 if (propThere
== NS_PROPTABLE_PROP_NOT_THERE
) {
3479 // Stash the current value of IsScriptEnabled on the document, so
3480 // that layout code running in print preview doesn't get confused.
3481 doc
->SetProperty(nsGkAtoms::scriptEnabledBeforePrintOrPreview
,
3482 NS_INT32_TO_PTR(doc
->IsScriptEnabled()));
3483 if (go
&& go
->GetGlobalJSObject()) {
3484 xpc::Scriptability::Get(go
->GetGlobalJSObject()).Block();
3486 window
->SuspendTimeouts(1, false);
3493 //-----------------------------------------------------------------
3494 //-- Done: Misc Support Methods
3495 //-----------------------------------------------------------------
3498 //-----------------------------------------------------------------
3499 //-- Section: Finishing up or Cleaning up
3500 //-----------------------------------------------------------------
3502 //-----------------------------------------------------------------
3504 nsPrintEngine::CloseProgressDialog(nsIWebProgressListener
* aWebProgressListener
)
3506 if (aWebProgressListener
) {
3507 aWebProgressListener
->OnStateChange(nullptr, nullptr, nsIWebProgressListener::STATE_STOP
|nsIWebProgressListener::STATE_IS_DOCUMENT
, NS_OK
);
3511 //-----------------------------------------------------------------
3513 nsPrintEngine::FinishPrintPreview()
3515 nsresult rv
= NS_OK
;
3517 #ifdef NS_PRINT_PREVIEW
3520 /* we're already finished with print preview */
3524 rv
= DocumentReadyForPrinting();
3526 SetIsCreatingPrintPreview(false);
3528 /* cleaup on failure + notify user */
3529 if (NS_FAILED(rv
)) {
3530 /* cleanup done, let's fire-up an error dialog to notify the user
3531 * what went wrong...
3533 mPrt
->OnEndPrinting();
3534 TurnScriptingOn(true);
3539 // At this point we are done preparing everything
3540 // before it is to be created
3543 if (mIsDoingPrintPreview
&& mOldPrtPreview
) {
3544 delete mOldPrtPreview
;
3545 mOldPrtPreview
= nullptr;
3549 mPrt
->OnEndPrinting();
3551 // PrintPreview was built using the mPrt (code reuse)
3552 // then we assign it over
3556 #endif // NS_PRINT_PREVIEW
3561 //-----------------------------------------------------------------
3562 //-- Done: Finishing up or Cleaning up
3563 //-----------------------------------------------------------------
3566 /*=============== Timer Related Code ======================*/
3568 nsPrintEngine::StartPagePrintTimer(nsPrintObject
* aPO
)
3570 if (!mPagePrintTimer
) {
3571 // Get the delay time in between the printing of each page
3572 // this gives the user more time to press cancel
3573 int32_t printPageDelay
= 50;
3574 mPrt
->mPrintSettings
->GetPrintPageDelay(&printPageDelay
);
3576 nsRefPtr
<nsPagePrintTimer
> timer
=
3577 new nsPagePrintTimer(this, mDocViewerPrint
, printPageDelay
);
3578 timer
.forget(&mPagePrintTimer
);
3581 return mPagePrintTimer
->Start(aPO
);
3584 /*=============== nsIObserver Interface ======================*/
3586 nsPrintEngine::Observe(nsISupports
*aSubject
, const char *aTopic
, const char16_t
*aData
)
3588 nsresult rv
= NS_ERROR_FAILURE
;
3590 rv
= InitPrintDocConstruction(true);
3591 if (!mIsDoingPrinting
&& mPrtPreview
) {
3592 mPrtPreview
->OnEndPrinting();
3599 //---------------------------------------------------------------
3600 //-- PLEvent Notification
3601 //---------------------------------------------------------------
3602 class nsPrintCompletionEvent
: public nsRunnable
{
3604 explicit nsPrintCompletionEvent(nsIDocumentViewerPrint
*docViewerPrint
)
3605 : mDocViewerPrint(docViewerPrint
) {
3606 NS_ASSERTION(mDocViewerPrint
, "mDocViewerPrint is null.");
3609 NS_IMETHOD
Run() MOZ_OVERRIDE
{
3610 if (mDocViewerPrint
)
3611 mDocViewerPrint
->OnDonePrinting();
3616 nsCOMPtr
<nsIDocumentViewerPrint
> mDocViewerPrint
;
3619 //-----------------------------------------------------------
3621 nsPrintEngine::FirePrintCompletionEvent()
3623 nsCOMPtr
<nsIRunnable
> event
= new nsPrintCompletionEvent(mDocViewerPrint
);
3624 if (NS_FAILED(NS_DispatchToCurrentThread(event
)))
3625 NS_WARNING("failed to dispatch print completion event");
3628 //---------------------------------------------------------------
3629 //---------------------------------------------------------------
3630 //-- Debug helper routines
3631 //---------------------------------------------------------------
3632 //---------------------------------------------------------------
3633 #if defined(XP_WIN) && defined(EXTENDED_DEBUG_PRINTING)
3634 #include "windows.h"
3635 #include "process.h"
3638 #define MY_FINDFIRST(a,b) FindFirstFile(a,b)
3639 #define MY_FINDNEXT(a,b) FindNextFile(a,b)
3640 #define ISDIR(a) (a.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
3641 #define MY_FINDCLOSE(a) FindClose(a)
3642 #define MY_FILENAME(a) a.cFileName
3643 #define MY_FILESIZE(a) (a.nFileSizeHigh * MAXDWORD) + a.nFileSizeLow
3645 int RemoveFilesInDir(const char * aDir
)
3647 WIN32_FIND_DATA data_ptr
;
3650 char path
[MAX_PATH
];
3654 // Append slash to the end of the directory names if not there
3655 if (path
[strlen(path
)-1] != '\\')
3658 char findPath
[MAX_PATH
];
3659 strcpy(findPath
, path
);
3660 strcat(findPath
, "*.*");
3662 find_handle
= MY_FINDFIRST(findPath
, &data_ptr
);
3664 if (find_handle
!= INVALID_HANDLE_VALUE
) {
3667 && (stricmp(MY_FILENAME(data_ptr
),"."))
3668 && (stricmp(MY_FILENAME(data_ptr
),".."))) {
3671 else if (!ISDIR(data_ptr
)) {
3672 if (!strncmp(MY_FILENAME(data_ptr
), "print_dump", 10)) {
3673 char fileName
[MAX_PATH
];
3674 strcpy(fileName
, aDir
);
3675 strcat(fileName
, "\\");
3676 strcat(fileName
, MY_FILENAME(data_ptr
));
3677 printf("Removing %s\n", fileName
);
3681 } while(MY_FINDNEXT(find_handle
,&data_ptr
));
3682 MY_FINDCLOSE(find_handle
);
3688 #ifdef EXTENDED_DEBUG_PRINTING
3690 /** ---------------------------------------------------
3691 * Dumps Frames for Printing
3693 static void RootFrameList(nsPresContext
* aPresContext
, FILE* out
, int32_t aIndent
)
3695 if (!aPresContext
|| !out
)
3698 nsIPresShell
*shell
= aPresContext
->GetPresShell();
3700 nsIFrame
* frame
= shell
->FrameManager()->GetRootFrame();
3702 frame
->List(aPresContext
, out
, aIndent
);
3707 /** ---------------------------------------------------
3708 * Dumps Frames for Printing
3710 static void DumpFrames(FILE* out
,
3711 nsPresContext
* aPresContext
,
3712 nsRenderingContext
* aRendContext
,
3716 NS_ASSERTION(out
, "Pointer is null!");
3717 NS_ASSERTION(aPresContext
, "Pointer is null!");
3718 NS_ASSERTION(aRendContext
, "Pointer is null!");
3719 NS_ASSERTION(aFrame
, "Pointer is null!");
3721 nsIFrame
* child
= aFrame
->GetFirstPrincipalChild();
3722 while (child
!= nullptr) {
3723 for (int32_t i
=0;i
<aLevel
;i
++) {
3727 child
->GetFrameName(tmp
);
3728 fputs(NS_LossyConvertUTF16toASCII(tmp
).get(), out
);
3730 if (NS_SUCCEEDED(child
->IsVisibleForPainting(aPresContext
, *aRendContext
, true, &isSelected
))) {
3731 fprintf(out
, " %p %s", child
, isSelected
?"VIS":"UVS");
3732 nsRect rect
= child
->GetRect();
3733 fprintf(out
, "[%d,%d,%d,%d] ", rect
.x
, rect
.y
, rect
.width
, rect
.height
);
3734 fprintf(out
, "v: %p ", (void*)child
->GetView());
3736 DumpFrames(out
, aPresContext
, aRendContext
, child
, aLevel
+1);
3737 child
= child
->GetNextSibling();
3743 /** ---------------------------------------------------
3744 * Dumps the Views from the DocShell
3747 DumpViews(nsIDocShell
* aDocShell
, FILE* out
)
3749 NS_ASSERTION(aDocShell
, "Pointer is null!");
3750 NS_ASSERTION(out
, "Pointer is null!");
3752 if (nullptr != aDocShell
) {
3753 fprintf(out
, "docshell=%p \n", aDocShell
);
3754 nsIPresShell
* shell
= nsPrintEngine::GetPresShellFor(aDocShell
);
3756 nsViewManager
* vm
= shell
->GetViewManager();
3758 nsView
* root
= vm
->GetRootView();
3765 fputs("null pres shell\n", out
);
3768 // dump the views of the sub documents
3770 aDocShell
->GetChildCount(&n
);
3771 for (i
= 0; i
< n
; i
++) {
3772 nsCOMPtr
<nsIDocShellTreeItem
> child
;
3773 aDocShell
->GetChildAt(i
, getter_AddRefs(child
));
3774 nsCOMPtr
<nsIDocShell
> childAsShell(do_QueryInterface(child
));
3776 DumpViews(childAsShell
, out
);
3782 /** ---------------------------------------------------
3783 * Dumps the Views and Frames
3785 void DumpLayoutData(char* aTitleStr
,
3787 nsPresContext
* aPresContext
,
3788 nsDeviceContext
* aDC
,
3789 nsIFrame
* aRootFrame
,
3790 nsIDocShekk
* aDocShell
,
3791 FILE* aFD
= nullptr)
3793 if (!kPrintingLogMod
|| kPrintingLogMod
->level
!= DUMP_LAYOUT_LEVEL
) return;
3795 if (aPresContext
== nullptr || aDC
== nullptr) {
3799 #ifdef NS_PRINT_PREVIEW
3800 if (aPresContext
->Type() == nsPresContext::eContext_PrintPreview
) {
3805 NS_ASSERTION(aRootFrame
, "Pointer is null!");
3806 NS_ASSERTION(aDocShell
, "Pointer is null!");
3808 // Dump all the frames and view to a a file
3810 sprintf(filename
, "print_dump_layout_%d.txt", gDumpLOFileNameCnt
++);
3811 FILE * fd
= aFD
?aFD
:fopen(filename
, "w");
3813 fprintf(fd
, "Title: %s\n", aTitleStr
?aTitleStr
:"");
3814 fprintf(fd
, "URL: %s\n", aURLStr
?aURLStr
:"");
3815 fprintf(fd
, "--------------- Frames ----------------\n");
3816 fprintf(fd
, "--------------- Frames ----------------\n");
3817 nsRefPtr
<nsRenderingContext
> renderingContext
=
3818 aDC
->CreateRenderingContext();
3819 RootFrameList(aPresContext
, fd
, 0);
3820 //DumpFrames(fd, aPresContext, renderingContext, aRootFrame, 0);
3821 fprintf(fd
, "---------------------------------------\n\n");
3822 fprintf(fd
, "--------------- Views From Root Frame----------------\n");
3823 nsView
* v
= aRootFrame
->GetView();
3827 printf("View is null!\n");
3830 fprintf(fd
, "--------------- All Views ----------------\n");
3831 DumpViews(aDocShell
, fd
);
3832 fprintf(fd
, "---------------------------------------\n\n");
3834 if (aFD
== nullptr) {
3840 //-------------------------------------------------------------
3841 static void DumpPrintObjectsList(nsTArray
<nsPrintObject
*> * aDocList
)
3843 if (!kPrintingLogMod
|| kPrintingLogMod
->level
!= DUMP_LAYOUT_LEVEL
) return;
3845 NS_ASSERTION(aDocList
, "Pointer is null!");
3847 const char types
[][3] = {"DC", "FR", "IF", "FS"};
3848 PR_PL(("Doc List\n***************************************************\n"));
3849 PR_PL(("T P A H PO DocShell Seq Page Root Page# Rect\n"));
3850 int32_t cnt
= aDocList
->Length();
3851 for (int32_t i
=0;i
<cnt
;i
++) {
3852 nsPrintObject
* po
= aDocList
->ElementAt(i
);
3853 NS_ASSERTION(po
, "nsPrintObject can't be null!");
3854 nsIFrame
* rootFrame
= nullptr;
3855 if (po
->mPresShell
) {
3856 rootFrame
= po
->mPresShell
->FrameManager()->GetRootFrame();
3857 while (rootFrame
!= nullptr) {
3858 nsIPageSequenceFrame
* sqf
= do_QueryFrame(rootFrame
);
3862 rootFrame
= rootFrame
->GetFirstPrincipalChild();
3866 PR_PL(("%s %d %d %d %p %p %p %p %p %d %d,%d,%d,%d\n", types
[po
->mFrameType
],
3867 po
->IsPrintable(), po
->mPrintAsIs
, po
->mHasBeenPrinted
, po
, po
->mDocShell
.get(), po
->mSeqFrame
,
3868 po
->mPageFrame
, rootFrame
, po
->mPageNum
, po
->mRect
.x
, po
->mRect
.y
, po
->mRect
.width
, po
->mRect
.height
));
3872 //-------------------------------------------------------------
3873 static void DumpPrintObjectsTree(nsPrintObject
* aPO
, int aLevel
, FILE* aFD
)
3875 if (!kPrintingLogMod
|| kPrintingLogMod
->level
!= DUMP_LAYOUT_LEVEL
) return;
3877 NS_ASSERTION(aPO
, "Pointer is null!");
3879 FILE * fd
= aFD
?aFD
:stdout
;
3880 const char types
[][3] = {"DC", "FR", "IF", "FS"};
3882 fprintf(fd
, "DocTree\n***************************************************\n");
3883 fprintf(fd
, "T PO DocShell Seq Page Page# Rect\n");
3885 int32_t cnt
= aPO
->mKids
.Length();
3886 for (int32_t i
=0;i
<cnt
;i
++) {
3887 nsPrintObject
* po
= aPO
->mKids
.ElementAt(i
);
3888 NS_ASSERTION(po
, "nsPrintObject can't be null!");
3889 for (int32_t k
=0;k
<aLevel
;k
++) fprintf(fd
, " ");
3890 fprintf(fd
, "%s %p %p %p %p %d %d,%d,%d,%d\n", types
[po
->mFrameType
], po
, po
->mDocShell
.get(), po
->mSeqFrame
,
3891 po
->mPageFrame
, po
->mPageNum
, po
->mRect
.x
, po
->mRect
.y
, po
->mRect
.width
, po
->mRect
.height
);
3895 //-------------------------------------------------------------
3896 static void GetDocTitleAndURL(nsPrintObject
* aPO
, nsACString
& aDocStr
, nsACString
& aURLStr
)
3898 nsAutoString docTitleStr
;
3899 nsAutoString docURLStr
;
3900 nsPrintEngine::GetDisplayTitleAndURL(aPO
,
3901 docTitleStr
, docURLStr
,
3902 nsPrintEngine::eDocTitleDefURLDoc
);
3903 aDocStr
= NS_ConvertUTF16toUTF8(docTitleStr
);
3904 aURLStr
= NS_ConvertUTF16toUTF8(docURLStr
);
3907 //-------------------------------------------------------------
3908 static void DumpPrintObjectsTreeLayout(nsPrintObject
* aPO
,
3909 nsDeviceContext
* aDC
,
3910 int aLevel
, FILE * aFD
)
3912 if (!kPrintingLogMod
|| kPrintingLogMod
->level
!= DUMP_LAYOUT_LEVEL
) return;
3914 NS_ASSERTION(aPO
, "Pointer is null!");
3915 NS_ASSERTION(aDC
, "Pointer is null!");
3917 const char types
[][3] = {"DC", "FR", "IF", "FS"};
3918 FILE * fd
= nullptr;
3920 fd
= fopen("tree_layout.txt", "w");
3921 fprintf(fd
, "DocTree\n***************************************************\n");
3922 fprintf(fd
, "***************************************************\n");
3923 fprintf(fd
, "T PO DocShell Seq Page Page# Rect\n");
3928 nsIFrame
* rootFrame
= nullptr;
3929 if (aPO
->mPresShell
) {
3930 rootFrame
= aPO
->mPresShell
->FrameManager()->GetRootFrame();
3932 for (int32_t k
=0;k
<aLevel
;k
++) fprintf(fd
, " ");
3933 fprintf(fd
, "%s %p %p %p %p %d %d,%d,%d,%d\n", types
[aPO
->mFrameType
], aPO
, aPO
->mDocShell
.get(), aPO
->mSeqFrame
,
3934 aPO
->mPageFrame
, aPO
->mPageNum
, aPO
->mRect
.x
, aPO
->mRect
.y
, aPO
->mRect
.width
, aPO
->mRect
.height
);
3935 if (aPO
->IsPrintable()) {
3936 nsAutoCString docStr
;
3937 nsAutoCString urlStr
;
3938 GetDocTitleAndURL(aPO
, docStr
, urlStr
);
3939 DumpLayoutData(docStr
.get(), urlStr
.get(), aPO
->mPresContext
, aDC
, rootFrame
, aPO
->mDocShell
, fd
);
3941 fprintf(fd
, "<***************************************************>\n");
3943 int32_t cnt
= aPO
->mKids
.Length();
3944 for (int32_t i
=0;i
<cnt
;i
++) {
3945 nsPrintObject
* po
= aPO
->mKids
.ElementAt(i
);
3946 NS_ASSERTION(po
, "nsPrintObject can't be null!");
3947 DumpPrintObjectsTreeLayout(po
, aDC
, aLevel
+1, fd
);
3950 if (aLevel
== 0 && fd
) {
3955 //-------------------------------------------------------------
3956 static void DumpPrintObjectsListStart(const char * aStr
, nsTArray
<nsPrintObject
*> * aDocList
)
3958 if (!kPrintingLogMod
|| kPrintingLogMod
->level
!= DUMP_LAYOUT_LEVEL
) return;
3960 NS_ASSERTION(aStr
, "Pointer is null!");
3961 NS_ASSERTION(aDocList
, "Pointer is null!");
3963 PR_PL(("%s\n", aStr
));
3964 DumpPrintObjectsList(aDocList
);
3967 #define DUMP_DOC_LIST(_title) DumpPrintObjectsListStart((_title), mPrt->mPrintDocList);
3968 #define DUMP_DOC_TREE DumpPrintObjectsTree(mPrt->mPrintObject);
3969 #define DUMP_DOC_TREELAYOUT DumpPrintObjectsTreeLayout(mPrt->mPrintObject, mPrt->mPrintDC);
3972 #define DUMP_DOC_LIST(_title)
3973 #define DUMP_DOC_TREE
3974 #define DUMP_DOC_TREELAYOUT
3977 //---------------------------------------------------------------
3978 //---------------------------------------------------------------
3979 //-- End of debug helper routines
3980 //---------------------------------------------------------------