1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* ***** BEGIN LICENSE BLOCK *****
3 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
5 * The contents of this file are subject to the Mozilla Public License Version
6 * 1.1 (the "License"); you may not use this file except in compliance with
7 * the License. You may obtain a copy of the License at
8 * http://www.mozilla.org/MPL/
10 * Software distributed under the License is distributed on an "AS IS" basis,
11 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
12 * for the specific language governing rights and limitations under the
15 * The Original Code is mozilla.org code.
17 * The Initial Developer of the Original Code is
18 * Netscape Communications Corporation.
19 * Portions created by the Initial Developer are Copyright (C) 1998
20 * the Initial Developer. All Rights Reserved.
23 * Roland Mainz <roland.mainz@informatik.med.uni-giessen.de>
25 * Alternatively, the contents of this file may be used under the terms of
26 * either of the GNU General Public License Version 2 or later (the "GPL"),
27 * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
28 * in which case the provisions of the GPL or the LGPL are applicable instead
29 * of those above. If you wish to allow use of your version of this file only
30 * under the terms of either the GPL or the LGPL, and not to allow others to
31 * use your version of this file under the terms of the MPL, indicate your
32 * decision by deleting the provisions above and replace them with the notice
33 * and other provisions required by the GPL or the LGPL. If you do not delete
34 * the provisions above, a recipient may use your version of this file under
35 * the terms of any one of the MPL, the GPL or the LGPL.
37 * ***** END LICENSE BLOCK ***** */
39 #include "nsPrintEngine.h"
41 #include "nsIStringBundle.h"
42 #include "nsReadableUtils.h"
45 #include "nsISelection.h"
46 #include "nsIScriptGlobalObject.h"
47 #include "nsPIDOMWindow.h"
48 #include "nsIDocShell.h"
50 #include "nsContentErrors.h"
53 #include "nsIPrintSettings.h"
54 #include "nsIPrintSettingsService.h"
55 #include "nsIPrintOptions.h"
56 #include "nsIPrintSession.h"
57 #include "nsGfxCIID.h"
58 #include "nsIServiceManager.h"
59 #include "nsGkAtoms.h"
61 #include "nsISupportsPrimitives.h"
63 static const char sPrintSettingsServiceContractID
[] = "@mozilla.org/gfx/printsettings-service;1";
66 #include "nsPrintPreviewListener.h"
67 #include "nsThreadUtils.h"
70 #include "nsIWebBrowserPrint.h"
71 #include "nsIDOMHTMLFrameElement.h"
72 #include "nsIDOMHTMLFrameSetElement.h"
73 #include "nsIDOMHTMLIFrameElement.h"
74 #include "nsIDOMHTMLObjectElement.h"
75 #include "nsIDOMHTMLEmbedElement.h"
78 #include "imgIContainer.h" // image animation mode constants
79 #include "nsIWebBrowserPrint.h" // needed for PrintPreview Navigation constants
82 #include "nsIPrintProgress.h"
83 #include "nsIPrintProgressParams.h"
84 #include "nsIObserver.h"
87 #include "nsIPrompt.h"
88 #include "nsIWindowWatcher.h"
89 #include "nsIStringBundle.h"
92 #include "nsIPrintingPromptService.h"
93 static const char kPrintingPromptService
[] = "@mozilla.org/embedcomp/printingprompt-service;1";
96 #include "nsPagePrintTimer.h"
99 #include "nsIDocument.h"
102 #include "nsIDOMEventTarget.h"
103 #include "nsIDOMFocusListener.h"
104 #include "nsISelectionController.h"
107 #include "nsISupportsUtils.h"
108 #include "nsIFrame.h"
109 #include "nsIScriptContext.h"
110 #include "nsILinkHandler.h"
111 #include "nsIDOMDocument.h"
112 #include "nsISelectionListener.h"
113 #include "nsISelectionPrivate.h"
114 #include "nsIDOMHTMLDocument.h"
115 #include "nsIDOMNSHTMLDocument.h"
116 #include "nsIDOMHTMLCollection.h"
117 #include "nsIDOMHTMLElement.h"
118 #include "nsIDOMRange.h"
119 #include "nsContentCID.h"
120 #include "nsLayoutCID.h"
121 #include "nsContentUtils.h"
122 #include "nsIPresShell.h"
123 #include "nsLayoutUtils.h"
125 #include "nsViewsCID.h"
126 #include "nsWidgetsCID.h"
127 #include "nsIDeviceContext.h"
128 #include "nsIDeviceContextSpec.h"
129 #include "nsIViewManager.h"
132 #include "nsIPageSequenceFrame.h"
134 #include "nsIContentViewerEdit.h"
135 #include "nsIContentViewerFile.h"
136 #include "nsIMarkupDocumentViewer.h"
137 #include "nsIInterfaceRequestor.h"
138 #include "nsIInterfaceRequestorUtils.h"
139 #include "nsIDocShellTreeItem.h"
140 #include "nsIDocShellTreeNode.h"
141 #include "nsIDocShellTreeOwner.h"
142 #include "nsIWebBrowserChrome.h"
143 #include "nsIDocShell.h"
144 #include "nsIBaseWindow.h"
145 #include "nsIFrameDebug.h"
146 #include "nsILayoutHistoryState.h"
147 #include "nsFrameManager.h"
148 #include "nsIParser.h"
149 #include "nsGUIEvent.h"
150 #include "nsHTMLReflowState.h"
151 #include "nsIDOMHTMLAnchorElement.h"
152 #include "nsIDOMHTMLAreaElement.h"
153 #include "nsIDOMHTMLLinkElement.h"
154 #include "nsIDOMHTMLImageElement.h"
155 #include "nsIContentViewerContainer.h"
156 #include "nsIContentViewer.h"
157 #include "nsIDocumentViewerPrint.h"
159 #include "nsPIDOMWindow.h"
160 #include "nsIFocusController.h"
162 #include "nsCDefaultURIFixup.h"
163 #include "nsIURIFixup.h"
165 //-----------------------------------------------------
168 #define FORCE_PR_LOG /* Allow logging in the release build */
176 // PR_LOGGING is force to always be on (even in release builds)
177 // but we only want some of it on,
178 //#define EXTENDED_DEBUG_PRINTING
181 #define DUMP_LAYOUT_LEVEL 9 // this turns on the dumping of each doucment's layout info
183 static PRLogModuleInfo
* kPrintingLogMod
= PR_NewLogModule("printing");
184 #define PR_PL(_p1) PR_LOG(kPrintingLogMod, PR_LOG_DEBUG, _p1);
186 #ifdef EXTENDED_DEBUG_PRINTING
187 static PRUint32 gDumpFileNameCnt
= 0;
188 static PRUint32 gDumpLOFileNameCnt
= 0;
191 #define PRT_YESNO(_p) ((_p)?"YES":"NO")
192 static const char * gFrameTypesStr
[] = {"eDoc", "eFrame", "eIFrame", "eFrameSet"};
193 static const char * gPrintFrameTypeStr
[] = {"kNoFrames", "kFramesAsIs", "kSelectedFrame", "kEachFrameSep"};
194 static const char * gFrameHowToEnableStr
[] = {"kFrameEnableNone", "kFrameEnableAll", "kFrameEnableAsIsAndEach"};
195 static const char * gPrintRangeStr
[] = {"kRangeAllPages", "kRangeSpecifiedPageRange", "kRangeSelection", "kRangeFocusFrame"};
197 #define PRT_YESNO(_p)
201 #ifdef EXTENDED_DEBUG_PRINTING
202 // Forward Declarations
203 static void DumpPrintObjectsListStart(const char * aStr
, nsVoidArray
* aDocList
);
204 static void DumpPrintObjectsTree(nsPrintObject
* aPO
, int aLevel
= 0, FILE* aFD
= nsnull
);
205 static void DumpPrintObjectsTreeLayout(nsPrintObject
* aPO
,nsIDeviceContext
* aDC
, int aLevel
= 0, FILE * aFD
= nsnull
);
207 #define DUMP_DOC_LIST(_title) DumpPrintObjectsListStart((_title), mPrt->mPrintDocList);
208 #define DUMP_DOC_TREE DumpPrintObjectsTree(mPrt->mPrintObject);
209 #define DUMP_DOC_TREELAYOUT DumpPrintObjectsTreeLayout(mPrt->mPrintObject, mPrt->mPrintDC);
211 #define DUMP_DOC_LIST(_title)
212 #define DUMP_DOC_TREE
213 #define DUMP_DOC_TREELAYOUT
218 static NS_DEFINE_CID(kViewManagerCID
, NS_VIEW_MANAGER_CID
);
219 static NS_DEFINE_CID(kWidgetCID
, NS_CHILD_CID
);
221 NS_IMPL_ISUPPORTS1(nsPrintEngine
, nsIObserver
)
223 //---------------------------------------------------
224 //-- nsPrintEngine Class Impl
225 //---------------------------------------------------
226 nsPrintEngine::nsPrintEngine() :
227 mIsCreatingPrintPreview(PR_FALSE
),
228 mIsDoingPrinting(PR_FALSE
),
229 mIsDoingPrintPreview(PR_FALSE
),
230 mProgressDialogIsShown(PR_FALSE
),
231 mDocViewerPrint(nsnull
),
233 mDeviceContext(nsnull
),
235 mPagePrintTimer(nsnull
),
236 mPageSeqFrame(nsnull
),
237 mParentWidget(nsnull
),
239 mOldPrtPreview(nsnull
),
244 //-------------------------------------------------------
245 nsPrintEngine::~nsPrintEngine()
247 Destroy(); // for insurance
250 //-------------------------------------------------------
251 void nsPrintEngine::Destroy()
258 #ifdef NS_PRINT_PREVIEW
261 mPrtPreview
= nsnull
;
265 if (mOldPrtPreview
) {
266 delete mOldPrtPreview
;
267 mOldPrtPreview
= nsnull
;
274 //-------------------------------------------------------
275 void nsPrintEngine::DestroyPrintingData()
283 //---------------------------------------------------------------------------------
284 //-- Section: Methods needed by the DocViewer
285 //---------------------------------------------------------------------------------
287 //--------------------------------------------------------
288 nsresult
nsPrintEngine::Initialize(nsIDocumentViewerPrint
* aDocViewerPrint
,
289 nsISupports
* aContainer
,
290 nsIDocument
* aDocument
,
291 nsIDeviceContext
* aDevContext
,
292 nsIWidget
* aParentWidget
,
295 NS_ENSURE_ARG_POINTER(aDocViewerPrint
);
296 NS_ENSURE_ARG_POINTER(aContainer
);
297 NS_ENSURE_ARG_POINTER(aDocument
);
298 NS_ENSURE_ARG_POINTER(aDevContext
);
299 NS_ENSURE_ARG_POINTER(aParentWidget
);
301 mDocViewerPrint
= aDocViewerPrint
; // weak reference
302 mContainer
= aContainer
; // weak reference
303 mDocument
= aDocument
;
304 mDeviceContext
= aDevContext
; // weak reference
305 mParentWidget
= aParentWidget
;
307 mDebugFile
= aDebugFile
; // ok to be NULL
312 //-------------------------------------------------------
314 nsPrintEngine::CheckBeforeDestroy()
316 if (mPrt
&& mPrt
->mPreparingForPrint
) {
317 mPrt
->mDocWasToBeDestroyed
= PR_TRUE
;
323 //-------------------------------------------------------
325 nsPrintEngine::Cancelled()
327 if (mPrt
&& mPrt
->mPrintSettings
) {
328 return mPrt
->mPrintSettings
->SetIsCancelled(PR_TRUE
);
330 return NS_ERROR_FAILURE
;
333 //-------------------------------------------------------
334 // Install our event listeners on the document to prevent
335 // some events from being processed while in PrintPreview
337 // No return code - if this fails, there isn't much we can do
339 nsPrintEngine::InstallPrintPreviewListener()
341 if (!mPrt
->mPPEventListeners
) {
342 nsCOMPtr
<nsPIDOMWindow
> win(do_GetInterface(mContainer
));
343 nsCOMPtr
<nsIDOMEventTarget
> target(do_QueryInterface(win
->GetFrameElementInternal()));
344 mPrt
->mPPEventListeners
= new nsPrintPreviewListener(target
);
346 if (mPrt
->mPPEventListeners
) {
347 mPrt
->mPPEventListeners
->AddListeners();
352 //----------------------------------------------------------------------
354 nsPrintEngine::GetSeqFrameAndCountPagesInternal(nsPrintObject
* aPO
,
355 nsIFrame
*& aSeqFrame
,
358 NS_ENSURE_ARG_POINTER(aPO
);
360 // Finds the SimplePageSequencer frame
361 nsIPageSequenceFrame
* seqFrame
= nsnull
;
362 aPO
->mPresShell
->GetPageSequenceFrame(&seqFrame
);
364 CallQueryInterface(seqFrame
, &aSeqFrame
);
368 if (aSeqFrame
== nsnull
) return NS_ERROR_FAILURE
;
370 // first count the total number of pages
372 nsIFrame
* pageFrame
= aSeqFrame
->GetFirstChild(nsnull
);
373 while (pageFrame
!= nsnull
) {
375 pageFrame
= pageFrame
->GetNextSibling();
382 //-----------------------------------------------------------------
383 nsresult
nsPrintEngine::GetSeqFrameAndCountPages(nsIFrame
*& aSeqFrame
, PRInt32
& aCount
)
385 NS_ASSERTION(mPrtPreview
, "mPrtPreview can't be null!");
386 return GetSeqFrameAndCountPagesInternal(mPrtPreview
->mPrintObject
, aSeqFrame
, aCount
);
388 //---------------------------------------------------------------------------------
389 //-- Done: Methods needed by the DocViewer
390 //---------------------------------------------------------------------------------
393 //---------------------------------------------------------------------------------
394 //-- Section: nsIWebBrowserPrint
395 //---------------------------------------------------------------------------------
397 // Foward decl for Debug Helper Functions
398 #ifdef EXTENDED_DEBUG_PRINTING
399 static int RemoveFilesInDir(const char * aDir
);
400 static void GetDocTitleAndURL(nsPrintObject
* aPO
, char *& aDocStr
, char *& aURLStr
);
401 static void DumpPrintObjectsTree(nsPrintObject
* aPO
, int aLevel
, FILE* aFD
);
402 static void DumpPrintObjectsList(nsVoidArray
* aDocList
);
403 static void RootFrameList(nsPresContext
* aPresContext
, FILE* out
, PRInt32 aIndent
);
404 static void DumpViews(nsIDocShell
* aDocShell
, FILE* out
);
405 static void DumpLayoutData(char* aTitleStr
, char* aURLStr
,
406 nsPresContext
* aPresContext
,
407 nsIDeviceContext
* aDC
, nsIFrame
* aRootFrame
,
408 nsIDocShell
* aDocShell
, FILE* aFD
);
411 //--------------------------------------------------------------------------------
414 nsPrintEngine::CommonPrint(PRBool aIsPrintPreview
,
415 nsIPrintSettings
* aPrintSettings
,
416 nsIWebProgressListener
* aWebProgressListener
) {
417 nsresult rv
= DoCommonPrint(aIsPrintPreview
, aPrintSettings
,
418 aWebProgressListener
);
420 if (aIsPrintPreview
) {
421 SetIsCreatingPrintPreview(PR_FALSE
);
422 SetIsPrintPreview(PR_FALSE
);
424 SetIsPrinting(PR_FALSE
);
426 if (mProgressDialogIsShown
)
427 CloseProgressDialog(aWebProgressListener
);
428 if (rv
!= NS_ERROR_ABORT
&& rv
!= NS_ERROR_OUT_OF_MEMORY
)
429 ShowPrintErrorDialog(rv
, !aIsPrintPreview
);
438 nsPrintEngine::DoCommonPrint(PRBool aIsPrintPreview
,
439 nsIPrintSettings
* aPrintSettings
,
440 nsIWebProgressListener
* aWebProgressListener
)
444 if (aIsPrintPreview
) {
445 // The WebProgressListener can be QI'ed to nsIPrintingPromptService
446 // then that means the progress dialog is already being shown.
447 nsCOMPtr
<nsIPrintingPromptService
> pps(do_QueryInterface(aWebProgressListener
));
448 mProgressDialogIsShown
= pps
!= nsnull
;
450 if (mIsDoingPrintPreview
) {
451 mOldPrtPreview
= mPrtPreview
;
452 mPrtPreview
= nsnull
;
455 mProgressDialogIsShown
= PR_FALSE
;
458 mPrt
= new nsPrintData(aIsPrintPreview
? nsPrintData::eIsPrintPreview
:
459 nsPrintData::eIsPrinting
);
460 NS_ENSURE_TRUE(mPrt
, NS_ERROR_OUT_OF_MEMORY
);
462 // if they don't pass in a PrintSettings, then get the Global PS
463 mPrt
->mPrintSettings
= aPrintSettings
;
464 if (!mPrt
->mPrintSettings
) {
465 rv
= GetGlobalPrintSettings(getter_AddRefs(mPrt
->mPrintSettings
));
466 NS_ENSURE_SUCCESS(rv
, rv
);
469 rv
= CheckForPrinters(mPrt
->mPrintSettings
);
470 NS_ENSURE_SUCCESS(rv
, rv
);
472 mPrt
->mPrintSettings
->SetIsCancelled(PR_FALSE
);
473 mPrt
->mPrintSettings
->GetShrinkToFit(&mPrt
->mShrinkToFit
);
475 if (aIsPrintPreview
) {
476 SetIsCreatingPrintPreview(PR_TRUE
);
477 SetIsPrintPreview(PR_TRUE
);
478 nsCOMPtr
<nsIMarkupDocumentViewer
> viewer
=
479 do_QueryInterface(mDocViewerPrint
);
481 viewer
->SetTextZoom(1.0f
);
482 viewer
->SetFullZoom(1.0f
);
485 SetIsPrinting(PR_TRUE
);
488 // Create a print session and let the print settings know about it.
489 // The print settings hold an nsWeakPtr to the session so it does not
490 // need to be cleared from the settings at the end of the job.
491 // XXX What lifetime does the printSession need to have?
492 nsCOMPtr
<nsIPrintSession
> printSession
;
493 if (!aIsPrintPreview
) {
494 printSession
= do_CreateInstance("@mozilla.org/gfx/printsession;1", &rv
);
495 NS_ENSURE_SUCCESS(rv
, rv
);
496 mPrt
->mPrintSettings
->SetPrintSession(printSession
);
499 if (aWebProgressListener
!= nsnull
) {
500 mPrt
->mPrintProgressListeners
.AppendObject(aWebProgressListener
);
503 // Get the currently focused window and cache it
504 // because the Print Dialog will "steal" focus and later when you try
505 // to get the currently focused windows it will be NULL
506 mPrt
->mCurrentFocusWin
= FindFocusedDOMWindow();
508 // Check to see if there is a "regular" selection
509 PRBool isSelection
= IsThereARangeSelection(mPrt
->mCurrentFocusWin
);
511 mPrt
->mPrintDocList
= new nsVoidArray();
512 NS_ENSURE_TRUE(mPrt
->mPrintDocList
, NS_ERROR_OUT_OF_MEMORY
);
514 // Get the docshell for this documentviewer
515 nsCOMPtr
<nsIDocShell
> webContainer(do_QueryInterface(mContainer
, &rv
));
516 NS_ENSURE_SUCCESS(rv
, rv
);
518 mPrt
->mPrintObject
= new nsPrintObject();
519 NS_ENSURE_TRUE(mPrt
->mPrintObject
, NS_ERROR_OUT_OF_MEMORY
);
520 rv
= mPrt
->mPrintObject
->Init(webContainer
);
521 NS_ENSURE_SUCCESS(rv
, rv
);
523 NS_ENSURE_TRUE(mPrt
->mPrintDocList
->AppendElement(mPrt
->mPrintObject
),
524 NS_ERROR_OUT_OF_MEMORY
);
526 mPrt
->mIsParentAFrameSet
= IsParentAFrameSet(webContainer
);
527 mPrt
->mPrintObject
->mFrameType
= mPrt
->mIsParentAFrameSet
? eFrameSet
: eDoc
;
529 // Build the "tree" of PrintObjects
530 nsCOMPtr
<nsIDocShellTreeNode
> parentAsNode(do_QueryInterface(webContainer
));
531 BuildDocTree(parentAsNode
, mPrt
->mPrintDocList
, mPrt
->mPrintObject
);
533 // XXX This isn't really correct...
534 if (!mPrt
->mPrintObject
->mDocument
->GetRootContent())
535 return NS_ERROR_GFX_PRINTER_STARTDOC
;
537 // Create the linkage from the sub-docs back to the content element
538 // in the parent document
539 MapContentToWebShells(mPrt
->mPrintObject
, mPrt
->mPrintObject
);
541 mPrt
->mIsIFrameSelected
= IsThereAnIFrameSelected(webContainer
, mPrt
->mCurrentFocusWin
, mPrt
->mIsParentAFrameSet
);
543 // Setup print options for UI
544 if (mPrt
->mIsParentAFrameSet
) {
545 if (mPrt
->mCurrentFocusWin
) {
546 mPrt
->mPrintSettings
->SetHowToEnableFrameUI(nsIPrintSettings::kFrameEnableAll
);
548 mPrt
->mPrintSettings
->SetHowToEnableFrameUI(nsIPrintSettings::kFrameEnableAsIsAndEach
);
551 mPrt
->mPrintSettings
->SetHowToEnableFrameUI(nsIPrintSettings::kFrameEnableNone
);
553 // Now determine how to set up the Frame print UI
554 mPrt
->mPrintSettings
->SetPrintOptions(nsIPrintSettings::kEnableSelectionRB
, isSelection
|| mPrt
->mIsIFrameSelected
);
556 nsCOMPtr
<nsIDeviceContextSpec
> devspec
557 (do_CreateInstance("@mozilla.org/gfx/devicecontextspec;1", &rv
));
558 NS_ENSURE_SUCCESS(rv
, rv
);
560 if (!aIsPrintPreview
) {
562 mPrt
->mDebugFilePtr
= mDebugFile
;
565 PRBool printSilently
;
566 mPrt
->mPrintSettings
->GetPrintSilent(&printSilently
);
568 // Check prefs for a default setting as to whether we should print silently
569 printSilently
= nsContentUtils::GetBoolPref("print.always_print_silent",
572 // Ask dialog to be Print Shown via the Plugable Printing Dialog Service
573 // This service is for the Print Dialog and the Print Progress Dialog
574 // If printing silently or you can't get the service continue on
575 if (!printSilently
) {
576 nsCOMPtr
<nsIPrintingPromptService
> printPromptService(do_GetService(kPrintingPromptService
));
577 if (printPromptService
) {
578 nsIDOMWindow
*domWin
= mDocument
->GetWindow();
579 NS_ENSURE_TRUE(domWin
, NS_ERROR_FAILURE
);
581 // Platforms not implementing a given dialog for the service may
582 // return NS_ERROR_NOT_IMPLEMENTED or an error code.
584 // NS_ERROR_NOT_IMPLEMENTED indicates they want default behavior
585 // Any other error code means we must bail out
587 nsCOMPtr
<nsIWebBrowserPrint
> wbp(do_QueryInterface(mDocViewerPrint
));
588 rv
= printPromptService
->ShowPrintDialog(domWin
, wbp
,
589 mPrt
->mPrintSettings
);
590 if (rv
== NS_ERROR_NOT_IMPLEMENTED
) {
591 // This means the Dialog service was there,
592 // but they choose not to implement this dialog and
593 // are looking for default behavior from the toolkit
595 } else if (NS_SUCCEEDED(rv
)) {
596 // since we got the dialog and it worked then make sure we
597 // are telling GFX we want to print silent
598 printSilently
= PR_TRUE
;
600 // The user might have changed shrink-to-fit in the print dialog, so update our copy of its state
601 mPrt
->mPrintSettings
->GetShrinkToFit(&mPrt
->mShrinkToFit
);
603 rv
= NS_ERROR_GFX_NO_PRINTROMPTSERVICE
;
606 // Call any code that requires a run of the event loop.
607 rv
= mPrt
->mPrintSettings
->SetupSilentPrinting();
609 // Check explicitly for abort because it's expected
610 if (rv
== NS_ERROR_ABORT
)
612 NS_ENSURE_SUCCESS(rv
, rv
);
615 rv
= devspec
->Init(nsnull
, mPrt
->mPrintSettings
, aIsPrintPreview
);
616 NS_ENSURE_SUCCESS(rv
, rv
);
618 mPrt
->mPrintDC
= do_CreateInstance("@mozilla.org/gfx/devicecontext;1", &rv
);
619 NS_ENSURE_SUCCESS(rv
, rv
);
620 rv
= mPrt
->mPrintDC
->InitForPrinting(devspec
);
621 NS_ENSURE_SUCCESS(rv
, rv
);
623 if (aIsPrintPreview
) {
624 mPrt
->mPrintSettings
->SetPrintFrameType(nsIPrintSettings::kFramesAsIs
);
626 // override any UI that wants to PrintPreview any selection or page range
627 // we want to view every page in PrintPreview each time
628 mPrt
->mPrintSettings
->SetPrintRange(nsIPrintSettings::kRangeAllPages
);
630 // Always check and set the print settings first and then fall back
631 // onto the PrintService if there isn't a PrintSettings
633 // Posiible Usage values:
634 // nsIPrintSettings::kUseInternalDefault
635 // nsIPrintSettings::kUseSettingWhenPossible
637 // NOTE: The consts are the same for PrintSettings and PrintSettings
638 PRInt16 printFrameTypeUsage
= nsIPrintSettings::kUseSettingWhenPossible
;
639 mPrt
->mPrintSettings
->GetPrintFrameTypeUsage(&printFrameTypeUsage
);
641 // Ok, see if we are going to use our value and override the default
642 if (printFrameTypeUsage
== nsIPrintSettings::kUseSettingWhenPossible
) {
643 // Get the Print Options/Settings PrintFrameType to see what is preferred
644 PRInt16 printFrameType
= nsIPrintSettings::kEachFrameSep
;
645 mPrt
->mPrintSettings
->GetPrintFrameType(&printFrameType
);
647 // Don't let anybody do something stupid like try to set it to
648 // kNoFrames when we are printing a FrameSet
649 if (printFrameType
== nsIPrintSettings::kNoFrames
) {
650 mPrt
->mPrintFrameType
= nsIPrintSettings::kEachFrameSep
;
651 mPrt
->mPrintSettings
->SetPrintFrameType(mPrt
->mPrintFrameType
);
653 // First find out from the PrinService what options are available
654 // to us for Printing FrameSets
655 PRInt16 howToEnableFrameUI
;
656 mPrt
->mPrintSettings
->GetHowToEnableFrameUI(&howToEnableFrameUI
);
657 if (howToEnableFrameUI
!= nsIPrintSettings::kFrameEnableNone
) {
658 switch (howToEnableFrameUI
) {
659 case nsIPrintSettings::kFrameEnableAll
:
660 mPrt
->mPrintFrameType
= printFrameType
;
663 case nsIPrintSettings::kFrameEnableAsIsAndEach
:
664 if (printFrameType
!= nsIPrintSettings::kSelectedFrame
) {
665 mPrt
->mPrintFrameType
= printFrameType
;
666 } else { // revert back to a good value
667 mPrt
->mPrintFrameType
= nsIPrintSettings::kEachFrameSep
;
671 mPrt
->mPrintSettings
->SetPrintFrameType(mPrt
->mPrintFrameType
);
675 mPrt
->mPrintSettings
->GetPrintFrameType(&mPrt
->mPrintFrameType
);
679 if (aIsPrintPreview
) {
680 PRBool notifyOnInit
= PR_FALSE
;
681 ShowPrintProgress(PR_FALSE
, notifyOnInit
);
683 // Very important! Turn Off scripting
684 TurnScriptingOn(PR_FALSE
);
687 rv
= FinishPrintPreview();
691 NS_ENSURE_SUCCESS(rv
, rv
);
693 PRUnichar
* docTitleStr
;
694 PRUnichar
* docURLStr
;
696 GetDisplayTitleAndURL(mPrt
->mPrintObject
, &docTitleStr
, &docURLStr
, eDocTitleDefURLDoc
);
698 // Nobody ever cared about the file name passed in, as far as I can tell
699 rv
= mPrt
->mPrintDC
->PrepareDocument(docTitleStr
, nsnull
);
701 if (docTitleStr
) nsMemory::Free(docTitleStr
);
702 if (docURLStr
) nsMemory::Free(docURLStr
);
704 NS_ENSURE_SUCCESS(rv
, rv
);
707 ShowPrintProgress(PR_TRUE
, doNotify
);
709 // Print listener setup...
710 mPrt
->OnStartPrinting();
711 rv
= DocumentReadyForPrinting();
712 NS_ENSURE_SUCCESS(rv
, rv
);
719 //---------------------------------------------------------------------------------
721 nsPrintEngine::Print(nsIPrintSettings
* aPrintSettings
,
722 nsIWebProgressListener
* aWebProgressListener
)
724 return CommonPrint(PR_FALSE
, aPrintSettings
, aWebProgressListener
);
728 nsPrintEngine::PrintPreview(nsIPrintSettings
* aPrintSettings
,
729 nsIDOMWindow
*aChildDOMWin
,
730 nsIWebProgressListener
* aWebProgressListener
)
732 // Get the DocShell and see if it is busy
733 // (We can't Print Preview this document if it is still busy)
734 nsCOMPtr
<nsIDocShell
> docShell(do_QueryInterface(mContainer
));
735 NS_ASSERTION(docShell
, "This has to be a docshell");
737 PRUint32 busyFlags
= nsIDocShell::BUSY_FLAGS_NONE
;
738 if (NS_FAILED(docShell
->GetBusyFlags(&busyFlags
)) ||
739 busyFlags
!= nsIDocShell::BUSY_FLAGS_NONE
) {
740 CloseProgressDialog(aWebProgressListener
);
741 ShowPrintErrorDialog(NS_ERROR_GFX_PRINTER_DOC_IS_BUSY_PP
, PR_FALSE
);
742 return NS_ERROR_FAILURE
;
745 // Document is not busy -- go ahead with the Print Preview
746 return CommonPrint(PR_TRUE
, aPrintSettings
, aWebProgressListener
);
749 //----------------------------------------------------------------------------------
750 /* readonly attribute boolean isFramesetDocument; */
752 nsPrintEngine::GetIsFramesetDocument(PRBool
*aIsFramesetDocument
)
754 nsCOMPtr
<nsIDocShell
> webContainer(do_QueryInterface(mContainer
));
755 *aIsFramesetDocument
= IsParentAFrameSet(webContainer
);
759 //----------------------------------------------------------------------------------
760 /* readonly attribute boolean isIFrameSelected; */
762 nsPrintEngine::GetIsIFrameSelected(PRBool
*aIsIFrameSelected
)
764 *aIsIFrameSelected
= PR_FALSE
;
766 // Get the docshell for this documentviewer
767 nsCOMPtr
<nsIDocShell
> webContainer(do_QueryInterface(mContainer
));
768 // Get the currently focused window
769 nsCOMPtr
<nsIDOMWindow
> currentFocusWin
= FindFocusedDOMWindow();
770 if (currentFocusWin
&& webContainer
) {
771 // Get whether the doc contains a frameset
772 // Also, check to see if the currently focus docshell
773 // is a child of this docshell
774 PRPackedBool isParentFrameSet
;
775 *aIsIFrameSelected
= IsThereAnIFrameSelected(webContainer
, currentFocusWin
, isParentFrameSet
);
780 //----------------------------------------------------------------------------------
781 /* readonly attribute boolean isRangeSelection; */
783 nsPrintEngine::GetIsRangeSelection(PRBool
*aIsRangeSelection
)
785 // Get the currently focused window
786 nsCOMPtr
<nsIDOMWindow
> currentFocusWin
= FindFocusedDOMWindow();
787 *aIsRangeSelection
= IsThereARangeSelection(currentFocusWin
);
791 //----------------------------------------------------------------------------------
792 /* readonly attribute boolean isFramesetFrameSelected; */
794 nsPrintEngine::GetIsFramesetFrameSelected(PRBool
*aIsFramesetFrameSelected
)
796 // Get the currently focused window
797 nsCOMPtr
<nsIDOMWindow
> currentFocusWin
= FindFocusedDOMWindow();
798 *aIsFramesetFrameSelected
= currentFocusWin
!= nsnull
;
802 //----------------------------------------------------------------------------------
803 /* readonly attribute long printPreviewNumPages; */
805 nsPrintEngine::GetPrintPreviewNumPages(PRInt32
*aPrintPreviewNumPages
)
807 NS_ENSURE_ARG_POINTER(aPrintPreviewNumPages
);
809 nsIFrame
* seqFrame
= nsnull
;
810 *aPrintPreviewNumPages
= 0;
812 NS_FAILED(GetSeqFrameAndCountPagesInternal(mPrtPreview
->mPrintObject
, seqFrame
, *aPrintPreviewNumPages
))) {
813 return NS_ERROR_FAILURE
;
818 //----------------------------------------------------------------------------------
819 // Enumerate all the documents for their titles
821 nsPrintEngine::EnumerateDocumentNames(PRUint32
* aCount
,
822 PRUnichar
*** aResult
)
824 NS_ENSURE_ARG(aCount
);
825 NS_ENSURE_ARG_POINTER(aResult
);
830 PRInt32 numDocs
= mPrt
->mPrintDocList
->Count();
831 PRUnichar
** array
= (PRUnichar
**) nsMemory::Alloc(numDocs
* sizeof(PRUnichar
*));
833 return NS_ERROR_OUT_OF_MEMORY
;
835 for (PRInt32 i
=0;i
<numDocs
;i
++) {
836 nsPrintObject
* po
= (nsPrintObject
*)mPrt
->mPrintDocList
->ElementAt(i
);
837 NS_ASSERTION(po
, "nsPrintObject can't be null!");
838 PRUnichar
* docTitleStr
;
839 PRUnichar
* docURLStr
;
840 GetDocumentTitleAndURL(po
->mDocument
, &docTitleStr
, &docURLStr
);
842 // Use the URL if the doc is empty
843 if (!docTitleStr
|| !*docTitleStr
) {
844 if (docURLStr
&& *docURLStr
) {
845 nsMemory::Free(docTitleStr
);
846 docTitleStr
= docURLStr
;
848 nsMemory::Free(docURLStr
);
851 if (!docTitleStr
|| !*docTitleStr
) {
852 CleanupDocTitleArray(array
, i
);
853 return NS_ERROR_OUT_OF_MEMORY
;
856 array
[i
] = docTitleStr
;
857 if (docURLStr
) nsMemory::Free(docURLStr
);
866 //----------------------------------------------------------------------------------
867 /* readonly attribute nsIPrintSettings globalPrintSettings; */
869 nsPrintEngine::GetGlobalPrintSettings(nsIPrintSettings
**aGlobalPrintSettings
)
871 NS_ENSURE_ARG_POINTER(aGlobalPrintSettings
);
873 nsresult rv
= NS_ERROR_FAILURE
;
874 nsCOMPtr
<nsIPrintSettingsService
> printSettingsService
=
875 do_GetService(sPrintSettingsServiceContractID
, &rv
);
876 if (NS_SUCCEEDED(rv
)) {
877 rv
= printSettingsService
->GetGlobalPrintSettings(aGlobalPrintSettings
);
882 //----------------------------------------------------------------------------------
883 /* readonly attribute boolean doingPrint; */
885 nsPrintEngine::GetDoingPrint(PRBool
*aDoingPrint
)
887 NS_ENSURE_ARG_POINTER(aDoingPrint
);
888 *aDoingPrint
= mIsDoingPrinting
;
892 //----------------------------------------------------------------------------------
893 /* readonly attribute boolean doingPrintPreview; */
895 nsPrintEngine::GetDoingPrintPreview(PRBool
*aDoingPrintPreview
)
897 NS_ENSURE_ARG_POINTER(aDoingPrintPreview
);
898 *aDoingPrintPreview
= mIsDoingPrintPreview
;
902 //----------------------------------------------------------------------------------
903 /* readonly attribute nsIPrintSettings currentPrintSettings; */
905 nsPrintEngine::GetCurrentPrintSettings(nsIPrintSettings
* *aCurrentPrintSettings
)
907 NS_ENSURE_ARG_POINTER(aCurrentPrintSettings
);
910 *aCurrentPrintSettings
= mPrt
->mPrintSettings
;
912 } else if (mPrtPreview
) {
913 *aCurrentPrintSettings
= mPrtPreview
->mPrintSettings
;
916 *aCurrentPrintSettings
= nsnull
;
918 NS_IF_ADDREF(*aCurrentPrintSettings
);
922 //-----------------------------------------------------------------
923 //-- Section: Pre-Reflow Methods
924 //-----------------------------------------------------------------
926 //---------------------------------------------------------------------
927 // This method checks to see if there is at least one printer defined
928 // and if so, it sets the first printer in the list as the default name
929 // in the PrintSettings which is then used for Printer Preview
931 nsPrintEngine::CheckForPrinters(nsIPrintSettings
* aPrintSettings
)
934 // Mac doesn't support retrieving a printer list.
937 NS_ENSURE_ARG_POINTER(aPrintSettings
);
939 // See if aPrintSettings already has a printer
940 nsXPIDLString printerName
;
941 nsresult rv
= aPrintSettings
->GetPrinterName(getter_Copies(printerName
));
942 if (NS_SUCCEEDED(rv
) && !printerName
.IsEmpty()) {
946 // aPrintSettings doesn't have a printer set. Try to fetch the default.
947 nsCOMPtr
<nsIPrintSettingsService
> printSettingsService
=
948 do_GetService(sPrintSettingsServiceContractID
, &rv
);
949 NS_ENSURE_SUCCESS(rv
, rv
);
951 rv
= printSettingsService
->GetDefaultPrinterName(getter_Copies(printerName
));
952 if (NS_SUCCEEDED(rv
) && !printerName
.IsEmpty()) {
953 rv
= aPrintSettings
->SetPrinterName(printerName
.get());
959 //----------------------------------------------------------------------
960 // Set up to use the "pluggable" Print Progress Dialog
962 nsPrintEngine::ShowPrintProgress(PRBool aIsForPrinting
, PRBool
& aDoNotify
)
964 // default to not notifying, that if something here goes wrong
965 // or we aren't going to show the progress dialog we can straight into
966 // reflowing the doc for printing.
967 aDoNotify
= PR_FALSE
;
969 // Assume we can't do progress and then see if we can
970 PRBool showProgresssDialog
= PR_FALSE
;
972 // if it is already being shown then don't bother to find out if it should be
973 // so skip this and leave mShowProgressDialog set to FALSE
974 if (!mProgressDialogIsShown
) {
975 showProgresssDialog
=
976 nsContentUtils::GetBoolPref("print.show_print_progress");
979 // Turning off the showing of Print Progress in Prefs overrides
980 // whether the calling PS desire to have it on or off, so only check PS if
981 // prefs says it's ok to be on.
982 if (showProgresssDialog
) {
983 mPrt
->mPrintSettings
->GetShowPrintProgress(&showProgresssDialog
);
986 // Now open the service to get the progress dialog
987 // If we don't get a service, that's ok, then just don't show progress
988 if (showProgresssDialog
) {
989 nsCOMPtr
<nsIPrintingPromptService
> printPromptService(do_GetService(kPrintingPromptService
));
990 if (printPromptService
) {
991 nsPIDOMWindow
*domWin
= mDocument
->GetWindow();
994 nsCOMPtr
<nsIDocShellTreeItem
> docShellItem
=
995 do_QueryInterface(domWin
->GetDocShell());
996 if (!docShellItem
) return;
997 nsCOMPtr
<nsIDocShellTreeOwner
> owner
;
998 docShellItem
->GetTreeOwner(getter_AddRefs(owner
));
999 nsCOMPtr
<nsIWebBrowserChrome
> browserChrome
= do_GetInterface(owner
);
1000 if (!browserChrome
) return;
1001 PRBool isModal
= PR_TRUE
;
1002 browserChrome
->IsWindowModal(&isModal
);
1004 // Showing a print progress dialog when printing a modal window
1005 // isn't supported. See bug 301560.
1009 nsCOMPtr
<nsIWebProgressListener
> printProgressListener
;
1011 nsCOMPtr
<nsIWebBrowserPrint
> wbp(do_QueryInterface(mDocViewerPrint
));
1012 nsresult rv
= printPromptService
->ShowProgress(domWin
, wbp
, mPrt
->mPrintSettings
, this, aIsForPrinting
,
1013 getter_AddRefs(printProgressListener
),
1014 getter_AddRefs(mPrt
->mPrintProgressParams
),
1016 if (NS_SUCCEEDED(rv
)) {
1017 if (printProgressListener
&& mPrt
->mPrintProgressParams
) {
1018 mPrt
->mPrintProgressListeners
.AppendObject(printProgressListener
);
1019 SetDocAndURLIntoProgress(mPrt
->mPrintObject
, mPrt
->mPrintProgressParams
);
1026 //---------------------------------------------------------------------
1028 nsPrintEngine::IsThereARangeSelection(nsIDOMWindow
* aDOMWin
)
1030 nsCOMPtr
<nsIPresShell
> presShell
;
1032 nsCOMPtr
<nsPIDOMWindow
> window(do_QueryInterface(aDOMWin
));
1033 window
->GetDocShell()->GetPresShell(getter_AddRefs(presShell
));
1039 // check here to see if there is a range selection
1040 // so we know whether to turn on the "Selection" radio button
1041 nsCOMPtr
<nsISelection
> selection
;
1042 selection
= presShell
->GetCurrentSelection(nsISelectionController::SELECTION_NORMAL
);
1045 selection
->GetRangeCount(&count
);
1047 nsCOMPtr
<nsIDOMRange
> range
;
1048 if (NS_SUCCEEDED(selection
->GetRangeAt(0, getter_AddRefs(range
)))) {
1049 // check to make sure it isn't an insertion selection
1051 selection
->GetIsCollapsed(&isCollapsed
);
1052 return !isCollapsed
;
1055 if (count
> 1) return PR_TRUE
;
1060 //---------------------------------------------------------------------
1062 nsPrintEngine::IsParentAFrameSet(nsIDocShell
* aParent
)
1064 NS_ASSERTION(aParent
, "Pointer is null!");
1066 nsCOMPtr
<nsIPresShell
> shell
;
1067 aParent
->GetPresShell(getter_AddRefs(shell
));
1068 NS_ASSERTION(shell
, "shell can't be null");
1070 // See if the incoming doc is the root document
1071 nsCOMPtr
<nsIDocShellTreeItem
> parentAsItem(do_QueryInterface(aParent
));
1072 if (!parentAsItem
) return PR_FALSE
;
1074 // When it is the top level document we need to check
1075 // to see if it contains a frameset. If it does, then
1076 // we only want to print the doc's children and not the document itself
1077 // For anything else we always print all the children and the document
1078 // for example, if the doc contains an IFRAME we eant to print the child
1079 // document (the IFRAME) and then the rest of the document.
1081 // XXX we really need to search the frame tree, and not the content
1082 // but there is no way to distinguish between IFRAMEs and FRAMEs
1083 // with the GetFrameType call.
1084 // Bug 53459 has been files so we can eventually distinguish
1085 // between IFRAME frames and FRAME frames
1086 PRBool isFrameSet
= PR_FALSE
;
1087 // only check to see if there is a frameset if there is
1088 // NO parent doc for this doc. meaning this parent is the root doc
1090 nsIDocument
*doc
= shell
->GetDocument();
1092 nsIContent
*rootContent
= doc
->GetRootContent();
1094 isFrameSet
= HasFramesetChild(rootContent
);
1102 //---------------------------------------------------------------------
1103 // Recursively build a list of sub documents to be printed
1104 // that mirrors the document tree
1106 nsPrintEngine::BuildDocTree(nsIDocShellTreeNode
* aParentNode
,
1107 nsVoidArray
* aDocList
,
1108 nsPrintObject
* aPO
)
1110 NS_ASSERTION(aParentNode
, "Pointer is null!");
1111 NS_ASSERTION(aDocList
, "Pointer is null!");
1112 NS_ASSERTION(aPO
, "Pointer is null!");
1114 PRInt32 childWebshellCount
;
1115 aParentNode
->GetChildCount(&childWebshellCount
);
1116 if (childWebshellCount
> 0) {
1117 for (PRInt32 i
=0;i
<childWebshellCount
;i
++) {
1118 nsCOMPtr
<nsIDocShellTreeItem
> child
;
1119 aParentNode
->GetChildAt(i
, getter_AddRefs(child
));
1120 nsCOMPtr
<nsIDocShell
> childAsShell(do_QueryInterface(child
));
1122 nsCOMPtr
<nsIContentViewer
> viewer
;
1123 childAsShell
->GetContentViewer(getter_AddRefs(viewer
));
1125 nsCOMPtr
<nsIContentViewerFile
> viewerFile(do_QueryInterface(viewer
));
1127 nsCOMPtr
<nsIDocShell
> childDocShell(do_QueryInterface(child
));
1128 nsCOMPtr
<nsIDocShellTreeNode
> childNode(do_QueryInterface(child
));
1129 nsPrintObject
* po
= new nsPrintObject();
1130 nsresult rv
= po
->Init(childDocShell
);
1132 NS_NOTREACHED("Init failed?");
1134 aPO
->mKids
.AppendElement(po
);
1135 aDocList
->AppendElement(po
);
1136 BuildDocTree(childNode
, aDocList
, po
);
1143 //---------------------------------------------------------------------
1145 nsPrintEngine::GetDocumentTitleAndURL(nsIDocument
* aDoc
,
1147 PRUnichar
** aURLStr
)
1149 NS_ASSERTION(aDoc
, "Pointer is null!");
1150 NS_ASSERTION(aTitle
, "Pointer is null!");
1151 NS_ASSERTION(aURLStr
, "Pointer is null!");
1156 const nsAString
&docTitle
= aDoc
->GetDocumentTitle();
1157 if (!docTitle
.IsEmpty()) {
1158 *aTitle
= ToNewUnicode(docTitle
);
1161 nsIURI
* url
= aDoc
->GetDocumentURI();
1164 nsCOMPtr
<nsIURIFixup
> urifixup(do_GetService(NS_URIFIXUP_CONTRACTID
));
1165 if (!urifixup
) return;
1167 nsCOMPtr
<nsIURI
> exposableURI
;
1168 urifixup
->CreateExposableURI(url
, getter_AddRefs(exposableURI
));
1170 if (!exposableURI
) return;
1172 nsCAutoString urlCStr
;
1173 exposableURI
->GetSpec(urlCStr
);
1174 *aURLStr
= UTF8ToNewUnicode(urlCStr
);
1177 //---------------------------------------------------------------------
1178 // The walks the PO tree and for each document it walks the content
1179 // tree looking for any content that are sub-shells
1181 // It then sets the mContent pointer in the "found" PO object back to the
1182 // the document that contained it.
1184 nsPrintEngine::MapContentToWebShells(nsPrintObject
* aRootPO
,
1187 NS_ASSERTION(aRootPO
, "Pointer is null!");
1188 NS_ASSERTION(aPO
, "Pointer is null!");
1190 // Recursively walk the content from the root item
1191 // XXX Would be faster to enumerate the subdocuments, although right now
1192 // nsIDocument doesn't expose quite what would be needed.
1193 MapContentForPO(aPO
, aPO
->mDocument
->GetRootContent());
1195 // Continue recursively walking the chilren of this PO
1196 for (PRInt32 i
=0;i
<aPO
->mKids
.Count();i
++) {
1197 MapContentToWebShells(aRootPO
, (nsPrintObject
*)aPO
->mKids
[i
]);
1202 //-------------------------------------------------------
1203 // A Frame's sub-doc may contain content or a FrameSet
1204 // When it contains a FrameSet the mFrameType for the PrintObject
1205 // is always set to an eFrame. Which is fine when printing "AsIs"
1206 // but is incorrect when when printing "Each Frame Separately".
1207 // When printing "Each Frame Separately" the Frame really acts like
1210 // This method walks the PO tree and checks to see if the PrintObject is
1211 // an eFrame and has children that are eFrames (meaning it's a Frame containing a FrameSet)
1212 // If so, then the mFrameType need to be changed to eFrameSet
1214 // Also note: We only want to call this we are printing "Each Frame Separately"
1215 // when printing "As Is" leave it as an eFrame
1217 nsPrintEngine::CheckForChildFrameSets(nsPrintObject
* aPO
)
1219 NS_ASSERTION(aPO
, "Pointer is null!");
1221 // Continue recursively walking the chilren of this PO
1222 PRBool hasChildFrames
= PR_FALSE
;
1223 for (PRInt32 i
=0;i
<aPO
->mKids
.Count();i
++) {
1224 nsPrintObject
* po
= (nsPrintObject
*)aPO
->mKids
[i
];
1225 if (po
->mFrameType
== eFrame
) {
1226 hasChildFrames
= PR_TRUE
;
1227 CheckForChildFrameSets(po
);
1231 if (hasChildFrames
&& aPO
->mFrameType
== eFrame
) {
1232 aPO
->mFrameType
= eFrameSet
;
1236 //---------------------------------------------------------------------
1237 // This method is key to the entire print mechanism.
1239 // This "maps" or figures out which sub-doc represents a
1240 // given Frame or IFrame in its parent sub-doc.
1242 // So the Mcontent pointer in the child sub-doc points to the
1243 // content in the its parent document, that caused it to be printed.
1244 // This is used later to (after reflow) to find the absolute location
1245 // of the sub-doc on its parent's page frame so it can be
1246 // printed in the correct location.
1248 // This method recursvely "walks" the content for a document finding
1249 // all the Frames and IFrames, then sets the "mFrameType" data member
1250 // which tells us what type of PO we have
1252 nsPrintEngine::MapContentForPO(nsPrintObject
* aPO
,
1253 nsIContent
* aContent
)
1255 NS_PRECONDITION(aPO
&& aContent
, "Null argument");
1257 nsIDocument
* doc
= aContent
->GetDocument();
1259 NS_ASSERTION(doc
, "Content without a document from a document tree?");
1261 nsIDocument
* subDoc
= doc
->GetSubDocumentFor(aContent
);
1264 nsCOMPtr
<nsISupports
> container
= subDoc
->GetContainer();
1265 nsCOMPtr
<nsIDocShell
> docShell(do_QueryInterface(container
));
1268 nsPrintObject
* po
= nsnull
;
1269 PRInt32 cnt
= aPO
->mKids
.Count();
1270 for (PRInt32 i
=0;i
<cnt
;i
++) {
1271 nsPrintObject
* kid
= (nsPrintObject
*)aPO
->mKids
.ElementAt(i
);
1272 if (kid
->mDocument
== subDoc
) {
1278 // XXX If a subdocument has no onscreen presentation, there will be no PO
1279 // This is even if there should be a print presentation
1281 po
->mContent
= aContent
;
1283 nsCOMPtr
<nsIDOMHTMLFrameElement
> frame(do_QueryInterface(aContent
));
1284 // "frame" elements not in a frameset context should be treated
1286 if (frame
&& po
->mParent
->mFrameType
== eFrameSet
) {
1287 po
->mFrameType
= eFrame
;
1289 // Assume something iframe-like, i.e. iframe, object, or embed
1290 po
->mFrameType
= eIFrame
;
1291 SetPrintAsIs(po
, PR_TRUE
);
1292 NS_ASSERTION(po
->mParent
, "The root must be a parent");
1293 po
->mParent
->mPrintAsIs
= PR_TRUE
;
1299 // walk children content
1300 PRUint32 count
= aContent
->GetChildCount();
1301 for (PRUint32 i
= 0; i
< count
; ++i
) {
1302 nsIContent
*child
= aContent
->GetChildAt(i
);
1303 MapContentForPO(aPO
, child
);
1307 //---------------------------------------------------------------------
1309 nsPrintEngine::IsThereAnIFrameSelected(nsIDocShell
* aDocShell
,
1310 nsIDOMWindow
* aDOMWin
,
1311 PRPackedBool
& aIsParentFrameSet
)
1313 aIsParentFrameSet
= IsParentAFrameSet(aDocShell
);
1314 PRBool iFrameIsSelected
= PR_FALSE
;
1315 if (mPrt
&& mPrt
->mPrintObject
) {
1316 nsPrintObject
* po
= FindPrintObjectByDOMWin(mPrt
->mPrintObject
, aDOMWin
);
1317 iFrameIsSelected
= po
&& po
->mFrameType
== eIFrame
;
1319 // First, check to see if we are a frameset
1320 if (!aIsParentFrameSet
) {
1321 // Check to see if there is a currenlt focused frame
1322 // if so, it means the selected frame is either the main docshell
1325 // Get the main docshell's DOMWin to see if it matches
1326 // the frame that is selected
1327 nsCOMPtr
<nsIDOMWindow
> domWin
= do_GetInterface(aDocShell
);
1328 if (domWin
!= aDOMWin
) {
1329 iFrameIsSelected
= PR_TRUE
; // we have a selected IFRAME
1335 return iFrameIsSelected
;
1338 //---------------------------------------------------------------------
1339 // Recursively sets all the PO items to be printed
1340 // from the given item down into the tree
1342 nsPrintEngine::SetPrintPO(nsPrintObject
* aPO
, PRBool aPrint
)
1344 NS_ASSERTION(aPO
, "Pointer is null!");
1346 // Set whether to print flag
1347 aPO
->mDontPrint
= !aPrint
;
1349 for (PRInt32 i
=0;i
<aPO
->mKids
.Count();i
++) {
1350 SetPrintPO((nsPrintObject
*)aPO
->mKids
[i
], aPrint
);
1354 //---------------------------------------------------------------------
1355 // This will first use a Title and/or URL from the PrintSettings
1356 // if one isn't set then it uses the one from the document
1357 // then if not title is there we will make sure we send something back
1358 // depending on the situation.
1360 nsPrintEngine::GetDisplayTitleAndURL(nsPrintObject
* aPO
,
1362 PRUnichar
** aURLStr
,
1363 eDocTitleDefault aDefType
)
1365 NS_ASSERTION(aPO
, "Pointer is null!");
1366 NS_ASSERTION(aTitle
, "Pointer is null!");
1367 NS_ASSERTION(aURLStr
, "Pointer is null!");
1375 // First check to see if the PrintSettings has defined an alternate title
1376 // and use that if it did
1377 PRUnichar
* docTitleStrPS
= nsnull
;
1378 PRUnichar
* docURLStrPS
= nsnull
;
1379 if (mPrt
->mPrintSettings
) {
1380 mPrt
->mPrintSettings
->GetTitle(&docTitleStrPS
);
1381 mPrt
->mPrintSettings
->GetDocURL(&docURLStrPS
);
1383 if (docTitleStrPS
&& *docTitleStrPS
) {
1384 *aTitle
= docTitleStrPS
;
1387 if (docURLStrPS
&& *docURLStrPS
) {
1388 *aURLStr
= docURLStrPS
;
1392 if (docTitleStrPS
&& docURLStrPS
) {
1397 PRUnichar
* docTitle
;
1399 GetDocumentTitleAndURL(aPO
->mDocument
, &docTitle
, &docUrl
);
1405 nsMemory::Free(docUrl
);
1412 nsMemory::Free(docTitle
);
1413 } else if (!docTitleStrPS
) {
1415 case eDocTitleDefBlank
: *aTitle
= ToNewUnicode(EmptyString());
1418 case eDocTitleDefURLDoc
:
1420 *aTitle
= NS_strdup(*aURLStr
);
1421 } else if (mPrt
->mBrandName
) {
1422 *aTitle
= NS_strdup(mPrt
->mBrandName
);
1429 //---------------------------------------------------------------------
1430 nsresult
nsPrintEngine::DocumentReadyForPrinting()
1432 if (mPrt
->mPrintFrameType
== nsIPrintSettings::kEachFrameSep
) {
1433 CheckForChildFrameSets(mPrt
->mPrintObject
);
1437 // Send the document to the printer...
1439 nsresult rv
= SetupToPrintContent();
1440 if (NS_FAILED(rv
)) {
1441 // The print job was canceled or there was a problem
1442 // So remove all other documents from the print list
1443 DonePrintingPages(nsnull
, rv
);
1448 /** ---------------------------------------------------
1449 * Cleans up when an error occurred
1451 nsresult
nsPrintEngine::CleanupOnFailure(nsresult aResult
, PRBool aIsPrinting
)
1453 PR_PL(("**** Failed %s - rv 0x%X", aIsPrinting
?"Printing":"Print Preview", aResult
));
1456 if (mPagePrintTimer
) {
1457 mPagePrintTimer
->Stop();
1458 NS_RELEASE(mPagePrintTimer
);
1462 SetIsPrinting(PR_FALSE
);
1464 SetIsPrintPreview(PR_FALSE
);
1465 SetIsCreatingPrintPreview(PR_FALSE
);
1468 /* cleanup done, let's fire-up an error dialog to notify the user
1469 * what went wrong...
1471 * When rv == NS_ERROR_ABORT, it means we want out of the
1472 * print job without displaying any error messages
1474 if (aResult
!= NS_ERROR_ABORT
) {
1475 ShowPrintErrorDialog(aResult
, aIsPrinting
);
1478 FirePrintCompletionEvent();
1484 //---------------------------------------------------------------------
1486 nsPrintEngine::ShowPrintErrorDialog(nsresult aPrintError
, PRBool aIsPrinting
)
1489 PR_PL(("nsPrintEngine::ShowPrintErrorDialog(nsresult aPrintError=%lx, PRBool aIsPrinting=%d)\n", (long)aPrintError
, (int)aIsPrinting
));
1491 nsCAutoString stringName
;
1495 #define NS_ERROR_TO_LOCALIZED_PRINT_ERROR_MSG(nserr) case nserr: stringName.AssignLiteral(#nserr); break;
1496 NS_ERROR_TO_LOCALIZED_PRINT_ERROR_MSG(NS_ERROR_GFX_PRINTER_CMD_NOT_FOUND
)
1497 NS_ERROR_TO_LOCALIZED_PRINT_ERROR_MSG(NS_ERROR_GFX_PRINTER_CMD_FAILURE
)
1498 NS_ERROR_TO_LOCALIZED_PRINT_ERROR_MSG(NS_ERROR_GFX_PRINTER_NO_PRINTER_AVAILABLE
)
1499 NS_ERROR_TO_LOCALIZED_PRINT_ERROR_MSG(NS_ERROR_GFX_PRINTER_NAME_NOT_FOUND
)
1500 NS_ERROR_TO_LOCALIZED_PRINT_ERROR_MSG(NS_ERROR_GFX_PRINTER_ACCESS_DENIED
)
1501 NS_ERROR_TO_LOCALIZED_PRINT_ERROR_MSG(NS_ERROR_GFX_PRINTER_INVALID_ATTRIBUTE
)
1502 NS_ERROR_TO_LOCALIZED_PRINT_ERROR_MSG(NS_ERROR_GFX_PRINTER_PRINTER_NOT_READY
)
1503 NS_ERROR_TO_LOCALIZED_PRINT_ERROR_MSG(NS_ERROR_GFX_PRINTER_OUT_OF_PAPER
)
1504 NS_ERROR_TO_LOCALIZED_PRINT_ERROR_MSG(NS_ERROR_GFX_PRINTER_PRINTER_IO_ERROR
)
1505 NS_ERROR_TO_LOCALIZED_PRINT_ERROR_MSG(NS_ERROR_GFX_PRINTER_COULD_NOT_OPEN_FILE
)
1506 NS_ERROR_TO_LOCALIZED_PRINT_ERROR_MSG(NS_ERROR_GFX_PRINTER_FILE_IO_ERROR
)
1507 NS_ERROR_TO_LOCALIZED_PRINT_ERROR_MSG(NS_ERROR_GFX_PRINTER_PRINTPREVIEW
)
1508 NS_ERROR_TO_LOCALIZED_PRINT_ERROR_MSG(NS_ERROR_UNEXPECTED
)
1509 NS_ERROR_TO_LOCALIZED_PRINT_ERROR_MSG(NS_ERROR_OUT_OF_MEMORY
)
1510 NS_ERROR_TO_LOCALIZED_PRINT_ERROR_MSG(NS_ERROR_NOT_IMPLEMENTED
)
1511 NS_ERROR_TO_LOCALIZED_PRINT_ERROR_MSG(NS_ERROR_NOT_AVAILABLE
)
1512 NS_ERROR_TO_LOCALIZED_PRINT_ERROR_MSG(NS_ERROR_ABORT
)
1513 NS_ERROR_TO_LOCALIZED_PRINT_ERROR_MSG(NS_ERROR_GFX_PRINTER_STARTDOC
)
1514 NS_ERROR_TO_LOCALIZED_PRINT_ERROR_MSG(NS_ERROR_GFX_PRINTER_ENDDOC
)
1515 NS_ERROR_TO_LOCALIZED_PRINT_ERROR_MSG(NS_ERROR_GFX_PRINTER_STARTPAGE
)
1516 NS_ERROR_TO_LOCALIZED_PRINT_ERROR_MSG(NS_ERROR_GFX_PRINTER_ENDPAGE
)
1517 NS_ERROR_TO_LOCALIZED_PRINT_ERROR_MSG(NS_ERROR_GFX_PRINTER_PRINT_WHILE_PREVIEW
)
1518 NS_ERROR_TO_LOCALIZED_PRINT_ERROR_MSG(NS_ERROR_GFX_PRINTER_PAPER_SIZE_NOT_SUPPORTED
)
1519 NS_ERROR_TO_LOCALIZED_PRINT_ERROR_MSG(NS_ERROR_GFX_PRINTER_ORIENTATION_NOT_SUPPORTED
)
1520 NS_ERROR_TO_LOCALIZED_PRINT_ERROR_MSG(NS_ERROR_GFX_PRINTER_COLORSPACE_NOT_SUPPORTED
)
1521 NS_ERROR_TO_LOCALIZED_PRINT_ERROR_MSG(NS_ERROR_GFX_PRINTER_TOO_MANY_COPIES
)
1522 NS_ERROR_TO_LOCALIZED_PRINT_ERROR_MSG(NS_ERROR_GFX_PRINTER_DRIVER_CONFIGURATION_ERROR
)
1523 NS_ERROR_TO_LOCALIZED_PRINT_ERROR_MSG(NS_ERROR_GFX_PRINTER_DOC_IS_BUSY_PP
)
1524 NS_ERROR_TO_LOCALIZED_PRINT_ERROR_MSG(NS_ERROR_GFX_PRINTER_DOC_WAS_DESTORYED
)
1525 NS_ERROR_TO_LOCALIZED_PRINT_ERROR_MSG(NS_ERROR_GFX_NO_PRINTDIALOG_IN_TOOLKIT
)
1526 NS_ERROR_TO_LOCALIZED_PRINT_ERROR_MSG(NS_ERROR_GFX_NO_PRINTROMPTSERVICE
)
1527 NS_ERROR_TO_LOCALIZED_PRINT_ERROR_MSG(NS_ERROR_GFX_PRINTER_NO_XUL
) // Temporary code for Bug 136185 / bug 240490
1528 NS_ERROR_TO_LOCALIZED_PRINT_ERROR_MSG(NS_ERROR_GFX_PRINTER_PLEX_NOT_SUPPORTED
)
1529 NS_ERROR_TO_LOCALIZED_PRINT_ERROR_MSG(NS_ERROR_GFX_PRINTER_DOC_IS_BUSY
)
1530 NS_ERROR_TO_LOCALIZED_PRINT_ERROR_MSG(NS_ERROR_GFX_PRINTING_NOT_IMPLEMENTED
)
1531 NS_ERROR_TO_LOCALIZED_PRINT_ERROR_MSG(NS_ERROR_GFX_COULD_NOT_LOAD_PRINT_MODULE
)
1532 NS_ERROR_TO_LOCALIZED_PRINT_ERROR_MSG(NS_ERROR_GFX_PRINTER_RESOLUTION_NOT_SUPPORTED
)
1535 NS_ERROR_TO_LOCALIZED_PRINT_ERROR_MSG(NS_ERROR_FAILURE
)
1536 #undef NS_ERROR_TO_LOCALIZED_PRINT_ERROR_MSG
1539 PR_PL(("ShowPrintErrorDialog: stringName='%s'\n", stringName
.get()));
1541 nsXPIDLString msg
, title
;
1543 nsContentUtils::GetLocalizedString(nsContentUtils::ePRINTING_PROPERTIES
,
1544 stringName
.get(), msg
);
1545 if (NS_FAILED(rv
)) {
1546 PR_PL(("GetLocalizedString failed\n"));
1550 rv
= nsContentUtils::GetLocalizedString(nsContentUtils::ePRINTING_PROPERTIES
,
1551 aIsPrinting
? "print_error_dialog_title"
1552 : "printpreview_error_dialog_title",
1555 nsCOMPtr
<nsIWindowWatcher
> wwatch
= do_GetService(NS_WINDOWWATCHER_CONTRACTID
, &rv
);
1556 if (NS_FAILED(rv
)) {
1557 PR_PL(("ShowPrintErrorDialog(): wwatch==nsnull\n"));
1561 nsCOMPtr
<nsIDOMWindow
> active
;
1562 wwatch
->GetActiveWindow(getter_AddRefs(active
));
1564 nsCOMPtr
<nsIPrompt
> dialog
;
1565 /* |GetNewPrompter| allows that |active| is |nsnull|
1566 * (see bug 234982 ("nsPrintEngine::ShowPrintErrorDialog() fails in many cases")) */
1567 wwatch
->GetNewPrompter(active
, getter_AddRefs(dialog
));
1569 PR_PL(("ShowPrintErrorDialog(): dialog==nsnull\n"));
1573 dialog
->Alert(title
.get(), msg
.get());
1574 PR_PL(("ShowPrintErrorDialog(): alert displayed successfully.\n"));
1577 //-----------------------------------------------------------------
1578 //-- Section: Reflow Methods
1579 //-----------------------------------------------------------------
1581 //-------------------------------------------------------
1583 nsPrintEngine::SetupToPrintContent()
1585 // In this step we figure out which documents should be printed
1586 // i.e. if we are printing the selection then only enable that nsPrintObject
1588 if (NS_FAILED(EnablePOsForPrinting())) {
1589 return NS_ERROR_FAILURE
;
1591 DUMP_DOC_LIST("\nAfter Enable------------------------------------------");
1593 // This is an Optimization
1594 // If we are in PP then we already know all the shrinkage information
1595 // so just transfer it to the PrintData and we will skip the extra shrinkage reflow
1597 // doSetPixelScale tells Reflow whether to set the shrinkage value into the DC
1598 // The first time we do not want to do this, the second time through we do
1599 PRBool doSetPixelScale
= PR_FALSE
;
1600 PRBool ppIsShrinkToFit
= mPrtPreview
&& mPrtPreview
->mShrinkToFit
;
1601 if (ppIsShrinkToFit
) {
1602 mPrt
->mShrinkRatio
= mPrtPreview
->mShrinkRatio
;
1603 doSetPixelScale
= PR_TRUE
;
1606 // Here we reflow all the PrintObjects
1607 nsresult rv
= ReflowDocList(mPrt
->mPrintObject
, doSetPixelScale
);
1608 if (NS_FAILED(rv
)) {
1609 return NS_ERROR_FAILURE
;
1612 // Here is where we do the extra reflow for shrinking the content
1613 // But skip this step if we are in PrintPreview
1614 if (mPrt
->mShrinkToFit
&& !ppIsShrinkToFit
) {
1615 // Now look for the PO that has the smallest percent for shrink to fit
1616 if (mPrt
->mPrintDocList
->Count() > 1 && mPrt
->mPrintObject
->mFrameType
== eFrameSet
) {
1617 nsPrintObject
* smallestPO
= FindSmallestSTF();
1618 NS_ASSERTION(smallestPO
, "There must always be an XMost PO!");
1620 // Calc the shrinkage based on the entire content area
1621 mPrt
->mShrinkRatio
= smallestPO
->mShrinkRatio
;
1624 // Single document so use the Shrink as calculated for the PO
1625 mPrt
->mShrinkRatio
= mPrt
->mPrintObject
->mShrinkRatio
;
1628 // Only Shrink if we are smaller
1629 if (mPrt
->mShrinkRatio
< 0.998f
) {
1630 // Clamp Shrink to Fit to 60%
1631 mPrt
->mShrinkRatio
= PR_MAX(mPrt
->mShrinkRatio
, 0.60f
);
1633 for (PRInt32 i
=0;i
<mPrt
->mPrintDocList
->Count();i
++) {
1634 nsPrintObject
* po
= (nsPrintObject
*)mPrt
->mPrintDocList
->ElementAt(i
);
1635 NS_ASSERTION(po
, "nsPrintObject can't be null!");
1636 // Wipe out the presentation before we reflow
1637 po
->DestroyPresentation();
1640 #if (defined(XP_WIN) || defined(XP_OS2)) && defined(EXTENDED_DEBUG_PRINTING)
1641 // We need to clear all the output files here
1642 // because they will be re-created with second reflow of the docs
1643 if (kPrintingLogMod
&& kPrintingLogMod
->level
== DUMP_LAYOUT_LEVEL
) {
1644 RemoveFilesInDir(".\\");
1645 gDumpFileNameCnt
= 0;
1646 gDumpLOFileNameCnt
= 0;
1650 // Here we reflow all the PrintObjects a second time
1651 // this time using the shrinkage values
1652 // The last param here tells reflow to NOT calc the shrinkage values
1653 if (NS_FAILED(ReflowDocList(mPrt
->mPrintObject
, PR_TRUE
))) {
1654 return NS_ERROR_FAILURE
;
1660 float calcRatio
= 0.0f
;
1661 if (mPrt
->mPrintDocList
->Count() > 1 && mPrt
->mPrintObject
->mFrameType
== eFrameSet
) {
1662 nsPrintObject
* smallestPO
= FindSmallestSTF();
1663 NS_ASSERTION(smallestPO
, "There must always be an XMost PO!");
1665 // Calc the shrinkage based on the entire content area
1666 calcRatio
= smallestPO
->mShrinkRatio
;
1669 // Single document so use the Shrink as calculated for the PO
1670 calcRatio
= mPrt
->mPrintObject
->mShrinkRatio
;
1672 PR_PL(("**************************************************************************\n"));
1673 PR_PL(("STF Ratio is: %8.5f Effective Ratio: %8.5f Diff: %8.5f\n", mPrt
->mShrinkRatio
, calcRatio
, mPrt
->mShrinkRatio
-calcRatio
));
1674 PR_PL(("**************************************************************************\n"));
1679 DUMP_DOC_LIST(("\nAfter Reflow------------------------------------------"));
1681 PR_PL(("-------------------------------------------------------\n"));
1684 CalcNumPrintablePages(mPrt
->mNumPrintablePages
);
1686 PR_PL(("--- Printing %d pages\n", mPrt
->mNumPrintablePages
));
1687 DUMP_DOC_TREELAYOUT
;
1689 // Print listener setup...
1690 if (mPrt
!= nsnull
) {
1691 mPrt
->OnStartPrinting();
1694 PRUnichar
* fileName
= nsnull
;
1695 // check to see if we are printing to a file
1696 PRBool isPrintToFile
= PR_FALSE
;
1697 mPrt
->mPrintSettings
->GetPrintToFile(&isPrintToFile
);
1698 if (isPrintToFile
) {
1699 // On some platforms The BeginDocument needs to know the name of the file
1700 // and it uses the PrintService to get it, so we need to set it into the PrintService here
1701 mPrt
->mPrintSettings
->GetToFileName(&fileName
);
1704 PRUnichar
* docTitleStr
;
1705 PRUnichar
* docURLStr
;
1706 GetDisplayTitleAndURL(mPrt
->mPrintObject
, &docTitleStr
, &docURLStr
, eDocTitleDefURLDoc
);
1708 PRInt32 startPage
= 1;
1709 PRInt32 endPage
= mPrt
->mNumPrintablePages
;
1711 PRInt16 printRangeType
= nsIPrintSettings::kRangeAllPages
;
1712 mPrt
->mPrintSettings
->GetPrintRange(&printRangeType
);
1713 if (printRangeType
== nsIPrintSettings::kRangeSpecifiedPageRange
) {
1714 mPrt
->mPrintSettings
->GetStartPageRange(&startPage
);
1715 mPrt
->mPrintSettings
->GetEndPageRange(&endPage
);
1716 if (endPage
> mPrt
->mNumPrintablePages
) {
1717 endPage
= mPrt
->mNumPrintablePages
;
1722 // BeginDocument may pass back a FAILURE code
1723 // i.e. On Windows, if you are printing to a file and hit "Cancel"
1724 // to the "File Name" dialog, this comes back as an error
1725 // Don't start printing when regression test are executed
1726 if (!mPrt
->mDebugFilePtr
&& mIsDoingPrinting
) {
1727 rv
= mPrt
->mPrintDC
->BeginDocument(docTitleStr
, fileName
, startPage
, endPage
);
1730 if (mIsCreatingPrintPreview
) {
1731 // Print Preview -- Pass ownership of docTitleStr and docURLStr
1732 // to the pageSequenceFrame, to be displayed in the header
1733 nsIPageSequenceFrame
*seqFrame
= nsnull
;
1734 mPrt
->mPrintObject
->mPresShell
->GetPageSequenceFrame(&seqFrame
);
1736 seqFrame
->StartPrint(mPrt
->mPrintObject
->mPresContext
,
1737 mPrt
->mPrintSettings
, docTitleStr
, docURLStr
);
1740 if (docTitleStr
) nsMemory::Free(docTitleStr
);
1741 if (docURLStr
) nsMemory::Free(docURLStr
);
1744 PR_PL(("****************** Begin Document ************************\n"));
1746 NS_ENSURE_SUCCESS(rv
, rv
);
1748 // This will print the docshell document
1749 // when it completes asynchronously in the DonePrintingPages method
1750 // it will check to see if there are more docshells to be printed and
1751 // then PrintDocContent will be called again.
1753 if (mIsDoingPrinting
) {
1754 PrintDocContent(mPrt
->mPrintObject
, rv
); // ignore return value
1760 //-------------------------------------------------------
1761 // Recursively reflow each sub-doc and then calc
1762 // all the frame locations of the sub-docs
1764 nsPrintEngine::ReflowDocList(nsPrintObject
* aPO
, PRBool aSetPixelScale
)
1766 NS_ENSURE_ARG_POINTER(aPO
);
1768 // Check to see if the subdocument's element has been hidden by the parent document
1769 if (aPO
->mParent
&& aPO
->mParent
->mPresShell
) {
1771 aPO
->mParent
->mPresShell
->GetPrimaryFrameFor(aPO
->mContent
);
1773 if (!frame
->GetStyleVisibility()->IsVisible()) {
1774 aPO
->mDontPrint
= PR_TRUE
;
1775 aPO
->mInvisible
= PR_TRUE
;
1781 // Here is where we set the shrinkage value into the DC
1782 // and this is what actually makes it shrink
1783 if (aSetPixelScale
&& aPO
->mFrameType
!= eIFrame
) {
1785 if (mPrt
->mPrintFrameType
== nsIPrintSettings::kFramesAsIs
|| mPrt
->mPrintFrameType
== nsIPrintSettings::kNoFrames
) {
1786 ratio
= mPrt
->mShrinkRatio
- 0.005f
; // round down
1788 ratio
= aPO
->mShrinkRatio
- 0.005f
; // round down
1790 aPO
->mZoomRatio
= ratio
;
1791 } else if (!mPrt
->mShrinkToFit
) {
1793 mPrt
->mPrintSettings
->GetScaling(&scaling
);
1794 aPO
->mZoomRatio
= float(scaling
);
1799 rv
= ReflowPrintObject(aPO
);
1800 NS_ENSURE_SUCCESS(rv
, rv
);
1802 PRInt32 cnt
= aPO
->mKids
.Count();
1803 for (PRInt32 i
=0;i
<cnt
;i
++) {
1804 rv
= ReflowDocList((nsPrintObject
*)aPO
->mKids
[i
], aSetPixelScale
);
1805 NS_ENSURE_SUCCESS(rv
, rv
);
1810 //-------------------------------------------------------
1811 // Reflow a nsPrintObject
1813 nsPrintEngine::ReflowPrintObject(nsPrintObject
* aPO
)
1815 NS_ASSERTION(aPO
, "Pointer is null!");
1816 if (!aPO
) return NS_ERROR_FAILURE
;
1819 PRBool documentIsTopLevel
;
1820 nsIFrame
* frame
= nsnull
;
1821 if (!aPO
->IsPrintable())
1824 if (aPO
->mParent
&& aPO
->mParent
->IsPrintable()) {
1825 if (aPO
->mParent
->mPresShell
) {
1826 frame
= aPO
->mParent
->mPresShell
->FrameManager()->
1827 GetPrimaryFrameFor(aPO
->mContent
, -1);
1829 // Without a frame, this document can't be displayed; therefore, there is no
1830 // point to reflowing it
1834 adjSize
= frame
->GetContentRect().Size();
1835 documentIsTopLevel
= PR_FALSE
;
1836 // presshell exists because parent is printable
1838 nscoord pageWidth
, pageHeight
;
1839 mPrt
->mPrintDC
->GetDeviceSurfaceDimensions(pageWidth
, pageHeight
);
1840 #if defined(XP_UNIX) && !defined(XP_MACOSX)
1841 // If we're in landscape mode on Linux, the device surface will have
1842 // been rotated, so for the purposes of reflowing content, we'll
1843 // treat device's height as our width and its width as our height,
1844 PRInt32 orientation
;
1845 mPrt
->mPrintSettings
->GetOrientation(&orientation
);
1846 if (nsIPrintSettings::kLandscapeOrientation
== orientation
) {
1847 adjSize
= nsSize(pageHeight
, pageWidth
);
1849 adjSize
= nsSize(pageWidth
, pageHeight
);
1852 adjSize
= nsSize(pageWidth
, pageHeight
);
1853 #endif // XP_UNIX && !XP_MACOSX
1854 documentIsTopLevel
= PR_TRUE
;
1857 // create the PresContext
1858 aPO
->mPresContext
= new nsPresContext(aPO
->mDocument
,
1859 mIsCreatingPrintPreview
?
1860 nsPresContext::eContext_PrintPreview
:
1861 nsPresContext::eContext_Print
);
1862 NS_ENSURE_TRUE(aPO
->mPresContext
, NS_ERROR_OUT_OF_MEMORY
);
1863 aPO
->mPresContext
->SetPrintSettings(mPrt
->mPrintSettings
);
1865 // set the presentation context to the value in the print settings
1866 PRBool printBGColors
;
1867 mPrt
->mPrintSettings
->GetPrintBGColors(&printBGColors
);
1868 aPO
->mPresContext
->SetBackgroundColorDraw(printBGColors
);
1869 mPrt
->mPrintSettings
->GetPrintBGImages(&printBGColors
);
1870 aPO
->mPresContext
->SetBackgroundImageDraw(printBGColors
);
1872 // init it with the DC
1873 nsresult rv
= aPO
->mPresContext
->Init(mPrt
->mPrintDC
);
1874 NS_ENSURE_SUCCESS(rv
, rv
);
1876 aPO
->mViewManager
= do_CreateInstance(kViewManagerCID
, &rv
);
1877 NS_ENSURE_SUCCESS(rv
,rv
);
1879 rv
= aPO
->mViewManager
->Init(mPrt
->mPrintDC
);
1880 NS_ENSURE_SUCCESS(rv
,rv
);
1882 nsStyleSet
* styleSet
;
1883 rv
= mDocViewerPrint
->CreateStyleSet(aPO
->mDocument
, &styleSet
);
1884 NS_ENSURE_SUCCESS(rv
, rv
);
1886 rv
= aPO
->mDocument
->CreateShell(aPO
->mPresContext
, aPO
->mViewManager
,
1887 styleSet
, getter_AddRefs(aPO
->mPresShell
));
1888 if (NS_FAILED(rv
)) {
1893 styleSet
->EndUpdate();
1895 // The pres shell now owns the style set object.
1897 PR_PL(("In DV::ReflowPrintObject PO: %p (%9s) Setting w,h to %d,%d\n", aPO
,
1898 gFrameTypesStr
[aPO
->mFrameType
], adjSize
.width
, adjSize
.height
));
1900 // Here we decide whether we need scrollbars and
1901 // what the parent will be of the widget
1902 // How this logic presently works: Print Preview is always as-is (as far
1903 // as I can tell; not sure how it would work in other cases); only the root
1904 // is not eIFrame or eFrame. The child documents get a parent widget from
1905 // logic in nsFrameFrame. In any case, a child widget is created for the root
1906 // view of the document.
1907 PRBool canCreateScrollbars
= PR_FALSE
;
1908 nsIView
* parentView
;
1909 // the top nsPrintObject's widget will always have scrollbars
1911 nsIView
* view
= frame
->GetView();
1912 NS_ENSURE_TRUE(view
, NS_ERROR_FAILURE
);
1913 view
= view
->GetFirstChild();
1914 NS_ENSURE_TRUE(view
, NS_ERROR_FAILURE
);
1917 canCreateScrollbars
= PR_TRUE
;
1918 parentView
= nsnull
;
1921 // Create a child window of the parent that is our "root view/window"
1922 nsRect tbounds
= nsRect(nsPoint(0, 0), adjSize
);
1923 nsIView
* rootView
= aPO
->mViewManager
->CreateView(tbounds
, parentView
);
1924 NS_ENSURE_TRUE(rootView
, NS_ERROR_OUT_OF_MEMORY
);
1926 // Only create a widget for print preview; when printing, a widget is
1927 // unnecessary and unexpected
1928 // Also, no widget should be needed except for the top-level document
1929 if (mIsCreatingPrintPreview
&& documentIsTopLevel
) {
1930 nsNativeWidget widget
= nsnull
;
1932 widget
= mParentWidget
->GetNativeData(NS_NATIVE_WIDGET
);
1933 rv
= rootView
->CreateWidget(kWidgetCID
, nsnull
,
1934 widget
, PR_TRUE
, PR_TRUE
,
1935 eContentTypeContent
);
1936 NS_ENSURE_SUCCESS(rv
, rv
);
1937 aPO
->mWindow
= rootView
->GetWidget();
1938 aPO
->mPresContext
->SetPaginatedScrolling(canCreateScrollbars
);
1941 // Setup hierarchical relationship in view manager
1942 aPO
->mViewManager
->SetRootView(rootView
);
1944 // This docshell stuff is weird; will go away when we stop having multiple
1945 // presentations per document
1946 nsCOMPtr
<nsISupports
> supps(do_QueryInterface(aPO
->mDocShell
));
1947 aPO
->mPresContext
->SetContainer(supps
);
1949 aPO
->mPresShell
->BeginObservingDocument();
1951 aPO
->mPresContext
->SetPageSize(adjSize
);
1952 aPO
->mPresContext
->SetIsRootPaginatedDocument(documentIsTopLevel
);
1953 aPO
->mPresContext
->SetPageScale(aPO
->mZoomRatio
);
1954 // Calculate scale factor from printer to screen
1955 float printDPI
= float(mPrt
->mPrintDC
->AppUnitsPerInch()) /
1956 float(mPrt
->mPrintDC
->AppUnitsPerDevPixel());
1957 float screenDPI
= float(mDeviceContext
->AppUnitsPerInch()) /
1958 float(mDeviceContext
->AppUnitsPerDevPixel());
1959 aPO
->mPresContext
->SetPrintPreviewScale(screenDPI
/ printDPI
);
1961 rv
= aPO
->mPresShell
->InitialReflow(adjSize
.width
, adjSize
.height
);
1963 NS_ENSURE_SUCCESS(rv
, rv
);
1964 NS_ASSERTION(aPO
->mPresShell
, "Presshell should still be here");
1966 // Process the reflow event InitialReflow posted
1967 aPO
->mPresShell
->FlushPendingNotifications(Flush_Layout
);
1969 nsCOMPtr
<nsIPresShell
> displayShell
;
1970 aPO
->mDocShell
->GetPresShell(getter_AddRefs(displayShell
));
1971 // Transfer Selection Ranges to the new Print PresShell
1972 nsCOMPtr
<nsISelection
> selection
, selectionPS
;
1973 // It's okay if there is no display shell, just skip copying the selection
1975 selection
= displayShell
->GetCurrentSelection(nsISelectionController::SELECTION_NORMAL
);
1977 selectionPS
= aPO
->mPresShell
->GetCurrentSelection(nsISelectionController::SELECTION_NORMAL
);
1978 if (selection
&& selectionPS
) {
1980 selection
->GetRangeCount(&cnt
);
1982 for (inx
=0;inx
<cnt
;inx
++) {
1983 nsCOMPtr
<nsIDOMRange
> range
;
1984 if (NS_SUCCEEDED(selection
->GetRangeAt(inx
, getter_AddRefs(range
))))
1985 selectionPS
->AddRange(range
);
1989 // If we are trying to shrink the contents to fit on the page
1990 // we must first locate the "pageContent" frame
1991 // Then we walk the frame tree and look for the "xmost" frame
1992 // this is the frame where the right-hand side of the frame extends
1994 if (mPrt
->mShrinkToFit
&& documentIsTopLevel
) {
1995 nsIPageSequenceFrame
* pageSequence
;
1996 aPO
->mPresShell
->GetPageSequenceFrame(&pageSequence
);
1997 pageSequence
->GetSTFPercent(aPO
->mShrinkRatio
);
2000 #ifdef EXTENDED_DEBUG_PRINTING
2001 if (kPrintingLogMod
&& kPrintingLogMod
->level
== DUMP_LAYOUT_LEVEL
) {
2004 GetDocTitleAndURL(aPO
, docStr
, urlStr
);
2006 sprintf(filename
, "print_dump_%d.txt", gDumpFileNameCnt
++);
2007 // Dump all the frames and view to a a file
2008 FILE * fd
= fopen(filename
, "w");
2010 nsIFrame
*theRootFrame
=
2011 aPO
->mPresShell
->FrameManager()->GetRootFrame();
2012 fprintf(fd
, "Title: %s\n", docStr
?docStr
:"");
2013 fprintf(fd
, "URL: %s\n", urlStr
?urlStr
:"");
2014 fprintf(fd
, "--------------- Frames ----------------\n");
2015 nsCOMPtr
<nsIRenderingContext
> renderingContext
;
2016 mPrt
->mPrintDocDC
->CreateRenderingContext(*getter_AddRefs(renderingContext
));
2017 RootFrameList(aPO
->mPresContext
, fd
, 0);
2018 //DumpFrames(fd, aPO->mPresContext, renderingContext, theRootFrame, 0);
2019 fprintf(fd
, "---------------------------------------\n\n");
2020 fprintf(fd
, "--------------- Views From Root Frame----------------\n");
2021 nsIView
* v
= theRootFrame
->GetView();
2025 printf("View is null!\n");
2028 fprintf(fd
, "--------------- All Views ----------------\n");
2029 DumpViews(docShell
, fd
);
2030 fprintf(fd
, "---------------------------------------\n\n");
2034 if (docStr
) nsMemory::Free(docStr
);
2035 if (urlStr
) nsMemory::Free(urlStr
);
2042 //-------------------------------------------------------
2043 // Figure out how many documents and how many total pages we are printing
2045 nsPrintEngine::CalcNumPrintablePages(PRInt32
& aNumPages
)
2048 // Count the number of printable documents
2049 // and printable pages
2051 for (i
=0; i
<mPrt
->mPrintDocList
->Count(); i
++) {
2052 nsPrintObject
* po
= (nsPrintObject
*)mPrt
->mPrintDocList
->ElementAt(i
);
2053 NS_ASSERTION(po
, "nsPrintObject can't be null!");
2054 if (po
->mPresContext
&& po
->mPresContext
->IsRootPaginatedDocument()) {
2055 nsIPageSequenceFrame
* pageSequence
;
2056 po
->mPresShell
->GetPageSequenceFrame(&pageSequence
);
2057 nsIFrame
* seqFrame
;
2058 if (NS_SUCCEEDED(CallQueryInterface(pageSequence
, &seqFrame
))) {
2059 nsIFrame
* frame
= seqFrame
->GetFirstChild(nsnull
);
2062 frame
= frame
->GetNextSibling();
2068 //-----------------------------------------------------------------
2069 //-- Done: Reflow Methods
2070 //-----------------------------------------------------------------
2072 //-----------------------------------------------------------------
2073 //-- Section: Printing Methods
2074 //-----------------------------------------------------------------
2076 //-------------------------------------------------------
2077 // Called for each DocShell that needs to be printed
2079 nsPrintEngine::PrintDocContent(nsPrintObject
* aPO
, nsresult
& aStatus
)
2081 NS_ASSERTION(aPO
, "Pointer is null!");
2084 if (!aPO
->mHasBeenPrinted
&& aPO
->IsPrintable()) {
2085 aStatus
= DoPrint(aPO
);
2089 // If |aPO->mPrintAsIs| and |aPO->mHasBeenPrinted| are true,
2090 // the kids frames are already processed in |PrintPage|.
2091 if (!aPO
->mInvisible
&& !(aPO
->mPrintAsIs
&& aPO
->mHasBeenPrinted
)) {
2092 for (PRInt32 i
=0;i
<aPO
->mKids
.Count();i
++) {
2093 nsPrintObject
* po
= (nsPrintObject
*)aPO
->mKids
[i
];
2094 PRBool printed
= PrintDocContent(po
, aStatus
);
2095 if (printed
|| NS_FAILED(aStatus
)) {
2103 //-------------------------------------------------------
2105 nsPrintEngine::DoPrint(nsPrintObject
* aPO
)
2108 PR_PL(("**************************** %s ****************************\n", gFrameTypesStr
[aPO
->mFrameType
]));
2109 PR_PL(("****** In DV::DoPrint PO: %p \n", aPO
));
2111 nsIPresShell
* poPresShell
= aPO
->mPresShell
;
2112 nsPresContext
* poPresContext
= aPO
->mPresContext
;
2114 NS_ASSERTION(poPresContext
, "PrintObject has not been reflowed");
2115 NS_ASSERTION(poPresContext
->Type() != nsPresContext::eContext_PrintPreview
,
2116 "How did this context end up here?");
2118 if (mPrt
->mPrintProgressParams
) {
2119 SetDocAndURLIntoProgress(aPO
, mPrt
->mPrintProgressParams
);
2123 PRInt16 printRangeType
= nsIPrintSettings::kRangeAllPages
;
2125 if (mPrt
->mPrintSettings
!= nsnull
) {
2126 mPrt
->mPrintSettings
->GetPrintRange(&printRangeType
);
2129 // Ask the page sequence frame to print all the pages
2130 nsIPageSequenceFrame
* pageSequence
;
2131 poPresShell
->GetPageSequenceFrame(&pageSequence
);
2132 NS_ASSERTION(nsnull
!= pageSequence
, "no page sequence frame");
2134 // We are done preparing for printing, so we can turn this off
2135 mPrt
->mPreparingForPrint
= PR_FALSE
;
2137 // mPrt->mDebugFilePtr this is onlu non-null when compiled for debugging
2138 if (nsnull
!= mPrt
->mDebugFilePtr
) {
2140 // output the regression test
2141 nsIFrameDebug
* fdbg
;
2142 nsIFrame
* root
= poPresShell
->FrameManager()->GetRootFrame();
2144 if (NS_SUCCEEDED(CallQueryInterface(root
, &fdbg
))) {
2145 fdbg
->DumpRegressionData(poPresContext
, mPrt
->mDebugFilePtr
, 0, PR_TRUE
);
2147 fclose(mPrt
->mDebugFilePtr
);
2148 SetIsPrinting(PR_FALSE
);
2151 #ifdef EXTENDED_DEBUG_PRINTING
2152 nsIFrame
* rootFrame
= poPresShell
->FrameManager()->GetRootFrame();
2153 if (aPO
->IsPrintable()) {
2156 GetDocTitleAndURL(aPO
, docStr
, urlStr
);
2157 DumpLayoutData(docStr
, urlStr
, poPresContext
, mPrt
->mPrintDocDC
, rootFrame
, docShell
, nsnull
);
2158 if (docStr
) nsMemory::Free(docStr
);
2159 if (urlStr
) nsMemory::Free(urlStr
);
2163 if (mPrt
->mPrintSettings
) {
2164 PRUnichar
* docTitleStr
= nsnull
;
2165 PRUnichar
* docURLStr
= nsnull
;
2167 GetDisplayTitleAndURL(aPO
, &docTitleStr
, &docURLStr
, eDocTitleDefBlank
);
2169 if (nsIPrintSettings::kRangeSelection
== printRangeType
) {
2170 poPresContext
->SetIsRenderingOnlySelection(PR_TRUE
);
2171 // temporarily creating rendering context
2172 // which is needed to dinf the selection frames
2173 nsCOMPtr
<nsIRenderingContext
> rc
;
2174 mPrt
->mPrintDC
->CreateRenderingContext(*getter_AddRefs(rc
));
2176 // find the starting and ending page numbers
2177 // via the selection
2178 nsIFrame
* startFrame
;
2180 PRInt32 startPageNum
;
2185 nsCOMPtr
<nsISelection
> selectionPS
;
2186 selectionPS
= poPresShell
->GetCurrentSelection(nsISelectionController::SELECTION_NORMAL
);
2188 rv
= GetPageRangeForSelection(poPresShell
, poPresContext
, *rc
, selectionPS
, pageSequence
,
2189 &startFrame
, startPageNum
, startRect
,
2190 &endFrame
, endPageNum
, endRect
);
2191 if (NS_SUCCEEDED(rv
)) {
2192 mPrt
->mPrintSettings
->SetStartPageRange(startPageNum
);
2193 mPrt
->mPrintSettings
->SetEndPageRange(endPageNum
);
2194 nsMargin
marginTwips(0,0,0,0);
2195 nsMargin
unwrtMarginTwips(0,0,0,0);
2196 mPrt
->mPrintSettings
->GetMarginInTwips(marginTwips
);
2197 mPrt
->mPrintSettings
->GetUnwriteableMarginInTwips(unwrtMarginTwips
);
2198 nsMargin totalMargin
= poPresContext
->TwipsToAppUnits(marginTwips
+
2200 if (startPageNum
== endPageNum
) {
2202 startRect
.y
-= totalMargin
.top
;
2203 endRect
.y
-= totalMargin
.top
;
2205 // Clip out selection regions above the top of the first page
2206 if (startRect
.y
< 0) {
2207 // Reduce height to be the height of the positive-territory
2208 // region of original rect
2209 startRect
.height
= PR_MAX(0, startRect
.YMost());
2212 if (endRect
.y
< 0) {
2213 // Reduce height to be the height of the positive-territory
2214 // region of original rect
2215 endRect
.height
= PR_MAX(0, endRect
.YMost());
2218 NS_ASSERTION(endRect
.y
>= startRect
.y
,
2219 "Selection end point should be after start point");
2220 NS_ASSERTION(startRect
.height
>= 0,
2221 "rect should have non-negative height.");
2222 NS_ASSERTION(endRect
.height
>= 0,
2223 "rect should have non-negative height.");
2225 nscoord selectionHgt
= endRect
.y
+ endRect
.height
- startRect
.y
;
2226 // XXX This is temporary fix for printing more than one page of a selection
2227 pageSequence
->SetSelectionHeight(startRect
.y
* aPO
->mZoomRatio
,
2228 selectionHgt
* aPO
->mZoomRatio
);
2230 // calc total pages by getting calculating the selection's height
2231 // and then dividing it by how page content frames will fit.
2232 nscoord pageWidth
, pageHeight
;
2233 mPrt
->mPrintDC
->GetDeviceSurfaceDimensions(pageWidth
, pageHeight
);
2234 pageHeight
-= totalMargin
.top
+ totalMargin
.bottom
;
2235 PRInt32 totalPages
= NSToIntCeil(float(selectionHgt
) * aPO
->mZoomRatio
/ float(pageHeight
));
2236 pageSequence
->SetTotalNumPages(totalPages
);
2242 nsIFrame
* seqFrame
;
2243 if (NS_FAILED(CallQueryInterface(pageSequence
, &seqFrame
))) {
2244 SetIsPrinting(PR_FALSE
);
2245 return NS_ERROR_FAILURE
;
2248 mPageSeqFrame
= pageSequence
;
2249 mPageSeqFrame
->StartPrint(poPresContext
, mPrt
->mPrintSettings
, docTitleStr
, docURLStr
);
2251 // Schedule Page to Print
2252 PR_PL(("Scheduling Print of PO: %p (%s) \n", aPO
, gFrameTypesStr
[aPO
->mFrameType
]));
2253 StartPagePrintTimer(aPO
);
2255 // not sure what to do here!
2256 SetIsPrinting(PR_FALSE
);
2257 return NS_ERROR_FAILURE
;
2265 //---------------------------------------------------------------------
2267 nsPrintEngine::SetDocAndURLIntoProgress(nsPrintObject
* aPO
,
2268 nsIPrintProgressParams
* aParams
)
2270 NS_ASSERTION(aPO
, "Must have vaild nsPrintObject");
2271 NS_ASSERTION(aParams
, "Must have vaild nsIPrintProgressParams");
2273 if (!aPO
|| !aPO
->mDocShell
|| !aParams
) {
2276 const PRUint32 kTitleLength
= 64;
2278 PRUnichar
* docTitleStr
;
2279 PRUnichar
* docURLStr
;
2280 GetDisplayTitleAndURL(aPO
, &docTitleStr
, &docURLStr
, eDocTitleDefURLDoc
);
2282 // Make sure the Titles & URLS don't get too long for the progress dialog
2283 ElipseLongString(docTitleStr
, kTitleLength
, PR_FALSE
);
2284 ElipseLongString(docURLStr
, kTitleLength
, PR_TRUE
);
2286 aParams
->SetDocTitle(docTitleStr
);
2287 aParams
->SetDocURL(docURLStr
);
2289 if (docTitleStr
!= nsnull
) nsMemory::Free(docTitleStr
);
2290 if (docURLStr
!= nsnull
) nsMemory::Free(docURLStr
);
2293 //---------------------------------------------------------------------
2295 nsPrintEngine::ElipseLongString(PRUnichar
*& aStr
, const PRUint32 aLen
, PRBool aDoFront
)
2297 // Make sure the URLS don't get too long for the progress dialog
2298 if (aStr
&& nsCRT::strlen(aStr
) > aLen
) {
2300 PRUnichar
* ptr
= &aStr
[nsCRT::strlen(aStr
)-aLen
+3];
2301 nsAutoString newStr
;
2302 newStr
.AppendLiteral("...");
2304 nsMemory::Free(aStr
);
2305 aStr
= ToNewUnicode(newStr
);
2307 nsAutoString
newStr(aStr
);
2308 newStr
.SetLength(aLen
-3);
2309 newStr
.AppendLiteral("...");
2310 nsMemory::Free(aStr
);
2311 aStr
= ToNewUnicode(newStr
);
2316 //-------------------------------------------------------
2318 nsPrintEngine::PrintPage(nsPrintObject
* aPO
,
2321 NS_ASSERTION(aPO
, "aPO is null!");
2322 NS_ASSERTION(mPageSeqFrame
, "mPageSeqFrame is null!");
2323 NS_ASSERTION(mPrt
, "mPrt is null!");
2325 // Although these should NEVER be NULL
2326 // This is added insurance, to make sure we don't crash in optimized builds
2327 if (!mPrt
|| !aPO
|| !mPageSeqFrame
) {
2328 ShowPrintErrorDialog(NS_ERROR_FAILURE
);
2329 return PR_TRUE
; // means we are done printing
2332 PR_PL(("-----------------------------------\n"));
2333 PR_PL(("------ In DV::PrintPage PO: %p (%s)\n", aPO
, gFrameTypesStr
[aPO
->mFrameType
]));
2335 // Check setting to see if someone request it be cancelled
2336 PRBool isCancelled
= PR_FALSE
;
2337 mPrt
->mPrintSettings
->GetIsCancelled(&isCancelled
);
2341 PRInt32 pageNum
, numPages
, endPage
;
2342 mPageSeqFrame
->GetCurrentPageNum(&pageNum
);
2343 mPageSeqFrame
->GetNumPages(&numPages
);
2345 PRBool donePrinting
;
2346 PRBool isDoingPrintRange
;
2347 mPageSeqFrame
->IsDoingPrintRange(&isDoingPrintRange
);
2348 if (isDoingPrintRange
) {
2351 mPageSeqFrame
->GetPrintRange(&fromPage
, &toPage
);
2353 if (fromPage
> numPages
) {
2356 if (toPage
> numPages
) {
2360 PR_PL(("****** Printing Page %d printing from %d to page %d\n", pageNum
, fromPage
, toPage
));
2362 donePrinting
= pageNum
>= toPage
;
2363 aInRange
= pageNum
>= fromPage
&& pageNum
<= toPage
;
2364 endPage
= (toPage
- fromPage
)+1;
2366 PR_PL(("****** Printing Page %d of %d page(s)\n", pageNum
, numPages
));
2368 donePrinting
= pageNum
>= numPages
;
2373 // XXX This is wrong, but the actual behavior in the presence of a print
2375 if (mPrt
->mPrintFrameType
== nsIPrintSettings::kEachFrameSep
)
2376 endPage
= mPrt
->mNumPrintablePages
;
2378 mPrt
->DoOnProgressChange(++mPrt
->mNumPagesPrinted
, endPage
, PR_FALSE
, 0);
2381 // if a print job was cancelled externally, an EndPage or BeginPage may
2382 // fail and the failure is passed back here.
2383 // Returning PR_TRUE means we are done printing.
2385 // When rv == NS_ERROR_ABORT, it means we want out of the
2386 // print job without displaying any error messages
2387 nsresult rv
= mPageSeqFrame
->PrintNextPage();
2388 if (NS_FAILED(rv
)) {
2389 if (rv
!= NS_ERROR_ABORT
) {
2390 ShowPrintErrorDialog(rv
);
2391 mPrt
->mIsAborted
= PR_TRUE
;
2396 mPageSeqFrame
->DoPageEnd();
2398 return donePrinting
;
2401 /** ---------------------------------------------------
2402 * Find by checking frames type
2405 nsPrintEngine::FindSelectionBoundsWithList(nsPresContext
* aPresContext
,
2406 nsIRenderingContext
& aRC
,
2408 nsIFrame
* aParentFrame
,
2410 nsIFrame
*& aStartFrame
,
2412 nsIFrame
*& aEndFrame
,
2415 NS_ASSERTION(aPresContext
, "Pointer is null!");
2416 NS_ASSERTION(aParentFrame
, "Pointer is null!");
2418 nsIFrame
* child
= aParentFrame
->GetFirstChild(aList
);
2419 aRect
+= aParentFrame
->GetPosition();
2421 // only leaf frames have this bit flipped
2422 // then check the hard way
2423 PRBool isSelected
= (child
->GetStateBits() & NS_FRAME_SELECTED_CONTENT
)
2424 == NS_FRAME_SELECTED_CONTENT
;
2426 isSelected
= child
->IsVisibleForPainting();
2430 nsRect r
= child
->GetRect();
2431 if (aStartFrame
== nsnull
) {
2432 aStartFrame
= child
;
2433 aStartRect
.SetRect(aRect
.x
+ r
.x
, aRect
.y
+ r
.y
, r
.width
, r
.height
);
2436 aEndRect
.SetRect(aRect
.x
+ r
.x
, aRect
.y
+ r
.y
, r
.width
, r
.height
);
2439 FindSelectionBounds(aPresContext
, aRC
, child
, aRect
, aStartFrame
, aStartRect
, aEndFrame
, aEndRect
);
2440 child
= child
->GetNextSibling();
2442 aRect
-= aParentFrame
->GetPosition();
2446 //-------------------------------------------------------
2447 // Find the Frame that is XMost
2449 nsPrintEngine::FindSelectionBounds(nsPresContext
* aPresContext
,
2450 nsIRenderingContext
& aRC
,
2451 nsIFrame
* aParentFrame
,
2453 nsIFrame
*& aStartFrame
,
2455 nsIFrame
*& aEndFrame
,
2458 NS_ASSERTION(aPresContext
, "Pointer is null!");
2459 NS_ASSERTION(aParentFrame
, "Pointer is null!");
2461 // loop through named child lists
2462 nsIAtom
* childListName
= nsnull
;
2463 PRInt32 childListIndex
= 0;
2465 nsresult rv
= FindSelectionBoundsWithList(aPresContext
, aRC
, childListName
, aParentFrame
, aRect
, aStartFrame
, aStartRect
, aEndFrame
, aEndRect
);
2466 NS_ENSURE_SUCCESS(rv
, rv
);
2467 childListName
= aParentFrame
->GetAdditionalChildListName(childListIndex
++);
2468 } while (childListName
);
2472 /** ---------------------------------------------------
2473 * This method finds the starting and ending page numbers
2474 * of the selection and also returns rect for each where
2475 * the x,y of the rect is relative to the very top of the
2476 * frame tree (absolutely positioned)
2479 nsPrintEngine::GetPageRangeForSelection(nsIPresShell
* aPresShell
,
2480 nsPresContext
* aPresContext
,
2481 nsIRenderingContext
& aRC
,
2482 nsISelection
* aSelection
,
2483 nsIPageSequenceFrame
* aPageSeqFrame
,
2484 nsIFrame
** aStartFrame
,
2485 PRInt32
& aStartPageNum
,
2487 nsIFrame
** aEndFrame
,
2488 PRInt32
& aEndPageNum
,
2491 NS_ASSERTION(aPresShell
, "Pointer is null!");
2492 NS_ASSERTION(aPresContext
, "Pointer is null!");
2493 NS_ASSERTION(aSelection
, "Pointer is null!");
2494 NS_ASSERTION(aPageSeqFrame
, "Pointer is null!");
2495 NS_ASSERTION(aStartFrame
, "Pointer is null!");
2496 NS_ASSERTION(aEndFrame
, "Pointer is null!");
2498 nsIFrame
* seqFrame
;
2499 if (NS_FAILED(CallQueryInterface(aPageSeqFrame
, &seqFrame
))) {
2500 return NS_ERROR_FAILURE
;
2503 nsIFrame
* startFrame
= nsnull
;
2504 nsIFrame
* endFrame
= nsnull
;
2506 // start out with the sequence frame and search the entire frame tree
2507 // capturing the starting and ending child frames of the selection
2509 nsRect r
= seqFrame
->GetRect();
2510 FindSelectionBounds(aPresContext
, aRC
, seqFrame
, r
,
2511 startFrame
, aStartRect
, endFrame
, aEndRect
);
2514 printf("Start Frame: %p\n", startFrame
);
2515 printf("End Frame: %p\n", endFrame
);
2518 // initial the page numbers here
2519 // in case we don't find and frames
2523 nsIFrame
* startPageFrame
;
2524 nsIFrame
* endPageFrame
;
2526 // check to make sure we found a starting frame
2527 if (startFrame
!= nsnull
) {
2528 // Now search up the tree to find what page the
2529 // start/ending selections frames are on
2531 // Check to see if start should be same as end if
2532 // the end frame comes back null
2533 if (endFrame
== nsnull
) {
2534 // XXX the "GetPageFrame" step could be integrated into
2535 // the FindSelectionBounds step, but walking up to find
2536 // the parent of a child frame isn't expensive and it makes
2537 // FindSelectionBounds a little easier to understand
2538 startPageFrame
= nsLayoutUtils::GetPageFrame(startFrame
);
2539 endPageFrame
= startPageFrame
;
2540 aEndRect
= aStartRect
;
2542 startPageFrame
= nsLayoutUtils::GetPageFrame(startFrame
);
2543 endPageFrame
= nsLayoutUtils::GetPageFrame(endFrame
);
2546 return NS_ERROR_FAILURE
;
2550 printf("Start Page: %p\n", startPageFrame
);
2551 printf("End Page: %p\n", endPageFrame
);
2553 // dump all the pages and their pointers
2555 PRInt32 pageNum
= 1;
2556 nsIFrame
* child
= seqFrame
->GetFirstChild(nsnull
);
2557 while (child
!= nsnull
) {
2558 printf("Page: %d - %p\n", pageNum
, child
);
2560 child
= child
->GetNextSibling();
2565 // Now that we have the page frames
2566 // find out what the page numbers are for each frame
2567 PRInt32 pageNum
= 1;
2568 nsIFrame
* page
= seqFrame
->GetFirstChild(nsnull
);
2569 while (page
!= nsnull
) {
2570 if (page
== startPageFrame
) {
2571 aStartPageNum
= pageNum
;
2573 if (page
== endPageFrame
) {
2574 aEndPageNum
= pageNum
;
2577 page
= page
->GetNextSibling();
2581 printf("Start Page No: %d\n", aStartPageNum
);
2582 printf("End Page No: %d\n", aEndPageNum
);
2585 *aStartFrame
= startPageFrame
;
2586 *aEndFrame
= endPageFrame
;
2591 //-----------------------------------------------------------------
2592 //-- Done: Printing Methods
2593 //-----------------------------------------------------------------
2596 //-----------------------------------------------------------------
2597 //-- Section: Misc Support Methods
2598 //-----------------------------------------------------------------
2600 //---------------------------------------------------------------------
2601 void nsPrintEngine::SetIsPrinting(PRBool aIsPrinting
)
2603 mIsDoingPrinting
= aIsPrinting
;
2604 if (mDocViewerPrint
) {
2605 mDocViewerPrint
->SetIsPrinting(aIsPrinting
);
2607 if (mPrt
&& aIsPrinting
) {
2608 mPrt
->mPreparingForPrint
= PR_TRUE
;
2612 //---------------------------------------------------------------------
2613 void nsPrintEngine::SetIsPrintPreview(PRBool aIsPrintPreview
)
2615 mIsDoingPrintPreview
= aIsPrintPreview
;
2617 if (mDocViewerPrint
) {
2618 mDocViewerPrint
->SetIsPrintPreview(aIsPrintPreview
);
2622 //---------------------------------------------------------------------
2624 nsPrintEngine::CleanupDocTitleArray(PRUnichar
**& aArray
, PRInt32
& aCount
)
2626 for (PRInt32 i
= aCount
- 1; i
>= 0; i
--) {
2627 nsMemory::Free(aArray
[i
]);
2629 nsMemory::Free(aArray
);
2634 //---------------------------------------------------------------------
2636 PRBool
nsPrintEngine::HasFramesetChild(nsIContent
* aContent
)
2642 PRUint32 numChildren
= aContent
->GetChildCount();
2644 // do a breadth search across all siblings
2645 for (PRUint32 i
= 0; i
< numChildren
; ++i
) {
2646 nsIContent
*child
= aContent
->GetChildAt(i
);
2647 if (child
->Tag() == nsGkAtoms::frameset
&&
2648 child
->IsNodeOfType(nsINode::eHTML
)) {
2658 /** ---------------------------------------------------
2659 * Get the Focused Frame for a documentviewer
2661 already_AddRefed
<nsIDOMWindow
>
2662 nsPrintEngine::FindFocusedDOMWindow()
2664 nsIDOMWindow
* domWin
= nsnull
;
2666 nsPIDOMWindow
*theDOMWindow
= mDocument
->GetWindow();
2668 nsIFocusController
*focusController
=
2669 theDOMWindow
->GetRootFocusController();
2670 if (focusController
) {
2671 nsCOMPtr
<nsIDOMWindowInternal
> theDOMWin
;
2672 focusController
->GetFocusedWindow(getter_AddRefs(theDOMWin
));
2673 if(theDOMWin
&& IsWindowsInOurSubTree(theDOMWin
)){
2674 NS_ADDREF(domWin
= theDOMWin
);
2682 //---------------------------------------------------------------------
2684 nsPrintEngine::IsWindowsInOurSubTree(nsIDOMWindow
* aDOMWindow
)
2686 PRBool found
= PR_FALSE
;
2688 // now check to make sure it is in "our" tree of docshells
2689 nsCOMPtr
<nsPIDOMWindow
> window(do_QueryInterface(aDOMWindow
));
2691 nsCOMPtr
<nsIDocShellTreeItem
> docShellAsItem
=
2692 do_QueryInterface(window
->GetDocShell());
2694 if (docShellAsItem
) {
2695 // get this DocViewer docshell
2696 nsCOMPtr
<nsIDocShell
> thisDVDocShell(do_QueryInterface(mContainer
));
2698 nsCOMPtr
<nsIDocShell
> parentDocshell(do_QueryInterface(docShellAsItem
));
2699 if (parentDocshell
) {
2700 if (parentDocshell
== thisDVDocShell
) {
2705 break; // at top of tree
2707 nsCOMPtr
<nsIDocShellTreeItem
> docShellParent
;
2708 docShellAsItem
->GetSameTypeParent(getter_AddRefs(docShellParent
));
2709 docShellAsItem
= docShellParent
;
2717 //-------------------------------------------------------
2719 nsPrintEngine::DonePrintingPages(nsPrintObject
* aPO
, nsresult aResult
)
2721 //NS_ASSERTION(aPO, "Pointer is null!");
2722 PR_PL(("****** In DV::DonePrintingPages PO: %p (%s)\n", aPO
, aPO
?gFrameTypesStr
[aPO
->mFrameType
]:""));
2724 if (aPO
!= nsnull
) {
2725 aPO
->mHasBeenPrinted
= PR_TRUE
;
2727 PRBool didPrint
= PrintDocContent(mPrt
->mPrintObject
, rv
);
2728 if (NS_SUCCEEDED(rv
) && didPrint
) {
2729 PR_PL(("****** In DV::DonePrintingPages PO: %p (%s) didPrint:%s (Not Done Printing)\n", aPO
, gFrameTypesStr
[aPO
->mFrameType
], PRT_YESNO(didPrint
)));
2734 if (NS_SUCCEEDED(aResult
)) {
2735 FirePrintCompletionEvent();
2738 SetIsPrinting(PR_FALSE
);
2740 // Release reference to mPagePrintTimer; the timer object destroys itself
2741 // after this returns true
2742 NS_IF_RELEASE(mPagePrintTimer
);
2747 //-------------------------------------------------------
2748 // Recursively sets the PO items to be printed "As Is"
2749 // from the given item down into the tree
2751 nsPrintEngine::SetPrintAsIs(nsPrintObject
* aPO
, PRBool aAsIs
)
2753 NS_ASSERTION(aPO
, "Pointer is null!");
2755 aPO
->mPrintAsIs
= aAsIs
;
2756 for (PRInt32 i
=0;i
<aPO
->mKids
.Count();i
++) {
2757 SetPrintAsIs((nsPrintObject
*)aPO
->mKids
[i
], aAsIs
);
2761 //-------------------------------------------------------
2762 // Given a DOMWindow it recursively finds the PO object that matches
2764 nsPrintEngine::FindPrintObjectByDOMWin(nsPrintObject
* aPO
,
2765 nsIDOMWindow
* aDOMWin
)
2767 NS_ASSERTION(aPO
, "Pointer is null!");
2769 // Often the CurFocused DOMWindow is passed in
2770 // andit is valid for it to be null, so short circut
2775 nsCOMPtr
<nsIDOMWindow
> domWin(do_GetInterface(aPO
->mDocShell
));
2776 if (domWin
&& domWin
== aDOMWin
) {
2780 PRInt32 cnt
= aPO
->mKids
.Count();
2781 for (PRInt32 i
= 0; i
< cnt
; ++i
) {
2782 nsPrintObject
* po
= FindPrintObjectByDOMWin((nsPrintObject
*)aPO
->mKids
[i
],
2792 //-------------------------------------------------------
2794 nsPrintEngine::EnablePOsForPrinting()
2796 // NOTE: All POs have been "turned off" for printing
2797 // this is where we decided which POs get printed.
2798 mPrt
->mSelectedPO
= nsnull
;
2800 if (mPrt
->mPrintSettings
== nsnull
) {
2801 return NS_ERROR_FAILURE
;
2804 mPrt
->mPrintFrameType
= nsIPrintSettings::kNoFrames
;
2805 mPrt
->mPrintSettings
->GetPrintFrameType(&mPrt
->mPrintFrameType
);
2807 PRInt16 printHowEnable
= nsIPrintSettings::kFrameEnableNone
;
2808 mPrt
->mPrintSettings
->GetHowToEnableFrameUI(&printHowEnable
);
2810 PRInt16 printRangeType
= nsIPrintSettings::kRangeAllPages
;
2811 mPrt
->mPrintSettings
->GetPrintRange(&printRangeType
);
2814 PR_PL(("********* nsPrintEngine::EnablePOsForPrinting *********\n"));
2815 PR_PL(("PrintFrameType: %s \n", gPrintFrameTypeStr
[mPrt
->mPrintFrameType
]));
2816 PR_PL(("HowToEnableFrameUI: %s \n", gFrameHowToEnableStr
[printHowEnable
]));
2817 PR_PL(("PrintRange: %s \n", gPrintRangeStr
[printRangeType
]));
2820 // ***** This is the ultimate override *****
2821 // if we are printing the selection (either an IFrame or selection range)
2822 // then set the mPrintFrameType as if it were the selected frame
2823 if (printRangeType
== nsIPrintSettings::kRangeSelection
) {
2824 mPrt
->mPrintFrameType
= nsIPrintSettings::kSelectedFrame
;
2825 printHowEnable
= nsIPrintSettings::kFrameEnableNone
;
2828 // This tells us that the "Frame" UI has turned off,
2829 // so therefore there are no FrameSets/Frames/IFrames to be printed
2831 // This means there are not FrameSets,
2832 // but the document could contain an IFrame
2833 if (printHowEnable
== nsIPrintSettings::kFrameEnableNone
) {
2835 // Print all the pages or a sub range of pages
2836 if (printRangeType
== nsIPrintSettings::kRangeAllPages
||
2837 printRangeType
== nsIPrintSettings::kRangeSpecifiedPageRange
) {
2838 SetPrintPO(mPrt
->mPrintObject
, PR_TRUE
);
2840 // Set the children so they are PrinAsIs
2841 // In this case, the children are probably IFrames
2842 if (mPrt
->mPrintObject
->mKids
.Count() > 0) {
2843 for (PRInt32 i
=0;i
<mPrt
->mPrintObject
->mKids
.Count();i
++) {
2844 nsPrintObject
* po
= (nsPrintObject
*)mPrt
->mPrintObject
->mKids
[i
];
2845 NS_ASSERTION(po
, "nsPrintObject can't be null!");
2849 // ***** Another override *****
2850 mPrt
->mPrintFrameType
= nsIPrintSettings::kFramesAsIs
;
2852 PR_PL(("PrintFrameType: %s \n", gPrintFrameTypeStr
[mPrt
->mPrintFrameType
]));
2853 PR_PL(("HowToEnableFrameUI: %s \n", gFrameHowToEnableStr
[printHowEnable
]));
2854 PR_PL(("PrintRange: %s \n", gPrintRangeStr
[printRangeType
]));
2858 // This means we are either printed a selected IFrame or
2859 // we are printing the current selection
2860 if (printRangeType
== nsIPrintSettings::kRangeSelection
) {
2862 // If the currentFocusDOMWin can'r be null if something is selected
2863 if (mPrt
->mCurrentFocusWin
) {
2864 // Find the selected IFrame
2865 nsPrintObject
* po
= FindPrintObjectByDOMWin(mPrt
->mPrintObject
, mPrt
->mCurrentFocusWin
);
2867 mPrt
->mSelectedPO
= po
;
2868 // Makes sure all of its children are be printed "AsIs"
2871 // Now, only enable this POs (the selected PO) and all of its children
2872 SetPrintPO(po
, PR_TRUE
);
2874 // check to see if we have a range selection,
2875 // as oppose to a insert selection
2876 // this means if the user just clicked on the IFrame then
2877 // there will not be a selection so we want the entire page to print
2879 // XXX this is sort of a hack right here to make the page
2880 // not try to reposition itself when printing selection
2881 nsCOMPtr
<nsIDOMWindow
> domWin
= do_GetInterface(po
->mDocShell
);
2882 if (!IsThereARangeSelection(domWin
)) {
2883 printRangeType
= nsIPrintSettings::kRangeAllPages
;
2884 mPrt
->mPrintSettings
->SetPrintRange(printRangeType
);
2886 PR_PL(("PrintFrameType: %s \n", gPrintFrameTypeStr
[mPrt
->mPrintFrameType
]));
2887 PR_PL(("HowToEnableFrameUI: %s \n", gFrameHowToEnableStr
[printHowEnable
]));
2888 PR_PL(("PrintRange: %s \n", gPrintRangeStr
[printRangeType
]));
2892 for (PRInt32 i
=0;i
<mPrt
->mPrintDocList
->Count();i
++) {
2893 nsPrintObject
* po
= (nsPrintObject
*)mPrt
->mPrintDocList
->ElementAt(i
);
2894 NS_ASSERTION(po
, "nsPrintObject can't be null!");
2895 nsCOMPtr
<nsIDOMWindow
> domWin
= do_GetInterface(po
->mDocShell
);
2896 if (IsThereARangeSelection(domWin
)) {
2897 mPrt
->mCurrentFocusWin
= domWin
;
2898 SetPrintPO(po
, PR_TRUE
);
2907 // check to see if there is a selection when a FrameSet is present
2908 if (printRangeType
== nsIPrintSettings::kRangeSelection
) {
2909 // If the currentFocusDOMWin can'r be null if something is selected
2910 if (mPrt
->mCurrentFocusWin
) {
2911 // Find the selected IFrame
2912 nsPrintObject
* po
= FindPrintObjectByDOMWin(mPrt
->mPrintObject
, mPrt
->mCurrentFocusWin
);
2914 mPrt
->mSelectedPO
= po
;
2915 // Makes sure all of its children are be printed "AsIs"
2918 // Now, only enable this POs (the selected PO) and all of its children
2919 SetPrintPO(po
, PR_TRUE
);
2921 // check to see if we have a range selection,
2922 // as oppose to a insert selection
2923 // this means if the user just clicked on the IFrame then
2924 // there will not be a selection so we want the entire page to print
2926 // XXX this is sort of a hack right here to make the page
2927 // not try to reposition itself when printing selection
2928 nsCOMPtr
<nsIDOMWindow
> domWin
= do_GetInterface(po
->mDocShell
);
2929 if (!IsThereARangeSelection(domWin
)) {
2930 printRangeType
= nsIPrintSettings::kRangeAllPages
;
2931 mPrt
->mPrintSettings
->SetPrintRange(printRangeType
);
2933 PR_PL(("PrintFrameType: %s \n", gPrintFrameTypeStr
[mPrt
->mPrintFrameType
]));
2934 PR_PL(("HowToEnableFrameUI: %s \n", gFrameHowToEnableStr
[printHowEnable
]));
2935 PR_PL(("PrintRange: %s \n", gPrintRangeStr
[printRangeType
]));
2941 // If we are printing "AsIs" then sets all the POs to be printed as is
2942 if (mPrt
->mPrintFrameType
== nsIPrintSettings::kFramesAsIs
) {
2943 SetPrintAsIs(mPrt
->mPrintObject
);
2944 SetPrintPO(mPrt
->mPrintObject
, PR_TRUE
);
2948 // If we are printing the selected Frame then
2949 // find that PO for that selected DOMWin and set it all of its
2950 // children to be printed
2951 if (mPrt
->mPrintFrameType
== nsIPrintSettings::kSelectedFrame
) {
2953 if ((mPrt
->mIsParentAFrameSet
&& mPrt
->mCurrentFocusWin
) || mPrt
->mIsIFrameSelected
) {
2954 nsPrintObject
* po
= FindPrintObjectByDOMWin(mPrt
->mPrintObject
, mPrt
->mCurrentFocusWin
);
2956 mPrt
->mSelectedPO
= po
;
2957 // NOTE: Calling this sets the "po" and
2958 // we don't want to do this for documents that have no children,
2959 // because then the "DoEndPage" gets called and it shouldn't
2960 if (po
->mKids
.Count() > 0) {
2961 // Makes sure that itself, and all of its children are printed "AsIs"
2965 // Now, only enable this POs (the selected PO) and all of its children
2966 SetPrintPO(po
, PR_TRUE
);
2972 // If we are print each subdoc separately,
2973 // then don't print any of the FraneSet Docs
2974 if (mPrt
->mPrintFrameType
== nsIPrintSettings::kEachFrameSep
) {
2975 SetPrintPO(mPrt
->mPrintObject
, PR_TRUE
);
2976 PRInt32 cnt
= mPrt
->mPrintDocList
->Count();
2977 for (PRInt32 i
=0;i
<cnt
;i
++) {
2978 nsPrintObject
* po
= (nsPrintObject
*)mPrt
->mPrintDocList
->ElementAt(i
);
2979 NS_ASSERTION(po
, "nsPrintObject can't be null!");
2980 if (po
->mFrameType
== eFrameSet
) {
2981 po
->mDontPrint
= PR_TRUE
;
2989 //-------------------------------------------------------
2990 // Return the nsPrintObject with that is XMost (The widest frameset frame) AND
2991 // contains the XMost (widest) layout frame
2993 nsPrintEngine::FindSmallestSTF()
2995 float smallestRatio
= 1.0f
;
2996 nsPrintObject
* smallestPO
= nsnull
;
2998 for (PRInt32 i
=0;i
<mPrt
->mPrintDocList
->Count();i
++) {
2999 nsPrintObject
* po
= (nsPrintObject
*)mPrt
->mPrintDocList
->ElementAt(i
);
3000 NS_ASSERTION(po
, "nsPrintObject can't be null!");
3001 if (po
->mFrameType
!= eFrameSet
&& po
->mFrameType
!= eIFrame
) {
3002 if (po
->mShrinkRatio
< smallestRatio
) {
3003 smallestRatio
= po
->mShrinkRatio
;
3009 #ifdef EXTENDED_DEBUG_PRINTING
3010 if (smallestPO
) printf("*PO: %p Type: %d %10.3f\n", smallestPO
, smallestPO
->mFrameType
, smallestPO
->mShrinkRatio
);
3015 //-------------------------------------------------------
3017 nsPrintEngine::TurnScriptingOn(PRBool aDoTurnOn
)
3019 nsPrintData
* prt
= mPrt
;
3020 #ifdef NS_PRINT_PREVIEW
3029 NS_ASSERTION(mDocument
, "We MUST have a document.");
3030 // First, get the script global object from the document...
3032 for (PRInt32 i
=0;i
<prt
->mPrintDocList
->Count();i
++) {
3033 nsPrintObject
* po
= (nsPrintObject
*)prt
->mPrintDocList
->ElementAt(i
);
3034 NS_ASSERTION(po
, "nsPrintObject can't be null!");
3036 nsIDocument
* doc
= po
->mDocument
;
3038 // get the script global object
3039 nsIScriptGlobalObject
*scriptGlobalObj
= doc
->GetScriptGlobalObject();
3041 if (scriptGlobalObj
) {
3042 nsIScriptContext
*scx
= scriptGlobalObj
->GetContext();
3043 NS_ASSERTION(scx
, "Can't get nsIScriptContext");
3045 doc
->DeleteProperty(nsGkAtoms::scriptEnabledBeforePrintPreview
);
3047 // Have to be careful, because people call us over and over again with
3048 // aDoTurnOn == PR_FALSE. So don't set the property if it's already
3049 // set, since in that case we'd set it to the wrong value.
3051 doc
->GetProperty(nsGkAtoms::scriptEnabledBeforePrintPreview
,
3053 if (propThere
== NS_PROPTABLE_PROP_NOT_THERE
) {
3054 // Stash the current value of IsScriptEnabled on the document, so
3055 // that layout code running in print preview doesn't get confused.
3056 doc
->SetProperty(nsGkAtoms::scriptEnabledBeforePrintPreview
,
3057 NS_INT32_TO_PTR(doc
->IsScriptEnabled()));
3060 scx
->SetScriptsEnabled(aDoTurnOn
, PR_TRUE
);
3065 //-----------------------------------------------------------------
3066 //-- Done: Misc Support Methods
3067 //-----------------------------------------------------------------
3070 //-----------------------------------------------------------------
3071 //-- Section: Finishing up or Cleaning up
3072 //-----------------------------------------------------------------
3074 //-----------------------------------------------------------------
3076 nsPrintEngine::CloseProgressDialog(nsIWebProgressListener
* aWebProgressListener
)
3078 if (aWebProgressListener
) {
3079 aWebProgressListener
->OnStateChange(nsnull
, nsnull
, nsIWebProgressListener::STATE_STOP
|nsIWebProgressListener::STATE_IS_DOCUMENT
, nsnull
);
3083 //-----------------------------------------------------------------
3085 nsPrintEngine::FinishPrintPreview()
3087 nsresult rv
= NS_OK
;
3089 #ifdef NS_PRINT_PREVIEW
3092 /* we're already finished with print preview */
3096 rv
= DocumentReadyForPrinting();
3098 SetIsCreatingPrintPreview(PR_FALSE
);
3100 /* cleaup on failure + notify user */
3101 if (NS_FAILED(rv
)) {
3102 /* cleanup done, let's fire-up an error dialog to notify the user
3103 * what went wrong...
3105 mPrt
->OnEndPrinting();
3106 TurnScriptingOn(PR_TRUE
);
3111 // At this point we are done preparing everything
3112 // before it is to be created
3115 if (mIsDoingPrintPreview
&& mOldPrtPreview
) {
3116 delete mOldPrtPreview
;
3117 mOldPrtPreview
= nsnull
;
3120 InstallPrintPreviewListener();
3122 mPrt
->OnEndPrinting();
3124 // PrintPreview was built using the mPrt (code reuse)
3125 // then we assign it over
3129 #endif // NS_PRINT_PREVIEW
3134 //-----------------------------------------------------------------
3135 //-- Done: Finishing up or Cleaning up
3136 //-----------------------------------------------------------------
3139 /*=============== Timer Related Code ======================*/
3141 nsPrintEngine::StartPagePrintTimer(nsPrintObject
* aPO
)
3143 if (!mPagePrintTimer
) {
3144 nsresult rv
= NS_NewPagePrintTimer(&mPagePrintTimer
);
3145 NS_ENSURE_SUCCESS(rv
, rv
);
3147 // Get the delay time in between the printing of each page
3148 // this gives the user more time to press cancel
3149 PRInt32 printPageDelay
= 500;
3150 mPrt
->mPrintSettings
->GetPrintPageDelay(&printPageDelay
);
3152 mPagePrintTimer
->Init(this, mDocViewerPrint
, printPageDelay
);
3155 return mPagePrintTimer
->Start(aPO
);
3158 /*=============== nsIObserver Interface ======================*/
3160 nsPrintEngine::Observe(nsISupports
*aSubject
, const char *aTopic
, const PRUnichar
*aData
)
3162 nsresult rv
= NS_ERROR_FAILURE
;
3164 if (mIsDoingPrinting
) {
3165 rv
= DocumentReadyForPrinting();
3167 /* cleaup on failure + notify user */
3168 if (NS_FAILED(rv
)) {
3169 CleanupOnFailure(rv
, PR_TRUE
);
3172 rv
= FinishPrintPreview();
3173 if (NS_FAILED(rv
)) {
3174 CleanupOnFailure(rv
, PR_FALSE
);
3177 mPrtPreview
->OnEndPrinting();
3186 //---------------------------------------------------------------
3187 //-- PLEvent Notification
3188 //---------------------------------------------------------------
3189 class nsPrintCompletionEvent
: public nsRunnable
{
3191 nsPrintCompletionEvent(nsIDocumentViewerPrint
*docViewerPrint
)
3192 : mDocViewerPrint(docViewerPrint
) {
3193 NS_ASSERTION(mDocViewerPrint
, "mDocViewerPrint is null.");
3197 if (mDocViewerPrint
)
3198 mDocViewerPrint
->OnDonePrinting();
3203 nsCOMPtr
<nsIDocumentViewerPrint
> mDocViewerPrint
;
3206 //-----------------------------------------------------------
3208 nsPrintEngine::FirePrintCompletionEvent()
3210 nsCOMPtr
<nsIRunnable
> event
= new nsPrintCompletionEvent(mDocViewerPrint
);
3211 if (NS_FAILED(NS_DispatchToCurrentThread(event
)))
3212 NS_WARNING("failed to dispatch print completion event");
3215 //---------------------------------------------------------------
3216 //---------------------------------------------------------------
3217 //-- Debug helper routines
3218 //---------------------------------------------------------------
3219 //---------------------------------------------------------------
3220 #if (defined(XP_WIN) || defined(XP_OS2)) && defined(EXTENDED_DEBUG_PRINTING)
3221 #include "windows.h"
3222 #include "process.h"
3225 #define MY_FINDFIRST(a,b) FindFirstFile(a,b)
3226 #define MY_FINDNEXT(a,b) FindNextFile(a,b)
3227 #define ISDIR(a) (a.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
3228 #define MY_FINDCLOSE(a) FindClose(a)
3229 #define MY_FILENAME(a) a.cFileName
3230 #define MY_FILESIZE(a) (a.nFileSizeHigh * MAXDWORD) + a.nFileSizeLow
3232 int RemoveFilesInDir(const char * aDir
)
3234 WIN32_FIND_DATA data_ptr
;
3237 char path
[MAX_PATH
];
3241 // Append slash to the end of the directory names if not there
3242 if (path
[strlen(path
)-1] != '\\')
3245 char findPath
[MAX_PATH
];
3246 strcpy(findPath
, path
);
3247 strcat(findPath
, "*.*");
3249 find_handle
= MY_FINDFIRST(findPath
, &data_ptr
);
3251 if (find_handle
!= INVALID_HANDLE_VALUE
) {
3254 && (stricmp(MY_FILENAME(data_ptr
),"."))
3255 && (stricmp(MY_FILENAME(data_ptr
),".."))) {
3258 else if (!ISDIR(data_ptr
)) {
3259 if (!strncmp(MY_FILENAME(data_ptr
), "print_dump", 10)) {
3260 char fileName
[MAX_PATH
];
3261 strcpy(fileName
, aDir
);
3262 strcat(fileName
, "\\");
3263 strcat(fileName
, MY_FILENAME(data_ptr
));
3264 printf("Removing %s\n", fileName
);
3268 } while(MY_FINDNEXT(find_handle
,&data_ptr
));
3269 MY_FINDCLOSE(find_handle
);
3275 #ifdef EXTENDED_DEBUG_PRINTING
3277 /** ---------------------------------------------------
3278 * Dumps Frames for Printing
3280 static void RootFrameList(nsPresContext
* aPresContext
, FILE* out
, PRInt32 aIndent
)
3282 if (!aPresContext
|| !out
)
3285 nsIPresShell
*shell
= aPresContext
->GetPresShell();
3287 nsIFrame
* frame
= shell
->FrameManager()->GetRootFrame();
3289 nsIFrameDebug
* debugFrame
;
3290 nsresult rv
= CallQueryInterface(frame
, &debugFrame
);
3291 if (NS_SUCCEEDED(rv
))
3292 debugFrame
->List(aPresContext
, out
, aIndent
);
3297 /** ---------------------------------------------------
3298 * Dumps Frames for Printing
3300 static void DumpFrames(FILE* out
,
3301 nsPresContext
* aPresContext
,
3302 nsIRenderingContext
* aRendContext
,
3306 NS_ASSERTION(out
, "Pointer is null!");
3307 NS_ASSERTION(aPresContext
, "Pointer is null!");
3308 NS_ASSERTION(aRendContext
, "Pointer is null!");
3309 NS_ASSERTION(aFrame
, "Pointer is null!");
3311 nsIFrame
* child
= aFrame
->GetFirstChild(nsnull
);
3312 while (child
!= nsnull
) {
3313 for (PRInt32 i
=0;i
<aLevel
;i
++) {
3317 nsIFrameDebug
* frameDebug
;
3319 if (NS_SUCCEEDED(CallQueryInterface(child
, &frameDebug
))) {
3320 frameDebug
->GetFrameName(tmp
);
3322 fputs(NS_LossyConvertUTF16toASCII(tmp
).get(), out
);
3324 if (NS_SUCCEEDED(child
->IsVisibleForPainting(aPresContext
, *aRendContext
, PR_TRUE
, &isSelected
))) {
3325 fprintf(out
, " %p %s", child
, isSelected
?"VIS":"UVS");
3326 nsRect rect
= child
->GetRect();
3327 fprintf(out
, "[%d,%d,%d,%d] ", rect
.x
, rect
.y
, rect
.width
, rect
.height
);
3328 fprintf(out
, "v: %p ", (void*)child
->GetView());
3330 DumpFrames(out
, aPresContext
, aRendContext
, child
, aLevel
+1);
3331 child
= child
->GetNextSibling();
3337 /** ---------------------------------------------------
3338 * Dumps the Views from the DocShell
3341 DumpViews(nsIDocShell
* aDocShell
, FILE* out
)
3343 NS_ASSERTION(aDocShell
, "Pointer is null!");
3344 NS_ASSERTION(out
, "Pointer is null!");
3346 if (nsnull
!= aDocShell
) {
3347 fprintf(out
, "docshell=%p \n", aDocShell
);
3348 nsIPresShell
* shell
= nsPrintEngine::GetPresShellFor(aDocShell
);
3350 nsIViewManager
* vm
= shell
->GetViewManager();
3353 vm
->GetRootView(root
);
3354 if (nsnull
!= root
) {
3360 fputs("null pres shell\n", out
);
3363 // dump the views of the sub documents
3365 nsCOMPtr
<nsIDocShellTreeNode
> docShellAsNode(do_QueryInterface(aDocShell
));
3366 docShellAsNode
->GetChildCount(&n
);
3367 for (i
= 0; i
< n
; i
++) {
3368 nsCOMPtr
<nsIDocShellTreeItem
> child
;
3369 docShellAsNode
->GetChildAt(i
, getter_AddRefs(child
));
3370 nsCOMPtr
<nsIDocShell
> childAsShell(do_QueryInterface(child
));
3372 DumpViews(childAsShell
, out
);
3378 /** ---------------------------------------------------
3379 * Dumps the Views and Frames
3381 void DumpLayoutData(char* aTitleStr
,
3383 nsPresContext
* aPresContext
,
3384 nsIDeviceContext
* aDC
,
3385 nsIFrame
* aRootFrame
,
3386 nsIDocShekk
* aDocShell
,
3389 if (!kPrintingLogMod
|| kPrintingLogMod
->level
!= DUMP_LAYOUT_LEVEL
) return;
3391 if (aPresContext
== nsnull
|| aDC
== nsnull
) {
3395 #ifdef NS_PRINT_PREVIEW
3396 if (aPresContext
->Type() == nsPresContext::eContext_PrintPreview
) {
3401 NS_ASSERTION(aRootFrame
, "Pointer is null!");
3402 NS_ASSERTION(aDocShell
, "Pointer is null!");
3404 // Dump all the frames and view to a a file
3406 sprintf(filename
, "print_dump_layout_%d.txt", gDumpLOFileNameCnt
++);
3407 FILE * fd
= aFD
?aFD
:fopen(filename
, "w");
3409 fprintf(fd
, "Title: %s\n", aTitleStr
?aTitleStr
:"");
3410 fprintf(fd
, "URL: %s\n", aURLStr
?aURLStr
:"");
3411 fprintf(fd
, "--------------- Frames ----------------\n");
3412 fprintf(fd
, "--------------- Frames ----------------\n");
3413 nsCOMPtr
<nsIRenderingContext
> renderingContext
;
3414 aDC
->CreateRenderingContext(*getter_AddRefs(renderingContext
));
3415 RootFrameList(aPresContext
, fd
, 0);
3416 //DumpFrames(fd, aPresContext, renderingContext, aRootFrame, 0);
3417 fprintf(fd
, "---------------------------------------\n\n");
3418 fprintf(fd
, "--------------- Views From Root Frame----------------\n");
3419 nsIView
* v
= aRootFrame
->GetView();
3423 printf("View is null!\n");
3426 fprintf(fd
, "--------------- All Views ----------------\n");
3427 DumpViews(aDocShell
, fd
);
3428 fprintf(fd
, "---------------------------------------\n\n");
3430 if (aFD
== nsnull
) {
3436 //-------------------------------------------------------------
3437 static void DumpPrintObjectsList(nsVoidArray
* aDocList
)
3439 if (!kPrintingLogMod
|| kPrintingLogMod
->level
!= DUMP_LAYOUT_LEVEL
) return;
3441 NS_ASSERTION(aDocList
, "Pointer is null!");
3443 const char types
[][3] = {"DC", "FR", "IF", "FS"};
3444 PR_PL(("Doc List\n***************************************************\n"));
3445 PR_PL(("T P A H PO DocShell Seq Page Root Page# Rect\n"));
3446 PRInt32 cnt
= aDocList
->Count();
3447 for (PRInt32 i
=0;i
<cnt
;i
++) {
3448 nsPrintObject
* po
= (nsPrintObject
*)aDocList
->ElementAt(i
);
3449 NS_ASSERTION(po
, "nsPrintObject can't be null!");
3450 nsIFrame
* rootFrame
= nsnull
;
3451 if (po
->mPresShell
) {
3452 rootFrame
= po
->mPresShell
->FrameManager()->GetRootFrame();
3453 while (rootFrame
!= nsnull
) {
3454 nsIPageSequenceFrame
* sqf
= nsnull
;
3455 if (NS_SUCCEEDED(CallQueryInterface(rootFrame
, &sqf
))) {
3458 rootFrame
= rootFrame
->GetFirstChild(nsnull
);
3462 PR_PL(("%s %d %d %d %p %p %p %p %p %d %d,%d,%d,%d\n", types
[po
->mFrameType
],
3463 po
->IsPrintable(), po
->mPrintAsIs
, po
->mHasBeenPrinted
, po
, po
->mDocShell
.get(), po
->mSeqFrame
,
3464 po
->mPageFrame
, rootFrame
, po
->mPageNum
, po
->mRect
.x
, po
->mRect
.y
, po
->mRect
.width
, po
->mRect
.height
));
3468 //-------------------------------------------------------------
3469 static void DumpPrintObjectsTree(nsPrintObject
* aPO
, int aLevel
, FILE* aFD
)
3471 if (!kPrintingLogMod
|| kPrintingLogMod
->level
!= DUMP_LAYOUT_LEVEL
) return;
3473 NS_ASSERTION(aPO
, "Pointer is null!");
3475 FILE * fd
= aFD
?aFD
:stdout
;
3476 const char types
[][3] = {"DC", "FR", "IF", "FS"};
3478 fprintf(fd
, "DocTree\n***************************************************\n");
3479 fprintf(fd
, "T PO DocShell Seq Page Page# Rect\n");
3481 PRInt32 cnt
= aPO
->mKids
.Count();
3482 for (PRInt32 i
=0;i
<cnt
;i
++) {
3483 nsPrintObject
* po
= (nsPrintObject
*)aPO
->mKids
.ElementAt(i
);
3484 NS_ASSERTION(po
, "nsPrintObject can't be null!");
3485 for (PRInt32 k
=0;k
<aLevel
;k
++) fprintf(fd
, " ");
3486 fprintf(fd
, "%s %p %p %p %p %d %d,%d,%d,%d\n", types
[po
->mFrameType
], po
, po
->mDocShell
.get(), po
->mSeqFrame
,
3487 po
->mPageFrame
, po
->mPageNum
, po
->mRect
.x
, po
->mRect
.y
, po
->mRect
.width
, po
->mRect
.height
);
3491 //-------------------------------------------------------------
3492 static void GetDocTitleAndURL(nsPrintObject
* aPO
, char *& aDocStr
, char *& aURLStr
)
3497 PRUnichar
* docTitleStr
;
3498 PRUnichar
* docURLStr
;
3499 nsPrintEngine::GetDisplayTitleAndURL(aPO
,
3500 &docTitleStr
, &docURLStr
,
3501 nsPrintEngine::eDocTitleDefURLDoc
);
3504 nsAutoString
strDocTitle(docTitleStr
);
3505 aDocStr
= ToNewCString(strDocTitle
);
3506 nsMemory::Free(docTitleStr
);
3510 nsAutoString
strURL(docURLStr
);
3511 aURLStr
= ToNewCString(strURL
);
3512 nsMemory::Free(docURLStr
);
3516 //-------------------------------------------------------------
3517 static void DumpPrintObjectsTreeLayout(nsPrintObject
* aPO
,
3518 nsIDeviceContext
* aDC
,
3519 int aLevel
, FILE * aFD
)
3521 if (!kPrintingLogMod
|| kPrintingLogMod
->level
!= DUMP_LAYOUT_LEVEL
) return;
3523 NS_ASSERTION(aPO
, "Pointer is null!");
3524 NS_ASSERTION(aDC
, "Pointer is null!");
3526 const char types
[][3] = {"DC", "FR", "IF", "FS"};
3529 fd
= fopen("tree_layout.txt", "w");
3530 fprintf(fd
, "DocTree\n***************************************************\n");
3531 fprintf(fd
, "***************************************************\n");
3532 fprintf(fd
, "T PO DocShell Seq Page Page# Rect\n");
3537 nsIFrame
* rootFrame
= nsnull
;
3538 if (aPO
->mPresShell
) {
3539 rootFrame
= aPO
->mPresShell
->FrameManager()->GetRootFrame();
3541 for (PRInt32 k
=0;k
<aLevel
;k
++) fprintf(fd
, " ");
3542 fprintf(fd
, "%s %p %p %p %p %d %d,%d,%d,%d\n", types
[aPO
->mFrameType
], aPO
, aPO
->mDocShell
.get(), aPO
->mSeqFrame
,
3543 aPO
->mPageFrame
, aPO
->mPageNum
, aPO
->mRect
.x
, aPO
->mRect
.y
, aPO
->mRect
.width
, aPO
->mRect
.height
);
3544 if (aPO
->IsPrintable()) {
3547 GetDocTitleAndURL(aPO
, docStr
, urlStr
);
3548 DumpLayoutData(docStr
, urlStr
, aPO
->mPresContext
, aDC
, rootFrame
, aPO
->mDocShell
, fd
);
3549 if (docStr
) nsMemory::Free(docStr
);
3550 if (urlStr
) nsMemory::Free(urlStr
);
3552 fprintf(fd
, "<***************************************************>\n");
3554 PRInt32 cnt
= aPO
->mKids
.Count();
3555 for (PRInt32 i
=0;i
<cnt
;i
++) {
3556 nsPrintObject
* po
= (nsPrintObject
*)aPO
->mKids
.ElementAt(i
);
3557 NS_ASSERTION(po
, "nsPrintObject can't be null!");
3558 DumpPrintObjectsTreeLayout(po
, aDC
, aLevel
+1, fd
);
3561 if (aLevel
== 0 && fd
) {
3566 //-------------------------------------------------------------
3567 static void DumpPrintObjectsListStart(const char * aStr
, nsVoidArray
* aDocList
)
3569 if (!kPrintingLogMod
|| kPrintingLogMod
->level
!= DUMP_LAYOUT_LEVEL
) return;
3571 NS_ASSERTION(aStr
, "Pointer is null!");
3572 NS_ASSERTION(aDocList
, "Pointer is null!");
3574 PR_PL(("%s\n", aStr
));
3575 DumpPrintObjectsList(aDocList
);
3578 #define DUMP_DOC_LIST(_title) DumpPrintObjectsListStart((_title), mPrt->mPrintDocList);
3579 #define DUMP_DOC_TREE DumpPrintObjectsTree(mPrt->mPrintObject);
3580 #define DUMP_DOC_TREELAYOUT DumpPrintObjectsTreeLayout(mPrt->mPrintObject, mPrt->mPrintDC);
3583 #define DUMP_DOC_LIST(_title)
3584 #define DUMP_DOC_TREE
3585 #define DUMP_DOC_TREELAYOUT
3588 //---------------------------------------------------------------
3589 //---------------------------------------------------------------
3590 //-- End of debug helper routines
3591 //---------------------------------------------------------------