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 nsIContent
*rootContent
= aPO
->mDocument
->GetRootContent();
1195 MapContentForPO(aPO
, rootContent
);
1197 NS_WARNING("Null root content on (sub)document.");
1200 // Continue recursively walking the chilren of this PO
1201 for (PRInt32 i
=0;i
<aPO
->mKids
.Count();i
++) {
1202 MapContentToWebShells(aRootPO
, (nsPrintObject
*)aPO
->mKids
[i
]);
1207 //-------------------------------------------------------
1208 // A Frame's sub-doc may contain content or a FrameSet
1209 // When it contains a FrameSet the mFrameType for the PrintObject
1210 // is always set to an eFrame. Which is fine when printing "AsIs"
1211 // but is incorrect when when printing "Each Frame Separately".
1212 // When printing "Each Frame Separately" the Frame really acts like
1215 // This method walks the PO tree and checks to see if the PrintObject is
1216 // an eFrame and has children that are eFrames (meaning it's a Frame containing a FrameSet)
1217 // If so, then the mFrameType need to be changed to eFrameSet
1219 // Also note: We only want to call this we are printing "Each Frame Separately"
1220 // when printing "As Is" leave it as an eFrame
1222 nsPrintEngine::CheckForChildFrameSets(nsPrintObject
* aPO
)
1224 NS_ASSERTION(aPO
, "Pointer is null!");
1226 // Continue recursively walking the chilren of this PO
1227 PRBool hasChildFrames
= PR_FALSE
;
1228 for (PRInt32 i
=0;i
<aPO
->mKids
.Count();i
++) {
1229 nsPrintObject
* po
= (nsPrintObject
*)aPO
->mKids
[i
];
1230 if (po
->mFrameType
== eFrame
) {
1231 hasChildFrames
= PR_TRUE
;
1232 CheckForChildFrameSets(po
);
1236 if (hasChildFrames
&& aPO
->mFrameType
== eFrame
) {
1237 aPO
->mFrameType
= eFrameSet
;
1241 //---------------------------------------------------------------------
1242 // This method is key to the entire print mechanism.
1244 // This "maps" or figures out which sub-doc represents a
1245 // given Frame or IFrame in its parent sub-doc.
1247 // So the Mcontent pointer in the child sub-doc points to the
1248 // content in the its parent document, that caused it to be printed.
1249 // This is used later to (after reflow) to find the absolute location
1250 // of the sub-doc on its parent's page frame so it can be
1251 // printed in the correct location.
1253 // This method recursvely "walks" the content for a document finding
1254 // all the Frames and IFrames, then sets the "mFrameType" data member
1255 // which tells us what type of PO we have
1257 nsPrintEngine::MapContentForPO(nsPrintObject
* aPO
,
1258 nsIContent
* aContent
)
1260 NS_PRECONDITION(aPO
&& aContent
, "Null argument");
1262 nsIDocument
* doc
= aContent
->GetDocument();
1264 NS_ASSERTION(doc
, "Content without a document from a document tree?");
1266 nsIDocument
* subDoc
= doc
->GetSubDocumentFor(aContent
);
1269 nsCOMPtr
<nsISupports
> container
= subDoc
->GetContainer();
1270 nsCOMPtr
<nsIDocShell
> docShell(do_QueryInterface(container
));
1273 nsPrintObject
* po
= nsnull
;
1274 PRInt32 cnt
= aPO
->mKids
.Count();
1275 for (PRInt32 i
=0;i
<cnt
;i
++) {
1276 nsPrintObject
* kid
= (nsPrintObject
*)aPO
->mKids
.ElementAt(i
);
1277 if (kid
->mDocument
== subDoc
) {
1283 // XXX If a subdocument has no onscreen presentation, there will be no PO
1284 // This is even if there should be a print presentation
1286 po
->mContent
= aContent
;
1288 nsCOMPtr
<nsIDOMHTMLFrameElement
> frame(do_QueryInterface(aContent
));
1289 // "frame" elements not in a frameset context should be treated
1291 if (frame
&& po
->mParent
->mFrameType
== eFrameSet
) {
1292 po
->mFrameType
= eFrame
;
1294 // Assume something iframe-like, i.e. iframe, object, or embed
1295 po
->mFrameType
= eIFrame
;
1296 SetPrintAsIs(po
, PR_TRUE
);
1297 NS_ASSERTION(po
->mParent
, "The root must be a parent");
1298 po
->mParent
->mPrintAsIs
= PR_TRUE
;
1304 // walk children content
1305 PRUint32 count
= aContent
->GetChildCount();
1306 for (PRUint32 i
= 0; i
< count
; ++i
) {
1307 nsIContent
*child
= aContent
->GetChildAt(i
);
1308 MapContentForPO(aPO
, child
);
1312 //---------------------------------------------------------------------
1314 nsPrintEngine::IsThereAnIFrameSelected(nsIDocShell
* aDocShell
,
1315 nsIDOMWindow
* aDOMWin
,
1316 PRPackedBool
& aIsParentFrameSet
)
1318 aIsParentFrameSet
= IsParentAFrameSet(aDocShell
);
1319 PRBool iFrameIsSelected
= PR_FALSE
;
1320 if (mPrt
&& mPrt
->mPrintObject
) {
1321 nsPrintObject
* po
= FindPrintObjectByDOMWin(mPrt
->mPrintObject
, aDOMWin
);
1322 iFrameIsSelected
= po
&& po
->mFrameType
== eIFrame
;
1324 // First, check to see if we are a frameset
1325 if (!aIsParentFrameSet
) {
1326 // Check to see if there is a currenlt focused frame
1327 // if so, it means the selected frame is either the main docshell
1330 // Get the main docshell's DOMWin to see if it matches
1331 // the frame that is selected
1332 nsCOMPtr
<nsIDOMWindow
> domWin
= do_GetInterface(aDocShell
);
1333 if (domWin
!= aDOMWin
) {
1334 iFrameIsSelected
= PR_TRUE
; // we have a selected IFRAME
1340 return iFrameIsSelected
;
1343 //---------------------------------------------------------------------
1344 // Recursively sets all the PO items to be printed
1345 // from the given item down into the tree
1347 nsPrintEngine::SetPrintPO(nsPrintObject
* aPO
, PRBool aPrint
)
1349 NS_ASSERTION(aPO
, "Pointer is null!");
1351 // Set whether to print flag
1352 aPO
->mDontPrint
= !aPrint
;
1354 for (PRInt32 i
=0;i
<aPO
->mKids
.Count();i
++) {
1355 SetPrintPO((nsPrintObject
*)aPO
->mKids
[i
], aPrint
);
1359 //---------------------------------------------------------------------
1360 // This will first use a Title and/or URL from the PrintSettings
1361 // if one isn't set then it uses the one from the document
1362 // then if not title is there we will make sure we send something back
1363 // depending on the situation.
1365 nsPrintEngine::GetDisplayTitleAndURL(nsPrintObject
* aPO
,
1367 PRUnichar
** aURLStr
,
1368 eDocTitleDefault aDefType
)
1370 NS_ASSERTION(aPO
, "Pointer is null!");
1371 NS_ASSERTION(aTitle
, "Pointer is null!");
1372 NS_ASSERTION(aURLStr
, "Pointer is null!");
1380 // First check to see if the PrintSettings has defined an alternate title
1381 // and use that if it did
1382 PRUnichar
* docTitleStrPS
= nsnull
;
1383 PRUnichar
* docURLStrPS
= nsnull
;
1384 if (mPrt
->mPrintSettings
) {
1385 mPrt
->mPrintSettings
->GetTitle(&docTitleStrPS
);
1386 mPrt
->mPrintSettings
->GetDocURL(&docURLStrPS
);
1388 if (docTitleStrPS
&& *docTitleStrPS
) {
1389 *aTitle
= docTitleStrPS
;
1392 if (docURLStrPS
&& *docURLStrPS
) {
1393 *aURLStr
= docURLStrPS
;
1397 if (docTitleStrPS
&& docURLStrPS
) {
1402 PRUnichar
* docTitle
;
1404 GetDocumentTitleAndURL(aPO
->mDocument
, &docTitle
, &docUrl
);
1410 nsMemory::Free(docUrl
);
1417 nsMemory::Free(docTitle
);
1418 } else if (!docTitleStrPS
) {
1420 case eDocTitleDefBlank
: *aTitle
= ToNewUnicode(EmptyString());
1423 case eDocTitleDefURLDoc
:
1425 *aTitle
= NS_strdup(*aURLStr
);
1426 } else if (mPrt
->mBrandName
) {
1427 *aTitle
= NS_strdup(mPrt
->mBrandName
);
1434 //---------------------------------------------------------------------
1435 nsresult
nsPrintEngine::DocumentReadyForPrinting()
1437 if (mPrt
->mPrintFrameType
== nsIPrintSettings::kEachFrameSep
) {
1438 CheckForChildFrameSets(mPrt
->mPrintObject
);
1442 // Send the document to the printer...
1444 nsresult rv
= SetupToPrintContent();
1445 if (NS_FAILED(rv
)) {
1446 // The print job was canceled or there was a problem
1447 // So remove all other documents from the print list
1448 DonePrintingPages(nsnull
, rv
);
1453 /** ---------------------------------------------------
1454 * Cleans up when an error occurred
1456 nsresult
nsPrintEngine::CleanupOnFailure(nsresult aResult
, PRBool aIsPrinting
)
1458 PR_PL(("**** Failed %s - rv 0x%X", aIsPrinting
?"Printing":"Print Preview", aResult
));
1461 if (mPagePrintTimer
) {
1462 mPagePrintTimer
->Stop();
1463 NS_RELEASE(mPagePrintTimer
);
1467 SetIsPrinting(PR_FALSE
);
1469 SetIsPrintPreview(PR_FALSE
);
1470 SetIsCreatingPrintPreview(PR_FALSE
);
1473 /* cleanup done, let's fire-up an error dialog to notify the user
1474 * what went wrong...
1476 * When rv == NS_ERROR_ABORT, it means we want out of the
1477 * print job without displaying any error messages
1479 if (aResult
!= NS_ERROR_ABORT
) {
1480 ShowPrintErrorDialog(aResult
, aIsPrinting
);
1483 FirePrintCompletionEvent();
1489 //---------------------------------------------------------------------
1491 nsPrintEngine::ShowPrintErrorDialog(nsresult aPrintError
, PRBool aIsPrinting
)
1494 PR_PL(("nsPrintEngine::ShowPrintErrorDialog(nsresult aPrintError=%lx, PRBool aIsPrinting=%d)\n", (long)aPrintError
, (int)aIsPrinting
));
1496 nsCAutoString stringName
;
1500 #define NS_ERROR_TO_LOCALIZED_PRINT_ERROR_MSG(nserr) case nserr: stringName.AssignLiteral(#nserr); break;
1501 NS_ERROR_TO_LOCALIZED_PRINT_ERROR_MSG(NS_ERROR_GFX_PRINTER_CMD_NOT_FOUND
)
1502 NS_ERROR_TO_LOCALIZED_PRINT_ERROR_MSG(NS_ERROR_GFX_PRINTER_CMD_FAILURE
)
1503 NS_ERROR_TO_LOCALIZED_PRINT_ERROR_MSG(NS_ERROR_GFX_PRINTER_NO_PRINTER_AVAILABLE
)
1504 NS_ERROR_TO_LOCALIZED_PRINT_ERROR_MSG(NS_ERROR_GFX_PRINTER_NAME_NOT_FOUND
)
1505 NS_ERROR_TO_LOCALIZED_PRINT_ERROR_MSG(NS_ERROR_GFX_PRINTER_ACCESS_DENIED
)
1506 NS_ERROR_TO_LOCALIZED_PRINT_ERROR_MSG(NS_ERROR_GFX_PRINTER_INVALID_ATTRIBUTE
)
1507 NS_ERROR_TO_LOCALIZED_PRINT_ERROR_MSG(NS_ERROR_GFX_PRINTER_PRINTER_NOT_READY
)
1508 NS_ERROR_TO_LOCALIZED_PRINT_ERROR_MSG(NS_ERROR_GFX_PRINTER_OUT_OF_PAPER
)
1509 NS_ERROR_TO_LOCALIZED_PRINT_ERROR_MSG(NS_ERROR_GFX_PRINTER_PRINTER_IO_ERROR
)
1510 NS_ERROR_TO_LOCALIZED_PRINT_ERROR_MSG(NS_ERROR_GFX_PRINTER_COULD_NOT_OPEN_FILE
)
1511 NS_ERROR_TO_LOCALIZED_PRINT_ERROR_MSG(NS_ERROR_GFX_PRINTER_FILE_IO_ERROR
)
1512 NS_ERROR_TO_LOCALIZED_PRINT_ERROR_MSG(NS_ERROR_GFX_PRINTER_PRINTPREVIEW
)
1513 NS_ERROR_TO_LOCALIZED_PRINT_ERROR_MSG(NS_ERROR_UNEXPECTED
)
1514 NS_ERROR_TO_LOCALIZED_PRINT_ERROR_MSG(NS_ERROR_OUT_OF_MEMORY
)
1515 NS_ERROR_TO_LOCALIZED_PRINT_ERROR_MSG(NS_ERROR_NOT_IMPLEMENTED
)
1516 NS_ERROR_TO_LOCALIZED_PRINT_ERROR_MSG(NS_ERROR_NOT_AVAILABLE
)
1517 NS_ERROR_TO_LOCALIZED_PRINT_ERROR_MSG(NS_ERROR_ABORT
)
1518 NS_ERROR_TO_LOCALIZED_PRINT_ERROR_MSG(NS_ERROR_GFX_PRINTER_STARTDOC
)
1519 NS_ERROR_TO_LOCALIZED_PRINT_ERROR_MSG(NS_ERROR_GFX_PRINTER_ENDDOC
)
1520 NS_ERROR_TO_LOCALIZED_PRINT_ERROR_MSG(NS_ERROR_GFX_PRINTER_STARTPAGE
)
1521 NS_ERROR_TO_LOCALIZED_PRINT_ERROR_MSG(NS_ERROR_GFX_PRINTER_ENDPAGE
)
1522 NS_ERROR_TO_LOCALIZED_PRINT_ERROR_MSG(NS_ERROR_GFX_PRINTER_PRINT_WHILE_PREVIEW
)
1523 NS_ERROR_TO_LOCALIZED_PRINT_ERROR_MSG(NS_ERROR_GFX_PRINTER_PAPER_SIZE_NOT_SUPPORTED
)
1524 NS_ERROR_TO_LOCALIZED_PRINT_ERROR_MSG(NS_ERROR_GFX_PRINTER_ORIENTATION_NOT_SUPPORTED
)
1525 NS_ERROR_TO_LOCALIZED_PRINT_ERROR_MSG(NS_ERROR_GFX_PRINTER_COLORSPACE_NOT_SUPPORTED
)
1526 NS_ERROR_TO_LOCALIZED_PRINT_ERROR_MSG(NS_ERROR_GFX_PRINTER_TOO_MANY_COPIES
)
1527 NS_ERROR_TO_LOCALIZED_PRINT_ERROR_MSG(NS_ERROR_GFX_PRINTER_DRIVER_CONFIGURATION_ERROR
)
1528 NS_ERROR_TO_LOCALIZED_PRINT_ERROR_MSG(NS_ERROR_GFX_PRINTER_DOC_IS_BUSY_PP
)
1529 NS_ERROR_TO_LOCALIZED_PRINT_ERROR_MSG(NS_ERROR_GFX_PRINTER_DOC_WAS_DESTORYED
)
1530 NS_ERROR_TO_LOCALIZED_PRINT_ERROR_MSG(NS_ERROR_GFX_NO_PRINTDIALOG_IN_TOOLKIT
)
1531 NS_ERROR_TO_LOCALIZED_PRINT_ERROR_MSG(NS_ERROR_GFX_NO_PRINTROMPTSERVICE
)
1532 NS_ERROR_TO_LOCALIZED_PRINT_ERROR_MSG(NS_ERROR_GFX_PRINTER_NO_XUL
) // Temporary code for Bug 136185 / bug 240490
1533 NS_ERROR_TO_LOCALIZED_PRINT_ERROR_MSG(NS_ERROR_GFX_PRINTER_PLEX_NOT_SUPPORTED
)
1534 NS_ERROR_TO_LOCALIZED_PRINT_ERROR_MSG(NS_ERROR_GFX_PRINTER_DOC_IS_BUSY
)
1535 NS_ERROR_TO_LOCALIZED_PRINT_ERROR_MSG(NS_ERROR_GFX_PRINTING_NOT_IMPLEMENTED
)
1536 NS_ERROR_TO_LOCALIZED_PRINT_ERROR_MSG(NS_ERROR_GFX_COULD_NOT_LOAD_PRINT_MODULE
)
1537 NS_ERROR_TO_LOCALIZED_PRINT_ERROR_MSG(NS_ERROR_GFX_PRINTER_RESOLUTION_NOT_SUPPORTED
)
1540 NS_ERROR_TO_LOCALIZED_PRINT_ERROR_MSG(NS_ERROR_FAILURE
)
1541 #undef NS_ERROR_TO_LOCALIZED_PRINT_ERROR_MSG
1544 PR_PL(("ShowPrintErrorDialog: stringName='%s'\n", stringName
.get()));
1546 nsXPIDLString msg
, title
;
1548 nsContentUtils::GetLocalizedString(nsContentUtils::ePRINTING_PROPERTIES
,
1549 stringName
.get(), msg
);
1550 if (NS_FAILED(rv
)) {
1551 PR_PL(("GetLocalizedString failed\n"));
1555 rv
= nsContentUtils::GetLocalizedString(nsContentUtils::ePRINTING_PROPERTIES
,
1556 aIsPrinting
? "print_error_dialog_title"
1557 : "printpreview_error_dialog_title",
1560 nsCOMPtr
<nsIWindowWatcher
> wwatch
= do_GetService(NS_WINDOWWATCHER_CONTRACTID
, &rv
);
1561 if (NS_FAILED(rv
)) {
1562 PR_PL(("ShowPrintErrorDialog(): wwatch==nsnull\n"));
1566 nsCOMPtr
<nsIDOMWindow
> active
;
1567 wwatch
->GetActiveWindow(getter_AddRefs(active
));
1569 nsCOMPtr
<nsIPrompt
> dialog
;
1570 /* |GetNewPrompter| allows that |active| is |nsnull|
1571 * (see bug 234982 ("nsPrintEngine::ShowPrintErrorDialog() fails in many cases")) */
1572 wwatch
->GetNewPrompter(active
, getter_AddRefs(dialog
));
1574 PR_PL(("ShowPrintErrorDialog(): dialog==nsnull\n"));
1578 dialog
->Alert(title
.get(), msg
.get());
1579 PR_PL(("ShowPrintErrorDialog(): alert displayed successfully.\n"));
1582 //-----------------------------------------------------------------
1583 //-- Section: Reflow Methods
1584 //-----------------------------------------------------------------
1586 //-------------------------------------------------------
1588 nsPrintEngine::SetupToPrintContent()
1590 // In this step we figure out which documents should be printed
1591 // i.e. if we are printing the selection then only enable that nsPrintObject
1593 if (NS_FAILED(EnablePOsForPrinting())) {
1594 return NS_ERROR_FAILURE
;
1596 DUMP_DOC_LIST("\nAfter Enable------------------------------------------");
1598 // This is an Optimization
1599 // If we are in PP then we already know all the shrinkage information
1600 // so just transfer it to the PrintData and we will skip the extra shrinkage reflow
1602 // doSetPixelScale tells Reflow whether to set the shrinkage value into the DC
1603 // The first time we do not want to do this, the second time through we do
1604 PRBool doSetPixelScale
= PR_FALSE
;
1605 PRBool ppIsShrinkToFit
= mPrtPreview
&& mPrtPreview
->mShrinkToFit
;
1606 if (ppIsShrinkToFit
) {
1607 mPrt
->mShrinkRatio
= mPrtPreview
->mShrinkRatio
;
1608 doSetPixelScale
= PR_TRUE
;
1611 // Here we reflow all the PrintObjects
1612 nsresult rv
= ReflowDocList(mPrt
->mPrintObject
, doSetPixelScale
);
1613 if (NS_FAILED(rv
)) {
1614 return NS_ERROR_FAILURE
;
1617 // Here is where we do the extra reflow for shrinking the content
1618 // But skip this step if we are in PrintPreview
1619 if (mPrt
->mShrinkToFit
&& !ppIsShrinkToFit
) {
1620 // Now look for the PO that has the smallest percent for shrink to fit
1621 if (mPrt
->mPrintDocList
->Count() > 1 && mPrt
->mPrintObject
->mFrameType
== eFrameSet
) {
1622 nsPrintObject
* smallestPO
= FindSmallestSTF();
1623 NS_ASSERTION(smallestPO
, "There must always be an XMost PO!");
1625 // Calc the shrinkage based on the entire content area
1626 mPrt
->mShrinkRatio
= smallestPO
->mShrinkRatio
;
1629 // Single document so use the Shrink as calculated for the PO
1630 mPrt
->mShrinkRatio
= mPrt
->mPrintObject
->mShrinkRatio
;
1633 // Only Shrink if we are smaller
1634 if (mPrt
->mShrinkRatio
< 0.998f
) {
1635 // Clamp Shrink to Fit to 60%
1636 mPrt
->mShrinkRatio
= PR_MAX(mPrt
->mShrinkRatio
, 0.60f
);
1638 for (PRInt32 i
=0;i
<mPrt
->mPrintDocList
->Count();i
++) {
1639 nsPrintObject
* po
= (nsPrintObject
*)mPrt
->mPrintDocList
->ElementAt(i
);
1640 NS_ASSERTION(po
, "nsPrintObject can't be null!");
1641 // Wipe out the presentation before we reflow
1642 po
->DestroyPresentation();
1645 #if (defined(XP_WIN) || defined(XP_OS2)) && defined(EXTENDED_DEBUG_PRINTING)
1646 // We need to clear all the output files here
1647 // because they will be re-created with second reflow of the docs
1648 if (kPrintingLogMod
&& kPrintingLogMod
->level
== DUMP_LAYOUT_LEVEL
) {
1649 RemoveFilesInDir(".\\");
1650 gDumpFileNameCnt
= 0;
1651 gDumpLOFileNameCnt
= 0;
1655 // Here we reflow all the PrintObjects a second time
1656 // this time using the shrinkage values
1657 // The last param here tells reflow to NOT calc the shrinkage values
1658 if (NS_FAILED(ReflowDocList(mPrt
->mPrintObject
, PR_TRUE
))) {
1659 return NS_ERROR_FAILURE
;
1665 float calcRatio
= 0.0f
;
1666 if (mPrt
->mPrintDocList
->Count() > 1 && mPrt
->mPrintObject
->mFrameType
== eFrameSet
) {
1667 nsPrintObject
* smallestPO
= FindSmallestSTF();
1668 NS_ASSERTION(smallestPO
, "There must always be an XMost PO!");
1670 // Calc the shrinkage based on the entire content area
1671 calcRatio
= smallestPO
->mShrinkRatio
;
1674 // Single document so use the Shrink as calculated for the PO
1675 calcRatio
= mPrt
->mPrintObject
->mShrinkRatio
;
1677 PR_PL(("**************************************************************************\n"));
1678 PR_PL(("STF Ratio is: %8.5f Effective Ratio: %8.5f Diff: %8.5f\n", mPrt
->mShrinkRatio
, calcRatio
, mPrt
->mShrinkRatio
-calcRatio
));
1679 PR_PL(("**************************************************************************\n"));
1684 DUMP_DOC_LIST(("\nAfter Reflow------------------------------------------"));
1686 PR_PL(("-------------------------------------------------------\n"));
1689 CalcNumPrintablePages(mPrt
->mNumPrintablePages
);
1691 PR_PL(("--- Printing %d pages\n", mPrt
->mNumPrintablePages
));
1692 DUMP_DOC_TREELAYOUT
;
1694 // Print listener setup...
1695 if (mPrt
!= nsnull
) {
1696 mPrt
->OnStartPrinting();
1699 PRUnichar
* fileName
= nsnull
;
1700 // check to see if we are printing to a file
1701 PRBool isPrintToFile
= PR_FALSE
;
1702 mPrt
->mPrintSettings
->GetPrintToFile(&isPrintToFile
);
1703 if (isPrintToFile
) {
1704 // On some platforms The BeginDocument needs to know the name of the file
1705 // and it uses the PrintService to get it, so we need to set it into the PrintService here
1706 mPrt
->mPrintSettings
->GetToFileName(&fileName
);
1709 PRUnichar
* docTitleStr
;
1710 PRUnichar
* docURLStr
;
1711 GetDisplayTitleAndURL(mPrt
->mPrintObject
, &docTitleStr
, &docURLStr
, eDocTitleDefURLDoc
);
1713 PRInt32 startPage
= 1;
1714 PRInt32 endPage
= mPrt
->mNumPrintablePages
;
1716 PRInt16 printRangeType
= nsIPrintSettings::kRangeAllPages
;
1717 mPrt
->mPrintSettings
->GetPrintRange(&printRangeType
);
1718 if (printRangeType
== nsIPrintSettings::kRangeSpecifiedPageRange
) {
1719 mPrt
->mPrintSettings
->GetStartPageRange(&startPage
);
1720 mPrt
->mPrintSettings
->GetEndPageRange(&endPage
);
1721 if (endPage
> mPrt
->mNumPrintablePages
) {
1722 endPage
= mPrt
->mNumPrintablePages
;
1727 // BeginDocument may pass back a FAILURE code
1728 // i.e. On Windows, if you are printing to a file and hit "Cancel"
1729 // to the "File Name" dialog, this comes back as an error
1730 // Don't start printing when regression test are executed
1731 if (!mPrt
->mDebugFilePtr
&& mIsDoingPrinting
) {
1732 rv
= mPrt
->mPrintDC
->BeginDocument(docTitleStr
, fileName
, startPage
, endPage
);
1735 if (mIsCreatingPrintPreview
) {
1736 // Print Preview -- Pass ownership of docTitleStr and docURLStr
1737 // to the pageSequenceFrame, to be displayed in the header
1738 nsIPageSequenceFrame
*seqFrame
= nsnull
;
1739 mPrt
->mPrintObject
->mPresShell
->GetPageSequenceFrame(&seqFrame
);
1741 seqFrame
->StartPrint(mPrt
->mPrintObject
->mPresContext
,
1742 mPrt
->mPrintSettings
, docTitleStr
, docURLStr
);
1745 if (docTitleStr
) nsMemory::Free(docTitleStr
);
1746 if (docURLStr
) nsMemory::Free(docURLStr
);
1749 PR_PL(("****************** Begin Document ************************\n"));
1751 NS_ENSURE_SUCCESS(rv
, rv
);
1753 // This will print the docshell document
1754 // when it completes asynchronously in the DonePrintingPages method
1755 // it will check to see if there are more docshells to be printed and
1756 // then PrintDocContent will be called again.
1758 if (mIsDoingPrinting
) {
1759 PrintDocContent(mPrt
->mPrintObject
, rv
); // ignore return value
1765 //-------------------------------------------------------
1766 // Recursively reflow each sub-doc and then calc
1767 // all the frame locations of the sub-docs
1769 nsPrintEngine::ReflowDocList(nsPrintObject
* aPO
, PRBool aSetPixelScale
)
1771 NS_ENSURE_ARG_POINTER(aPO
);
1773 // Check to see if the subdocument's element has been hidden by the parent document
1774 if (aPO
->mParent
&& aPO
->mParent
->mPresShell
) {
1776 aPO
->mParent
->mPresShell
->GetPrimaryFrameFor(aPO
->mContent
);
1778 if (!frame
->GetStyleVisibility()->IsVisible()) {
1779 aPO
->mDontPrint
= PR_TRUE
;
1780 aPO
->mInvisible
= PR_TRUE
;
1786 // Here is where we set the shrinkage value into the DC
1787 // and this is what actually makes it shrink
1788 if (aSetPixelScale
&& aPO
->mFrameType
!= eIFrame
) {
1790 if (mPrt
->mPrintFrameType
== nsIPrintSettings::kFramesAsIs
|| mPrt
->mPrintFrameType
== nsIPrintSettings::kNoFrames
) {
1791 ratio
= mPrt
->mShrinkRatio
- 0.005f
; // round down
1793 ratio
= aPO
->mShrinkRatio
- 0.005f
; // round down
1795 aPO
->mZoomRatio
= ratio
;
1796 } else if (!mPrt
->mShrinkToFit
) {
1798 mPrt
->mPrintSettings
->GetScaling(&scaling
);
1799 aPO
->mZoomRatio
= float(scaling
);
1804 rv
= ReflowPrintObject(aPO
);
1805 NS_ENSURE_SUCCESS(rv
, rv
);
1807 PRInt32 cnt
= aPO
->mKids
.Count();
1808 for (PRInt32 i
=0;i
<cnt
;i
++) {
1809 rv
= ReflowDocList((nsPrintObject
*)aPO
->mKids
[i
], aSetPixelScale
);
1810 NS_ENSURE_SUCCESS(rv
, rv
);
1815 //-------------------------------------------------------
1816 // Reflow a nsPrintObject
1818 nsPrintEngine::ReflowPrintObject(nsPrintObject
* aPO
)
1820 NS_ASSERTION(aPO
, "Pointer is null!");
1821 if (!aPO
) return NS_ERROR_FAILURE
;
1824 PRBool documentIsTopLevel
;
1825 nsIFrame
* frame
= nsnull
;
1826 if (!aPO
->IsPrintable())
1829 if (aPO
->mParent
&& aPO
->mParent
->IsPrintable()) {
1830 if (aPO
->mParent
->mPresShell
) {
1831 frame
= aPO
->mParent
->mPresShell
->FrameManager()->
1832 GetPrimaryFrameFor(aPO
->mContent
, -1);
1834 // Without a frame, this document can't be displayed; therefore, there is no
1835 // point to reflowing it
1839 adjSize
= frame
->GetContentRect().Size();
1840 documentIsTopLevel
= PR_FALSE
;
1841 // presshell exists because parent is printable
1843 nscoord pageWidth
, pageHeight
;
1844 mPrt
->mPrintDC
->GetDeviceSurfaceDimensions(pageWidth
, pageHeight
);
1845 #if defined(XP_UNIX) && !defined(XP_MACOSX)
1846 // If we're in landscape mode on Linux, the device surface will have
1847 // been rotated, so for the purposes of reflowing content, we'll
1848 // treat device's height as our width and its width as our height,
1849 PRInt32 orientation
;
1850 mPrt
->mPrintSettings
->GetOrientation(&orientation
);
1851 if (nsIPrintSettings::kLandscapeOrientation
== orientation
) {
1852 adjSize
= nsSize(pageHeight
, pageWidth
);
1854 adjSize
= nsSize(pageWidth
, pageHeight
);
1857 adjSize
= nsSize(pageWidth
, pageHeight
);
1858 #endif // XP_UNIX && !XP_MACOSX
1859 documentIsTopLevel
= PR_TRUE
;
1862 // create the PresContext
1863 aPO
->mPresContext
= new nsPresContext(aPO
->mDocument
,
1864 mIsCreatingPrintPreview
?
1865 nsPresContext::eContext_PrintPreview
:
1866 nsPresContext::eContext_Print
);
1867 NS_ENSURE_TRUE(aPO
->mPresContext
, NS_ERROR_OUT_OF_MEMORY
);
1868 aPO
->mPresContext
->SetPrintSettings(mPrt
->mPrintSettings
);
1870 // set the presentation context to the value in the print settings
1871 PRBool printBGColors
;
1872 mPrt
->mPrintSettings
->GetPrintBGColors(&printBGColors
);
1873 aPO
->mPresContext
->SetBackgroundColorDraw(printBGColors
);
1874 mPrt
->mPrintSettings
->GetPrintBGImages(&printBGColors
);
1875 aPO
->mPresContext
->SetBackgroundImageDraw(printBGColors
);
1877 // init it with the DC
1878 nsresult rv
= aPO
->mPresContext
->Init(mPrt
->mPrintDC
);
1879 NS_ENSURE_SUCCESS(rv
, rv
);
1881 aPO
->mViewManager
= do_CreateInstance(kViewManagerCID
, &rv
);
1882 NS_ENSURE_SUCCESS(rv
,rv
);
1884 rv
= aPO
->mViewManager
->Init(mPrt
->mPrintDC
);
1885 NS_ENSURE_SUCCESS(rv
,rv
);
1887 nsStyleSet
* styleSet
;
1888 rv
= mDocViewerPrint
->CreateStyleSet(aPO
->mDocument
, &styleSet
);
1889 NS_ENSURE_SUCCESS(rv
, rv
);
1891 rv
= aPO
->mDocument
->CreateShell(aPO
->mPresContext
, aPO
->mViewManager
,
1892 styleSet
, getter_AddRefs(aPO
->mPresShell
));
1893 if (NS_FAILED(rv
)) {
1898 styleSet
->EndUpdate();
1900 // The pres shell now owns the style set object.
1902 PR_PL(("In DV::ReflowPrintObject PO: %p (%9s) Setting w,h to %d,%d\n", aPO
,
1903 gFrameTypesStr
[aPO
->mFrameType
], adjSize
.width
, adjSize
.height
));
1905 // Here we decide whether we need scrollbars and
1906 // what the parent will be of the widget
1907 // How this logic presently works: Print Preview is always as-is (as far
1908 // as I can tell; not sure how it would work in other cases); only the root
1909 // is not eIFrame or eFrame. The child documents get a parent widget from
1910 // logic in nsFrameFrame. In any case, a child widget is created for the root
1911 // view of the document.
1912 PRBool canCreateScrollbars
= PR_FALSE
;
1913 nsIView
* parentView
;
1914 // the top nsPrintObject's widget will always have scrollbars
1916 nsIView
* view
= frame
->GetView();
1917 NS_ENSURE_TRUE(view
, NS_ERROR_FAILURE
);
1918 view
= view
->GetFirstChild();
1919 NS_ENSURE_TRUE(view
, NS_ERROR_FAILURE
);
1922 canCreateScrollbars
= PR_TRUE
;
1923 parentView
= nsnull
;
1926 // Create a child window of the parent that is our "root view/window"
1927 nsRect tbounds
= nsRect(nsPoint(0, 0), adjSize
);
1928 nsIView
* rootView
= aPO
->mViewManager
->CreateView(tbounds
, parentView
);
1929 NS_ENSURE_TRUE(rootView
, NS_ERROR_OUT_OF_MEMORY
);
1931 // Only create a widget for print preview; when printing, a widget is
1932 // unnecessary and unexpected
1933 // Also, no widget should be needed except for the top-level document
1934 if (mIsCreatingPrintPreview
&& documentIsTopLevel
) {
1935 nsNativeWidget widget
= nsnull
;
1937 widget
= mParentWidget
->GetNativeData(NS_NATIVE_WIDGET
);
1938 rv
= rootView
->CreateWidget(kWidgetCID
, nsnull
,
1939 widget
, PR_TRUE
, PR_TRUE
,
1940 eContentTypeContent
);
1941 NS_ENSURE_SUCCESS(rv
, rv
);
1942 aPO
->mWindow
= rootView
->GetWidget();
1943 aPO
->mPresContext
->SetPaginatedScrolling(canCreateScrollbars
);
1946 // Setup hierarchical relationship in view manager
1947 aPO
->mViewManager
->SetRootView(rootView
);
1949 // This docshell stuff is weird; will go away when we stop having multiple
1950 // presentations per document
1951 nsCOMPtr
<nsISupports
> supps(do_QueryInterface(aPO
->mDocShell
));
1952 aPO
->mPresContext
->SetContainer(supps
);
1954 aPO
->mPresShell
->BeginObservingDocument();
1956 aPO
->mPresContext
->SetPageSize(adjSize
);
1957 aPO
->mPresContext
->SetIsRootPaginatedDocument(documentIsTopLevel
);
1958 aPO
->mPresContext
->SetPageScale(aPO
->mZoomRatio
);
1959 // Calculate scale factor from printer to screen
1960 float printDPI
= float(mPrt
->mPrintDC
->AppUnitsPerInch()) /
1961 float(mPrt
->mPrintDC
->AppUnitsPerDevPixel());
1962 float screenDPI
= float(mDeviceContext
->AppUnitsPerInch()) /
1963 float(mDeviceContext
->AppUnitsPerDevPixel());
1964 aPO
->mPresContext
->SetPrintPreviewScale(screenDPI
/ printDPI
);
1966 rv
= aPO
->mPresShell
->InitialReflow(adjSize
.width
, adjSize
.height
);
1968 NS_ENSURE_SUCCESS(rv
, rv
);
1969 NS_ASSERTION(aPO
->mPresShell
, "Presshell should still be here");
1971 // Process the reflow event InitialReflow posted
1972 aPO
->mPresShell
->FlushPendingNotifications(Flush_Layout
);
1974 nsCOMPtr
<nsIPresShell
> displayShell
;
1975 aPO
->mDocShell
->GetPresShell(getter_AddRefs(displayShell
));
1976 // Transfer Selection Ranges to the new Print PresShell
1977 nsCOMPtr
<nsISelection
> selection
, selectionPS
;
1978 // It's okay if there is no display shell, just skip copying the selection
1980 selection
= displayShell
->GetCurrentSelection(nsISelectionController::SELECTION_NORMAL
);
1982 selectionPS
= aPO
->mPresShell
->GetCurrentSelection(nsISelectionController::SELECTION_NORMAL
);
1983 if (selection
&& selectionPS
) {
1985 selection
->GetRangeCount(&cnt
);
1987 for (inx
=0;inx
<cnt
;inx
++) {
1988 nsCOMPtr
<nsIDOMRange
> range
;
1989 if (NS_SUCCEEDED(selection
->GetRangeAt(inx
, getter_AddRefs(range
))))
1990 selectionPS
->AddRange(range
);
1994 // If we are trying to shrink the contents to fit on the page
1995 // we must first locate the "pageContent" frame
1996 // Then we walk the frame tree and look for the "xmost" frame
1997 // this is the frame where the right-hand side of the frame extends
1999 if (mPrt
->mShrinkToFit
&& documentIsTopLevel
) {
2000 nsIPageSequenceFrame
* pageSequence
;
2001 aPO
->mPresShell
->GetPageSequenceFrame(&pageSequence
);
2002 pageSequence
->GetSTFPercent(aPO
->mShrinkRatio
);
2005 #ifdef EXTENDED_DEBUG_PRINTING
2006 if (kPrintingLogMod
&& kPrintingLogMod
->level
== DUMP_LAYOUT_LEVEL
) {
2009 GetDocTitleAndURL(aPO
, docStr
, urlStr
);
2011 sprintf(filename
, "print_dump_%d.txt", gDumpFileNameCnt
++);
2012 // Dump all the frames and view to a a file
2013 FILE * fd
= fopen(filename
, "w");
2015 nsIFrame
*theRootFrame
=
2016 aPO
->mPresShell
->FrameManager()->GetRootFrame();
2017 fprintf(fd
, "Title: %s\n", docStr
?docStr
:"");
2018 fprintf(fd
, "URL: %s\n", urlStr
?urlStr
:"");
2019 fprintf(fd
, "--------------- Frames ----------------\n");
2020 nsCOMPtr
<nsIRenderingContext
> renderingContext
;
2021 mPrt
->mPrintDocDC
->CreateRenderingContext(*getter_AddRefs(renderingContext
));
2022 RootFrameList(aPO
->mPresContext
, fd
, 0);
2023 //DumpFrames(fd, aPO->mPresContext, renderingContext, theRootFrame, 0);
2024 fprintf(fd
, "---------------------------------------\n\n");
2025 fprintf(fd
, "--------------- Views From Root Frame----------------\n");
2026 nsIView
* v
= theRootFrame
->GetView();
2030 printf("View is null!\n");
2033 fprintf(fd
, "--------------- All Views ----------------\n");
2034 DumpViews(docShell
, fd
);
2035 fprintf(fd
, "---------------------------------------\n\n");
2039 if (docStr
) nsMemory::Free(docStr
);
2040 if (urlStr
) nsMemory::Free(urlStr
);
2047 //-------------------------------------------------------
2048 // Figure out how many documents and how many total pages we are printing
2050 nsPrintEngine::CalcNumPrintablePages(PRInt32
& aNumPages
)
2053 // Count the number of printable documents
2054 // and printable pages
2056 for (i
=0; i
<mPrt
->mPrintDocList
->Count(); i
++) {
2057 nsPrintObject
* po
= (nsPrintObject
*)mPrt
->mPrintDocList
->ElementAt(i
);
2058 NS_ASSERTION(po
, "nsPrintObject can't be null!");
2059 if (po
->mPresContext
&& po
->mPresContext
->IsRootPaginatedDocument()) {
2060 nsIPageSequenceFrame
* pageSequence
;
2061 po
->mPresShell
->GetPageSequenceFrame(&pageSequence
);
2062 nsIFrame
* seqFrame
;
2063 if (NS_SUCCEEDED(CallQueryInterface(pageSequence
, &seqFrame
))) {
2064 nsIFrame
* frame
= seqFrame
->GetFirstChild(nsnull
);
2067 frame
= frame
->GetNextSibling();
2073 //-----------------------------------------------------------------
2074 //-- Done: Reflow Methods
2075 //-----------------------------------------------------------------
2077 //-----------------------------------------------------------------
2078 //-- Section: Printing Methods
2079 //-----------------------------------------------------------------
2081 //-------------------------------------------------------
2082 // Called for each DocShell that needs to be printed
2084 nsPrintEngine::PrintDocContent(nsPrintObject
* aPO
, nsresult
& aStatus
)
2086 NS_ASSERTION(aPO
, "Pointer is null!");
2089 if (!aPO
->mHasBeenPrinted
&& aPO
->IsPrintable()) {
2090 aStatus
= DoPrint(aPO
);
2094 // If |aPO->mPrintAsIs| and |aPO->mHasBeenPrinted| are true,
2095 // the kids frames are already processed in |PrintPage|.
2096 if (!aPO
->mInvisible
&& !(aPO
->mPrintAsIs
&& aPO
->mHasBeenPrinted
)) {
2097 for (PRInt32 i
=0;i
<aPO
->mKids
.Count();i
++) {
2098 nsPrintObject
* po
= (nsPrintObject
*)aPO
->mKids
[i
];
2099 PRBool printed
= PrintDocContent(po
, aStatus
);
2100 if (printed
|| NS_FAILED(aStatus
)) {
2108 //-------------------------------------------------------
2110 nsPrintEngine::DoPrint(nsPrintObject
* aPO
)
2113 PR_PL(("**************************** %s ****************************\n", gFrameTypesStr
[aPO
->mFrameType
]));
2114 PR_PL(("****** In DV::DoPrint PO: %p \n", aPO
));
2116 nsIPresShell
* poPresShell
= aPO
->mPresShell
;
2117 nsPresContext
* poPresContext
= aPO
->mPresContext
;
2119 NS_ASSERTION(poPresContext
, "PrintObject has not been reflowed");
2120 NS_ASSERTION(poPresContext
->Type() != nsPresContext::eContext_PrintPreview
,
2121 "How did this context end up here?");
2123 if (mPrt
->mPrintProgressParams
) {
2124 SetDocAndURLIntoProgress(aPO
, mPrt
->mPrintProgressParams
);
2128 PRInt16 printRangeType
= nsIPrintSettings::kRangeAllPages
;
2130 if (mPrt
->mPrintSettings
!= nsnull
) {
2131 mPrt
->mPrintSettings
->GetPrintRange(&printRangeType
);
2134 // Ask the page sequence frame to print all the pages
2135 nsIPageSequenceFrame
* pageSequence
;
2136 poPresShell
->GetPageSequenceFrame(&pageSequence
);
2137 NS_ASSERTION(nsnull
!= pageSequence
, "no page sequence frame");
2139 // We are done preparing for printing, so we can turn this off
2140 mPrt
->mPreparingForPrint
= PR_FALSE
;
2142 // mPrt->mDebugFilePtr this is onlu non-null when compiled for debugging
2143 if (nsnull
!= mPrt
->mDebugFilePtr
) {
2145 // output the regression test
2146 nsIFrameDebug
* fdbg
;
2147 nsIFrame
* root
= poPresShell
->FrameManager()->GetRootFrame();
2149 if (NS_SUCCEEDED(CallQueryInterface(root
, &fdbg
))) {
2150 fdbg
->DumpRegressionData(poPresContext
, mPrt
->mDebugFilePtr
, 0, PR_TRUE
);
2152 fclose(mPrt
->mDebugFilePtr
);
2153 SetIsPrinting(PR_FALSE
);
2156 #ifdef EXTENDED_DEBUG_PRINTING
2157 nsIFrame
* rootFrame
= poPresShell
->FrameManager()->GetRootFrame();
2158 if (aPO
->IsPrintable()) {
2161 GetDocTitleAndURL(aPO
, docStr
, urlStr
);
2162 DumpLayoutData(docStr
, urlStr
, poPresContext
, mPrt
->mPrintDocDC
, rootFrame
, docShell
, nsnull
);
2163 if (docStr
) nsMemory::Free(docStr
);
2164 if (urlStr
) nsMemory::Free(urlStr
);
2168 if (mPrt
->mPrintSettings
) {
2169 PRUnichar
* docTitleStr
= nsnull
;
2170 PRUnichar
* docURLStr
= nsnull
;
2172 GetDisplayTitleAndURL(aPO
, &docTitleStr
, &docURLStr
, eDocTitleDefBlank
);
2174 if (nsIPrintSettings::kRangeSelection
== printRangeType
) {
2175 poPresContext
->SetIsRenderingOnlySelection(PR_TRUE
);
2176 // temporarily creating rendering context
2177 // which is needed to dinf the selection frames
2178 nsCOMPtr
<nsIRenderingContext
> rc
;
2179 mPrt
->mPrintDC
->CreateRenderingContext(*getter_AddRefs(rc
));
2181 // find the starting and ending page numbers
2182 // via the selection
2183 nsIFrame
* startFrame
;
2185 PRInt32 startPageNum
;
2190 nsCOMPtr
<nsISelection
> selectionPS
;
2191 selectionPS
= poPresShell
->GetCurrentSelection(nsISelectionController::SELECTION_NORMAL
);
2193 rv
= GetPageRangeForSelection(poPresShell
, poPresContext
, *rc
, selectionPS
, pageSequence
,
2194 &startFrame
, startPageNum
, startRect
,
2195 &endFrame
, endPageNum
, endRect
);
2196 if (NS_SUCCEEDED(rv
)) {
2197 mPrt
->mPrintSettings
->SetStartPageRange(startPageNum
);
2198 mPrt
->mPrintSettings
->SetEndPageRange(endPageNum
);
2199 nsMargin
marginTwips(0,0,0,0);
2200 nsMargin
unwrtMarginTwips(0,0,0,0);
2201 mPrt
->mPrintSettings
->GetMarginInTwips(marginTwips
);
2202 mPrt
->mPrintSettings
->GetUnwriteableMarginInTwips(unwrtMarginTwips
);
2203 nsMargin totalMargin
= poPresContext
->TwipsToAppUnits(marginTwips
+
2205 if (startPageNum
== endPageNum
) {
2207 startRect
.y
-= totalMargin
.top
;
2208 endRect
.y
-= totalMargin
.top
;
2210 // Clip out selection regions above the top of the first page
2211 if (startRect
.y
< 0) {
2212 // Reduce height to be the height of the positive-territory
2213 // region of original rect
2214 startRect
.height
= PR_MAX(0, startRect
.YMost());
2217 if (endRect
.y
< 0) {
2218 // Reduce height to be the height of the positive-territory
2219 // region of original rect
2220 endRect
.height
= PR_MAX(0, endRect
.YMost());
2223 NS_ASSERTION(endRect
.y
>= startRect
.y
,
2224 "Selection end point should be after start point");
2225 NS_ASSERTION(startRect
.height
>= 0,
2226 "rect should have non-negative height.");
2227 NS_ASSERTION(endRect
.height
>= 0,
2228 "rect should have non-negative height.");
2230 nscoord selectionHgt
= endRect
.y
+ endRect
.height
- startRect
.y
;
2231 // XXX This is temporary fix for printing more than one page of a selection
2232 pageSequence
->SetSelectionHeight(startRect
.y
* aPO
->mZoomRatio
,
2233 selectionHgt
* aPO
->mZoomRatio
);
2235 // calc total pages by getting calculating the selection's height
2236 // and then dividing it by how page content frames will fit.
2237 nscoord pageWidth
, pageHeight
;
2238 mPrt
->mPrintDC
->GetDeviceSurfaceDimensions(pageWidth
, pageHeight
);
2239 pageHeight
-= totalMargin
.top
+ totalMargin
.bottom
;
2240 PRInt32 totalPages
= NSToIntCeil(float(selectionHgt
) * aPO
->mZoomRatio
/ float(pageHeight
));
2241 pageSequence
->SetTotalNumPages(totalPages
);
2247 nsIFrame
* seqFrame
;
2248 if (NS_FAILED(CallQueryInterface(pageSequence
, &seqFrame
))) {
2249 SetIsPrinting(PR_FALSE
);
2250 return NS_ERROR_FAILURE
;
2253 mPageSeqFrame
= pageSequence
;
2254 mPageSeqFrame
->StartPrint(poPresContext
, mPrt
->mPrintSettings
, docTitleStr
, docURLStr
);
2256 // Schedule Page to Print
2257 PR_PL(("Scheduling Print of PO: %p (%s) \n", aPO
, gFrameTypesStr
[aPO
->mFrameType
]));
2258 StartPagePrintTimer(aPO
);
2260 // not sure what to do here!
2261 SetIsPrinting(PR_FALSE
);
2262 return NS_ERROR_FAILURE
;
2270 //---------------------------------------------------------------------
2272 nsPrintEngine::SetDocAndURLIntoProgress(nsPrintObject
* aPO
,
2273 nsIPrintProgressParams
* aParams
)
2275 NS_ASSERTION(aPO
, "Must have vaild nsPrintObject");
2276 NS_ASSERTION(aParams
, "Must have vaild nsIPrintProgressParams");
2278 if (!aPO
|| !aPO
->mDocShell
|| !aParams
) {
2281 const PRUint32 kTitleLength
= 64;
2283 PRUnichar
* docTitleStr
;
2284 PRUnichar
* docURLStr
;
2285 GetDisplayTitleAndURL(aPO
, &docTitleStr
, &docURLStr
, eDocTitleDefURLDoc
);
2287 // Make sure the Titles & URLS don't get too long for the progress dialog
2288 ElipseLongString(docTitleStr
, kTitleLength
, PR_FALSE
);
2289 ElipseLongString(docURLStr
, kTitleLength
, PR_TRUE
);
2291 aParams
->SetDocTitle(docTitleStr
);
2292 aParams
->SetDocURL(docURLStr
);
2294 if (docTitleStr
!= nsnull
) nsMemory::Free(docTitleStr
);
2295 if (docURLStr
!= nsnull
) nsMemory::Free(docURLStr
);
2298 //---------------------------------------------------------------------
2300 nsPrintEngine::ElipseLongString(PRUnichar
*& aStr
, const PRUint32 aLen
, PRBool aDoFront
)
2302 // Make sure the URLS don't get too long for the progress dialog
2303 if (aStr
&& nsCRT::strlen(aStr
) > aLen
) {
2305 PRUnichar
* ptr
= &aStr
[nsCRT::strlen(aStr
)-aLen
+3];
2306 nsAutoString newStr
;
2307 newStr
.AppendLiteral("...");
2309 nsMemory::Free(aStr
);
2310 aStr
= ToNewUnicode(newStr
);
2312 nsAutoString
newStr(aStr
);
2313 newStr
.SetLength(aLen
-3);
2314 newStr
.AppendLiteral("...");
2315 nsMemory::Free(aStr
);
2316 aStr
= ToNewUnicode(newStr
);
2321 //-------------------------------------------------------
2323 nsPrintEngine::PrintPage(nsPrintObject
* aPO
,
2326 NS_ASSERTION(aPO
, "aPO is null!");
2327 NS_ASSERTION(mPageSeqFrame
, "mPageSeqFrame is null!");
2328 NS_ASSERTION(mPrt
, "mPrt is null!");
2330 // Although these should NEVER be NULL
2331 // This is added insurance, to make sure we don't crash in optimized builds
2332 if (!mPrt
|| !aPO
|| !mPageSeqFrame
) {
2333 ShowPrintErrorDialog(NS_ERROR_FAILURE
);
2334 return PR_TRUE
; // means we are done printing
2337 PR_PL(("-----------------------------------\n"));
2338 PR_PL(("------ In DV::PrintPage PO: %p (%s)\n", aPO
, gFrameTypesStr
[aPO
->mFrameType
]));
2340 // Check setting to see if someone request it be cancelled
2341 PRBool isCancelled
= PR_FALSE
;
2342 mPrt
->mPrintSettings
->GetIsCancelled(&isCancelled
);
2346 PRInt32 pageNum
, numPages
, endPage
;
2347 mPageSeqFrame
->GetCurrentPageNum(&pageNum
);
2348 mPageSeqFrame
->GetNumPages(&numPages
);
2350 PRBool donePrinting
;
2351 PRBool isDoingPrintRange
;
2352 mPageSeqFrame
->IsDoingPrintRange(&isDoingPrintRange
);
2353 if (isDoingPrintRange
) {
2356 mPageSeqFrame
->GetPrintRange(&fromPage
, &toPage
);
2358 if (fromPage
> numPages
) {
2361 if (toPage
> numPages
) {
2365 PR_PL(("****** Printing Page %d printing from %d to page %d\n", pageNum
, fromPage
, toPage
));
2367 donePrinting
= pageNum
>= toPage
;
2368 aInRange
= pageNum
>= fromPage
&& pageNum
<= toPage
;
2369 endPage
= (toPage
- fromPage
)+1;
2371 PR_PL(("****** Printing Page %d of %d page(s)\n", pageNum
, numPages
));
2373 donePrinting
= pageNum
>= numPages
;
2378 // XXX This is wrong, but the actual behavior in the presence of a print
2380 if (mPrt
->mPrintFrameType
== nsIPrintSettings::kEachFrameSep
)
2381 endPage
= mPrt
->mNumPrintablePages
;
2383 mPrt
->DoOnProgressChange(++mPrt
->mNumPagesPrinted
, endPage
, PR_FALSE
, 0);
2386 // if a print job was cancelled externally, an EndPage or BeginPage may
2387 // fail and the failure is passed back here.
2388 // Returning PR_TRUE means we are done printing.
2390 // When rv == NS_ERROR_ABORT, it means we want out of the
2391 // print job without displaying any error messages
2392 nsresult rv
= mPageSeqFrame
->PrintNextPage();
2393 if (NS_FAILED(rv
)) {
2394 if (rv
!= NS_ERROR_ABORT
) {
2395 ShowPrintErrorDialog(rv
);
2396 mPrt
->mIsAborted
= PR_TRUE
;
2401 mPageSeqFrame
->DoPageEnd();
2403 return donePrinting
;
2406 /** ---------------------------------------------------
2407 * Find by checking frames type
2410 nsPrintEngine::FindSelectionBoundsWithList(nsPresContext
* aPresContext
,
2411 nsIRenderingContext
& aRC
,
2413 nsIFrame
* aParentFrame
,
2415 nsIFrame
*& aStartFrame
,
2417 nsIFrame
*& aEndFrame
,
2420 NS_ASSERTION(aPresContext
, "Pointer is null!");
2421 NS_ASSERTION(aParentFrame
, "Pointer is null!");
2423 nsIFrame
* child
= aParentFrame
->GetFirstChild(aList
);
2424 aRect
+= aParentFrame
->GetPosition();
2426 // only leaf frames have this bit flipped
2427 // then check the hard way
2428 PRBool isSelected
= (child
->GetStateBits() & NS_FRAME_SELECTED_CONTENT
)
2429 == NS_FRAME_SELECTED_CONTENT
;
2431 isSelected
= child
->IsVisibleForPainting();
2435 nsRect r
= child
->GetRect();
2436 if (aStartFrame
== nsnull
) {
2437 aStartFrame
= child
;
2438 aStartRect
.SetRect(aRect
.x
+ r
.x
, aRect
.y
+ r
.y
, r
.width
, r
.height
);
2441 aEndRect
.SetRect(aRect
.x
+ r
.x
, aRect
.y
+ r
.y
, r
.width
, r
.height
);
2444 FindSelectionBounds(aPresContext
, aRC
, child
, aRect
, aStartFrame
, aStartRect
, aEndFrame
, aEndRect
);
2445 child
= child
->GetNextSibling();
2447 aRect
-= aParentFrame
->GetPosition();
2451 //-------------------------------------------------------
2452 // Find the Frame that is XMost
2454 nsPrintEngine::FindSelectionBounds(nsPresContext
* aPresContext
,
2455 nsIRenderingContext
& aRC
,
2456 nsIFrame
* aParentFrame
,
2458 nsIFrame
*& aStartFrame
,
2460 nsIFrame
*& aEndFrame
,
2463 NS_ASSERTION(aPresContext
, "Pointer is null!");
2464 NS_ASSERTION(aParentFrame
, "Pointer is null!");
2466 // loop through named child lists
2467 nsIAtom
* childListName
= nsnull
;
2468 PRInt32 childListIndex
= 0;
2470 nsresult rv
= FindSelectionBoundsWithList(aPresContext
, aRC
, childListName
, aParentFrame
, aRect
, aStartFrame
, aStartRect
, aEndFrame
, aEndRect
);
2471 NS_ENSURE_SUCCESS(rv
, rv
);
2472 childListName
= aParentFrame
->GetAdditionalChildListName(childListIndex
++);
2473 } while (childListName
);
2477 /** ---------------------------------------------------
2478 * This method finds the starting and ending page numbers
2479 * of the selection and also returns rect for each where
2480 * the x,y of the rect is relative to the very top of the
2481 * frame tree (absolutely positioned)
2484 nsPrintEngine::GetPageRangeForSelection(nsIPresShell
* aPresShell
,
2485 nsPresContext
* aPresContext
,
2486 nsIRenderingContext
& aRC
,
2487 nsISelection
* aSelection
,
2488 nsIPageSequenceFrame
* aPageSeqFrame
,
2489 nsIFrame
** aStartFrame
,
2490 PRInt32
& aStartPageNum
,
2492 nsIFrame
** aEndFrame
,
2493 PRInt32
& aEndPageNum
,
2496 NS_ASSERTION(aPresShell
, "Pointer is null!");
2497 NS_ASSERTION(aPresContext
, "Pointer is null!");
2498 NS_ASSERTION(aSelection
, "Pointer is null!");
2499 NS_ASSERTION(aPageSeqFrame
, "Pointer is null!");
2500 NS_ASSERTION(aStartFrame
, "Pointer is null!");
2501 NS_ASSERTION(aEndFrame
, "Pointer is null!");
2503 nsIFrame
* seqFrame
;
2504 if (NS_FAILED(CallQueryInterface(aPageSeqFrame
, &seqFrame
))) {
2505 return NS_ERROR_FAILURE
;
2508 nsIFrame
* startFrame
= nsnull
;
2509 nsIFrame
* endFrame
= nsnull
;
2511 // start out with the sequence frame and search the entire frame tree
2512 // capturing the starting and ending child frames of the selection
2514 nsRect r
= seqFrame
->GetRect();
2515 FindSelectionBounds(aPresContext
, aRC
, seqFrame
, r
,
2516 startFrame
, aStartRect
, endFrame
, aEndRect
);
2519 printf("Start Frame: %p\n", startFrame
);
2520 printf("End Frame: %p\n", endFrame
);
2523 // initial the page numbers here
2524 // in case we don't find and frames
2528 nsIFrame
* startPageFrame
;
2529 nsIFrame
* endPageFrame
;
2531 // check to make sure we found a starting frame
2532 if (startFrame
!= nsnull
) {
2533 // Now search up the tree to find what page the
2534 // start/ending selections frames are on
2536 // Check to see if start should be same as end if
2537 // the end frame comes back null
2538 if (endFrame
== nsnull
) {
2539 // XXX the "GetPageFrame" step could be integrated into
2540 // the FindSelectionBounds step, but walking up to find
2541 // the parent of a child frame isn't expensive and it makes
2542 // FindSelectionBounds a little easier to understand
2543 startPageFrame
= nsLayoutUtils::GetPageFrame(startFrame
);
2544 endPageFrame
= startPageFrame
;
2545 aEndRect
= aStartRect
;
2547 startPageFrame
= nsLayoutUtils::GetPageFrame(startFrame
);
2548 endPageFrame
= nsLayoutUtils::GetPageFrame(endFrame
);
2551 return NS_ERROR_FAILURE
;
2555 printf("Start Page: %p\n", startPageFrame
);
2556 printf("End Page: %p\n", endPageFrame
);
2558 // dump all the pages and their pointers
2560 PRInt32 pageNum
= 1;
2561 nsIFrame
* child
= seqFrame
->GetFirstChild(nsnull
);
2562 while (child
!= nsnull
) {
2563 printf("Page: %d - %p\n", pageNum
, child
);
2565 child
= child
->GetNextSibling();
2570 // Now that we have the page frames
2571 // find out what the page numbers are for each frame
2572 PRInt32 pageNum
= 1;
2573 nsIFrame
* page
= seqFrame
->GetFirstChild(nsnull
);
2574 while (page
!= nsnull
) {
2575 if (page
== startPageFrame
) {
2576 aStartPageNum
= pageNum
;
2578 if (page
== endPageFrame
) {
2579 aEndPageNum
= pageNum
;
2582 page
= page
->GetNextSibling();
2586 printf("Start Page No: %d\n", aStartPageNum
);
2587 printf("End Page No: %d\n", aEndPageNum
);
2590 *aStartFrame
= startPageFrame
;
2591 *aEndFrame
= endPageFrame
;
2596 //-----------------------------------------------------------------
2597 //-- Done: Printing Methods
2598 //-----------------------------------------------------------------
2601 //-----------------------------------------------------------------
2602 //-- Section: Misc Support Methods
2603 //-----------------------------------------------------------------
2605 //---------------------------------------------------------------------
2606 void nsPrintEngine::SetIsPrinting(PRBool aIsPrinting
)
2608 mIsDoingPrinting
= aIsPrinting
;
2609 if (mDocViewerPrint
) {
2610 mDocViewerPrint
->SetIsPrinting(aIsPrinting
);
2612 if (mPrt
&& aIsPrinting
) {
2613 mPrt
->mPreparingForPrint
= PR_TRUE
;
2617 //---------------------------------------------------------------------
2618 void nsPrintEngine::SetIsPrintPreview(PRBool aIsPrintPreview
)
2620 mIsDoingPrintPreview
= aIsPrintPreview
;
2622 if (mDocViewerPrint
) {
2623 mDocViewerPrint
->SetIsPrintPreview(aIsPrintPreview
);
2627 //---------------------------------------------------------------------
2629 nsPrintEngine::CleanupDocTitleArray(PRUnichar
**& aArray
, PRInt32
& aCount
)
2631 for (PRInt32 i
= aCount
- 1; i
>= 0; i
--) {
2632 nsMemory::Free(aArray
[i
]);
2634 nsMemory::Free(aArray
);
2639 //---------------------------------------------------------------------
2641 PRBool
nsPrintEngine::HasFramesetChild(nsIContent
* aContent
)
2647 PRUint32 numChildren
= aContent
->GetChildCount();
2649 // do a breadth search across all siblings
2650 for (PRUint32 i
= 0; i
< numChildren
; ++i
) {
2651 nsIContent
*child
= aContent
->GetChildAt(i
);
2652 if (child
->Tag() == nsGkAtoms::frameset
&&
2653 child
->IsNodeOfType(nsINode::eHTML
)) {
2663 /** ---------------------------------------------------
2664 * Get the Focused Frame for a documentviewer
2666 already_AddRefed
<nsIDOMWindow
>
2667 nsPrintEngine::FindFocusedDOMWindow()
2669 nsIDOMWindow
* domWin
= nsnull
;
2671 nsPIDOMWindow
*theDOMWindow
= mDocument
->GetWindow();
2673 nsIFocusController
*focusController
=
2674 theDOMWindow
->GetRootFocusController();
2675 if (focusController
) {
2676 nsCOMPtr
<nsIDOMWindowInternal
> theDOMWin
;
2677 focusController
->GetFocusedWindow(getter_AddRefs(theDOMWin
));
2678 if(theDOMWin
&& IsWindowsInOurSubTree(theDOMWin
)){
2679 NS_ADDREF(domWin
= theDOMWin
);
2687 //---------------------------------------------------------------------
2689 nsPrintEngine::IsWindowsInOurSubTree(nsIDOMWindow
* aDOMWindow
)
2691 PRBool found
= PR_FALSE
;
2693 // now check to make sure it is in "our" tree of docshells
2694 nsCOMPtr
<nsPIDOMWindow
> window(do_QueryInterface(aDOMWindow
));
2696 nsCOMPtr
<nsIDocShellTreeItem
> docShellAsItem
=
2697 do_QueryInterface(window
->GetDocShell());
2699 if (docShellAsItem
) {
2700 // get this DocViewer docshell
2701 nsCOMPtr
<nsIDocShell
> thisDVDocShell(do_QueryInterface(mContainer
));
2703 nsCOMPtr
<nsIDocShell
> parentDocshell(do_QueryInterface(docShellAsItem
));
2704 if (parentDocshell
) {
2705 if (parentDocshell
== thisDVDocShell
) {
2710 break; // at top of tree
2712 nsCOMPtr
<nsIDocShellTreeItem
> docShellParent
;
2713 docShellAsItem
->GetSameTypeParent(getter_AddRefs(docShellParent
));
2714 docShellAsItem
= docShellParent
;
2722 //-------------------------------------------------------
2724 nsPrintEngine::DonePrintingPages(nsPrintObject
* aPO
, nsresult aResult
)
2726 //NS_ASSERTION(aPO, "Pointer is null!");
2727 PR_PL(("****** In DV::DonePrintingPages PO: %p (%s)\n", aPO
, aPO
?gFrameTypesStr
[aPO
->mFrameType
]:""));
2729 if (aPO
!= nsnull
) {
2730 aPO
->mHasBeenPrinted
= PR_TRUE
;
2732 PRBool didPrint
= PrintDocContent(mPrt
->mPrintObject
, rv
);
2733 if (NS_SUCCEEDED(rv
) && didPrint
) {
2734 PR_PL(("****** In DV::DonePrintingPages PO: %p (%s) didPrint:%s (Not Done Printing)\n", aPO
, gFrameTypesStr
[aPO
->mFrameType
], PRT_YESNO(didPrint
)));
2739 if (NS_SUCCEEDED(aResult
)) {
2740 FirePrintCompletionEvent();
2743 SetIsPrinting(PR_FALSE
);
2745 // Release reference to mPagePrintTimer; the timer object destroys itself
2746 // after this returns true
2747 NS_IF_RELEASE(mPagePrintTimer
);
2752 //-------------------------------------------------------
2753 // Recursively sets the PO items to be printed "As Is"
2754 // from the given item down into the tree
2756 nsPrintEngine::SetPrintAsIs(nsPrintObject
* aPO
, PRBool aAsIs
)
2758 NS_ASSERTION(aPO
, "Pointer is null!");
2760 aPO
->mPrintAsIs
= aAsIs
;
2761 for (PRInt32 i
=0;i
<aPO
->mKids
.Count();i
++) {
2762 SetPrintAsIs((nsPrintObject
*)aPO
->mKids
[i
], aAsIs
);
2766 //-------------------------------------------------------
2767 // Given a DOMWindow it recursively finds the PO object that matches
2769 nsPrintEngine::FindPrintObjectByDOMWin(nsPrintObject
* aPO
,
2770 nsIDOMWindow
* aDOMWin
)
2772 NS_ASSERTION(aPO
, "Pointer is null!");
2774 // Often the CurFocused DOMWindow is passed in
2775 // andit is valid for it to be null, so short circut
2780 nsCOMPtr
<nsIDOMWindow
> domWin(do_GetInterface(aPO
->mDocShell
));
2781 if (domWin
&& domWin
== aDOMWin
) {
2785 PRInt32 cnt
= aPO
->mKids
.Count();
2786 for (PRInt32 i
= 0; i
< cnt
; ++i
) {
2787 nsPrintObject
* po
= FindPrintObjectByDOMWin((nsPrintObject
*)aPO
->mKids
[i
],
2797 //-------------------------------------------------------
2799 nsPrintEngine::EnablePOsForPrinting()
2801 // NOTE: All POs have been "turned off" for printing
2802 // this is where we decided which POs get printed.
2803 mPrt
->mSelectedPO
= nsnull
;
2805 if (mPrt
->mPrintSettings
== nsnull
) {
2806 return NS_ERROR_FAILURE
;
2809 mPrt
->mPrintFrameType
= nsIPrintSettings::kNoFrames
;
2810 mPrt
->mPrintSettings
->GetPrintFrameType(&mPrt
->mPrintFrameType
);
2812 PRInt16 printHowEnable
= nsIPrintSettings::kFrameEnableNone
;
2813 mPrt
->mPrintSettings
->GetHowToEnableFrameUI(&printHowEnable
);
2815 PRInt16 printRangeType
= nsIPrintSettings::kRangeAllPages
;
2816 mPrt
->mPrintSettings
->GetPrintRange(&printRangeType
);
2819 PR_PL(("********* nsPrintEngine::EnablePOsForPrinting *********\n"));
2820 PR_PL(("PrintFrameType: %s \n", gPrintFrameTypeStr
[mPrt
->mPrintFrameType
]));
2821 PR_PL(("HowToEnableFrameUI: %s \n", gFrameHowToEnableStr
[printHowEnable
]));
2822 PR_PL(("PrintRange: %s \n", gPrintRangeStr
[printRangeType
]));
2825 // ***** This is the ultimate override *****
2826 // if we are printing the selection (either an IFrame or selection range)
2827 // then set the mPrintFrameType as if it were the selected frame
2828 if (printRangeType
== nsIPrintSettings::kRangeSelection
) {
2829 mPrt
->mPrintFrameType
= nsIPrintSettings::kSelectedFrame
;
2830 printHowEnable
= nsIPrintSettings::kFrameEnableNone
;
2833 // This tells us that the "Frame" UI has turned off,
2834 // so therefore there are no FrameSets/Frames/IFrames to be printed
2836 // This means there are not FrameSets,
2837 // but the document could contain an IFrame
2838 if (printHowEnable
== nsIPrintSettings::kFrameEnableNone
) {
2840 // Print all the pages or a sub range of pages
2841 if (printRangeType
== nsIPrintSettings::kRangeAllPages
||
2842 printRangeType
== nsIPrintSettings::kRangeSpecifiedPageRange
) {
2843 SetPrintPO(mPrt
->mPrintObject
, PR_TRUE
);
2845 // Set the children so they are PrinAsIs
2846 // In this case, the children are probably IFrames
2847 if (mPrt
->mPrintObject
->mKids
.Count() > 0) {
2848 for (PRInt32 i
=0;i
<mPrt
->mPrintObject
->mKids
.Count();i
++) {
2849 nsPrintObject
* po
= (nsPrintObject
*)mPrt
->mPrintObject
->mKids
[i
];
2850 NS_ASSERTION(po
, "nsPrintObject can't be null!");
2854 // ***** Another override *****
2855 mPrt
->mPrintFrameType
= nsIPrintSettings::kFramesAsIs
;
2857 PR_PL(("PrintFrameType: %s \n", gPrintFrameTypeStr
[mPrt
->mPrintFrameType
]));
2858 PR_PL(("HowToEnableFrameUI: %s \n", gFrameHowToEnableStr
[printHowEnable
]));
2859 PR_PL(("PrintRange: %s \n", gPrintRangeStr
[printRangeType
]));
2863 // This means we are either printed a selected IFrame or
2864 // we are printing the current selection
2865 if (printRangeType
== nsIPrintSettings::kRangeSelection
) {
2867 // If the currentFocusDOMWin can'r be null if something is selected
2868 if (mPrt
->mCurrentFocusWin
) {
2869 // Find the selected IFrame
2870 nsPrintObject
* po
= FindPrintObjectByDOMWin(mPrt
->mPrintObject
, mPrt
->mCurrentFocusWin
);
2872 mPrt
->mSelectedPO
= po
;
2873 // Makes sure all of its children are be printed "AsIs"
2876 // Now, only enable this POs (the selected PO) and all of its children
2877 SetPrintPO(po
, PR_TRUE
);
2879 // check to see if we have a range selection,
2880 // as oppose to a insert selection
2881 // this means if the user just clicked on the IFrame then
2882 // there will not be a selection so we want the entire page to print
2884 // XXX this is sort of a hack right here to make the page
2885 // not try to reposition itself when printing selection
2886 nsCOMPtr
<nsIDOMWindow
> domWin
= do_GetInterface(po
->mDocShell
);
2887 if (!IsThereARangeSelection(domWin
)) {
2888 printRangeType
= nsIPrintSettings::kRangeAllPages
;
2889 mPrt
->mPrintSettings
->SetPrintRange(printRangeType
);
2891 PR_PL(("PrintFrameType: %s \n", gPrintFrameTypeStr
[mPrt
->mPrintFrameType
]));
2892 PR_PL(("HowToEnableFrameUI: %s \n", gFrameHowToEnableStr
[printHowEnable
]));
2893 PR_PL(("PrintRange: %s \n", gPrintRangeStr
[printRangeType
]));
2897 for (PRInt32 i
=0;i
<mPrt
->mPrintDocList
->Count();i
++) {
2898 nsPrintObject
* po
= (nsPrintObject
*)mPrt
->mPrintDocList
->ElementAt(i
);
2899 NS_ASSERTION(po
, "nsPrintObject can't be null!");
2900 nsCOMPtr
<nsIDOMWindow
> domWin
= do_GetInterface(po
->mDocShell
);
2901 if (IsThereARangeSelection(domWin
)) {
2902 mPrt
->mCurrentFocusWin
= domWin
;
2903 SetPrintPO(po
, PR_TRUE
);
2912 // check to see if there is a selection when a FrameSet is present
2913 if (printRangeType
== nsIPrintSettings::kRangeSelection
) {
2914 // If the currentFocusDOMWin can'r be null if something is selected
2915 if (mPrt
->mCurrentFocusWin
) {
2916 // Find the selected IFrame
2917 nsPrintObject
* po
= FindPrintObjectByDOMWin(mPrt
->mPrintObject
, mPrt
->mCurrentFocusWin
);
2919 mPrt
->mSelectedPO
= po
;
2920 // Makes sure all of its children are be printed "AsIs"
2923 // Now, only enable this POs (the selected PO) and all of its children
2924 SetPrintPO(po
, PR_TRUE
);
2926 // check to see if we have a range selection,
2927 // as oppose to a insert selection
2928 // this means if the user just clicked on the IFrame then
2929 // there will not be a selection so we want the entire page to print
2931 // XXX this is sort of a hack right here to make the page
2932 // not try to reposition itself when printing selection
2933 nsCOMPtr
<nsIDOMWindow
> domWin
= do_GetInterface(po
->mDocShell
);
2934 if (!IsThereARangeSelection(domWin
)) {
2935 printRangeType
= nsIPrintSettings::kRangeAllPages
;
2936 mPrt
->mPrintSettings
->SetPrintRange(printRangeType
);
2938 PR_PL(("PrintFrameType: %s \n", gPrintFrameTypeStr
[mPrt
->mPrintFrameType
]));
2939 PR_PL(("HowToEnableFrameUI: %s \n", gFrameHowToEnableStr
[printHowEnable
]));
2940 PR_PL(("PrintRange: %s \n", gPrintRangeStr
[printRangeType
]));
2946 // If we are printing "AsIs" then sets all the POs to be printed as is
2947 if (mPrt
->mPrintFrameType
== nsIPrintSettings::kFramesAsIs
) {
2948 SetPrintAsIs(mPrt
->mPrintObject
);
2949 SetPrintPO(mPrt
->mPrintObject
, PR_TRUE
);
2953 // If we are printing the selected Frame then
2954 // find that PO for that selected DOMWin and set it all of its
2955 // children to be printed
2956 if (mPrt
->mPrintFrameType
== nsIPrintSettings::kSelectedFrame
) {
2958 if ((mPrt
->mIsParentAFrameSet
&& mPrt
->mCurrentFocusWin
) || mPrt
->mIsIFrameSelected
) {
2959 nsPrintObject
* po
= FindPrintObjectByDOMWin(mPrt
->mPrintObject
, mPrt
->mCurrentFocusWin
);
2961 mPrt
->mSelectedPO
= po
;
2962 // NOTE: Calling this sets the "po" and
2963 // we don't want to do this for documents that have no children,
2964 // because then the "DoEndPage" gets called and it shouldn't
2965 if (po
->mKids
.Count() > 0) {
2966 // Makes sure that itself, and all of its children are printed "AsIs"
2970 // Now, only enable this POs (the selected PO) and all of its children
2971 SetPrintPO(po
, PR_TRUE
);
2977 // If we are print each subdoc separately,
2978 // then don't print any of the FraneSet Docs
2979 if (mPrt
->mPrintFrameType
== nsIPrintSettings::kEachFrameSep
) {
2980 SetPrintPO(mPrt
->mPrintObject
, PR_TRUE
);
2981 PRInt32 cnt
= mPrt
->mPrintDocList
->Count();
2982 for (PRInt32 i
=0;i
<cnt
;i
++) {
2983 nsPrintObject
* po
= (nsPrintObject
*)mPrt
->mPrintDocList
->ElementAt(i
);
2984 NS_ASSERTION(po
, "nsPrintObject can't be null!");
2985 if (po
->mFrameType
== eFrameSet
) {
2986 po
->mDontPrint
= PR_TRUE
;
2994 //-------------------------------------------------------
2995 // Return the nsPrintObject with that is XMost (The widest frameset frame) AND
2996 // contains the XMost (widest) layout frame
2998 nsPrintEngine::FindSmallestSTF()
3000 float smallestRatio
= 1.0f
;
3001 nsPrintObject
* smallestPO
= nsnull
;
3003 for (PRInt32 i
=0;i
<mPrt
->mPrintDocList
->Count();i
++) {
3004 nsPrintObject
* po
= (nsPrintObject
*)mPrt
->mPrintDocList
->ElementAt(i
);
3005 NS_ASSERTION(po
, "nsPrintObject can't be null!");
3006 if (po
->mFrameType
!= eFrameSet
&& po
->mFrameType
!= eIFrame
) {
3007 if (po
->mShrinkRatio
< smallestRatio
) {
3008 smallestRatio
= po
->mShrinkRatio
;
3014 #ifdef EXTENDED_DEBUG_PRINTING
3015 if (smallestPO
) printf("*PO: %p Type: %d %10.3f\n", smallestPO
, smallestPO
->mFrameType
, smallestPO
->mShrinkRatio
);
3020 //-------------------------------------------------------
3022 nsPrintEngine::TurnScriptingOn(PRBool aDoTurnOn
)
3024 nsPrintData
* prt
= mPrt
;
3025 #ifdef NS_PRINT_PREVIEW
3034 NS_ASSERTION(mDocument
, "We MUST have a document.");
3035 // First, get the script global object from the document...
3037 for (PRInt32 i
=0;i
<prt
->mPrintDocList
->Count();i
++) {
3038 nsPrintObject
* po
= (nsPrintObject
*)prt
->mPrintDocList
->ElementAt(i
);
3039 NS_ASSERTION(po
, "nsPrintObject can't be null!");
3041 nsIDocument
* doc
= po
->mDocument
;
3043 // get the script global object
3044 nsIScriptGlobalObject
*scriptGlobalObj
= doc
->GetScriptGlobalObject();
3046 if (scriptGlobalObj
) {
3047 nsIScriptContext
*scx
= scriptGlobalObj
->GetContext();
3048 NS_ASSERTION(scx
, "Can't get nsIScriptContext");
3050 doc
->DeleteProperty(nsGkAtoms::scriptEnabledBeforePrintPreview
);
3052 // Have to be careful, because people call us over and over again with
3053 // aDoTurnOn == PR_FALSE. So don't set the property if it's already
3054 // set, since in that case we'd set it to the wrong value.
3056 doc
->GetProperty(nsGkAtoms::scriptEnabledBeforePrintPreview
,
3058 if (propThere
== NS_PROPTABLE_PROP_NOT_THERE
) {
3059 // Stash the current value of IsScriptEnabled on the document, so
3060 // that layout code running in print preview doesn't get confused.
3061 doc
->SetProperty(nsGkAtoms::scriptEnabledBeforePrintPreview
,
3062 NS_INT32_TO_PTR(doc
->IsScriptEnabled()));
3065 scx
->SetScriptsEnabled(aDoTurnOn
, PR_TRUE
);
3070 //-----------------------------------------------------------------
3071 //-- Done: Misc Support Methods
3072 //-----------------------------------------------------------------
3075 //-----------------------------------------------------------------
3076 //-- Section: Finishing up or Cleaning up
3077 //-----------------------------------------------------------------
3079 //-----------------------------------------------------------------
3081 nsPrintEngine::CloseProgressDialog(nsIWebProgressListener
* aWebProgressListener
)
3083 if (aWebProgressListener
) {
3084 aWebProgressListener
->OnStateChange(nsnull
, nsnull
, nsIWebProgressListener::STATE_STOP
|nsIWebProgressListener::STATE_IS_DOCUMENT
, nsnull
);
3088 //-----------------------------------------------------------------
3090 nsPrintEngine::FinishPrintPreview()
3092 nsresult rv
= NS_OK
;
3094 #ifdef NS_PRINT_PREVIEW
3097 /* we're already finished with print preview */
3101 rv
= DocumentReadyForPrinting();
3103 SetIsCreatingPrintPreview(PR_FALSE
);
3105 /* cleaup on failure + notify user */
3106 if (NS_FAILED(rv
)) {
3107 /* cleanup done, let's fire-up an error dialog to notify the user
3108 * what went wrong...
3110 mPrt
->OnEndPrinting();
3111 TurnScriptingOn(PR_TRUE
);
3116 // At this point we are done preparing everything
3117 // before it is to be created
3120 if (mIsDoingPrintPreview
&& mOldPrtPreview
) {
3121 delete mOldPrtPreview
;
3122 mOldPrtPreview
= nsnull
;
3125 InstallPrintPreviewListener();
3127 mPrt
->OnEndPrinting();
3129 // PrintPreview was built using the mPrt (code reuse)
3130 // then we assign it over
3134 #endif // NS_PRINT_PREVIEW
3139 //-----------------------------------------------------------------
3140 //-- Done: Finishing up or Cleaning up
3141 //-----------------------------------------------------------------
3144 /*=============== Timer Related Code ======================*/
3146 nsPrintEngine::StartPagePrintTimer(nsPrintObject
* aPO
)
3148 if (!mPagePrintTimer
) {
3149 nsresult rv
= NS_NewPagePrintTimer(&mPagePrintTimer
);
3150 NS_ENSURE_SUCCESS(rv
, rv
);
3152 // Get the delay time in between the printing of each page
3153 // this gives the user more time to press cancel
3154 PRInt32 printPageDelay
= 500;
3155 mPrt
->mPrintSettings
->GetPrintPageDelay(&printPageDelay
);
3157 mPagePrintTimer
->Init(this, mDocViewerPrint
, printPageDelay
);
3160 return mPagePrintTimer
->Start(aPO
);
3163 /*=============== nsIObserver Interface ======================*/
3165 nsPrintEngine::Observe(nsISupports
*aSubject
, const char *aTopic
, const PRUnichar
*aData
)
3167 nsresult rv
= NS_ERROR_FAILURE
;
3169 if (mIsDoingPrinting
) {
3170 rv
= DocumentReadyForPrinting();
3172 /* cleaup on failure + notify user */
3173 if (NS_FAILED(rv
)) {
3174 CleanupOnFailure(rv
, PR_TRUE
);
3177 rv
= FinishPrintPreview();
3178 if (NS_FAILED(rv
)) {
3179 CleanupOnFailure(rv
, PR_FALSE
);
3182 mPrtPreview
->OnEndPrinting();
3191 //---------------------------------------------------------------
3192 //-- PLEvent Notification
3193 //---------------------------------------------------------------
3194 class nsPrintCompletionEvent
: public nsRunnable
{
3196 nsPrintCompletionEvent(nsIDocumentViewerPrint
*docViewerPrint
)
3197 : mDocViewerPrint(docViewerPrint
) {
3198 NS_ASSERTION(mDocViewerPrint
, "mDocViewerPrint is null.");
3202 if (mDocViewerPrint
)
3203 mDocViewerPrint
->OnDonePrinting();
3208 nsCOMPtr
<nsIDocumentViewerPrint
> mDocViewerPrint
;
3211 //-----------------------------------------------------------
3213 nsPrintEngine::FirePrintCompletionEvent()
3215 nsCOMPtr
<nsIRunnable
> event
= new nsPrintCompletionEvent(mDocViewerPrint
);
3216 if (NS_FAILED(NS_DispatchToCurrentThread(event
)))
3217 NS_WARNING("failed to dispatch print completion event");
3220 //---------------------------------------------------------------
3221 //---------------------------------------------------------------
3222 //-- Debug helper routines
3223 //---------------------------------------------------------------
3224 //---------------------------------------------------------------
3225 #if (defined(XP_WIN) || defined(XP_OS2)) && defined(EXTENDED_DEBUG_PRINTING)
3226 #include "windows.h"
3227 #include "process.h"
3230 #define MY_FINDFIRST(a,b) FindFirstFile(a,b)
3231 #define MY_FINDNEXT(a,b) FindNextFile(a,b)
3232 #define ISDIR(a) (a.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
3233 #define MY_FINDCLOSE(a) FindClose(a)
3234 #define MY_FILENAME(a) a.cFileName
3235 #define MY_FILESIZE(a) (a.nFileSizeHigh * MAXDWORD) + a.nFileSizeLow
3237 int RemoveFilesInDir(const char * aDir
)
3239 WIN32_FIND_DATA data_ptr
;
3242 char path
[MAX_PATH
];
3246 // Append slash to the end of the directory names if not there
3247 if (path
[strlen(path
)-1] != '\\')
3250 char findPath
[MAX_PATH
];
3251 strcpy(findPath
, path
);
3252 strcat(findPath
, "*.*");
3254 find_handle
= MY_FINDFIRST(findPath
, &data_ptr
);
3256 if (find_handle
!= INVALID_HANDLE_VALUE
) {
3259 && (stricmp(MY_FILENAME(data_ptr
),"."))
3260 && (stricmp(MY_FILENAME(data_ptr
),".."))) {
3263 else if (!ISDIR(data_ptr
)) {
3264 if (!strncmp(MY_FILENAME(data_ptr
), "print_dump", 10)) {
3265 char fileName
[MAX_PATH
];
3266 strcpy(fileName
, aDir
);
3267 strcat(fileName
, "\\");
3268 strcat(fileName
, MY_FILENAME(data_ptr
));
3269 printf("Removing %s\n", fileName
);
3273 } while(MY_FINDNEXT(find_handle
,&data_ptr
));
3274 MY_FINDCLOSE(find_handle
);
3280 #ifdef EXTENDED_DEBUG_PRINTING
3282 /** ---------------------------------------------------
3283 * Dumps Frames for Printing
3285 static void RootFrameList(nsPresContext
* aPresContext
, FILE* out
, PRInt32 aIndent
)
3287 if (!aPresContext
|| !out
)
3290 nsIPresShell
*shell
= aPresContext
->GetPresShell();
3292 nsIFrame
* frame
= shell
->FrameManager()->GetRootFrame();
3294 nsIFrameDebug
* debugFrame
;
3295 nsresult rv
= CallQueryInterface(frame
, &debugFrame
);
3296 if (NS_SUCCEEDED(rv
))
3297 debugFrame
->List(aPresContext
, out
, aIndent
);
3302 /** ---------------------------------------------------
3303 * Dumps Frames for Printing
3305 static void DumpFrames(FILE* out
,
3306 nsPresContext
* aPresContext
,
3307 nsIRenderingContext
* aRendContext
,
3311 NS_ASSERTION(out
, "Pointer is null!");
3312 NS_ASSERTION(aPresContext
, "Pointer is null!");
3313 NS_ASSERTION(aRendContext
, "Pointer is null!");
3314 NS_ASSERTION(aFrame
, "Pointer is null!");
3316 nsIFrame
* child
= aFrame
->GetFirstChild(nsnull
);
3317 while (child
!= nsnull
) {
3318 for (PRInt32 i
=0;i
<aLevel
;i
++) {
3322 nsIFrameDebug
* frameDebug
;
3324 if (NS_SUCCEEDED(CallQueryInterface(child
, &frameDebug
))) {
3325 frameDebug
->GetFrameName(tmp
);
3327 fputs(NS_LossyConvertUTF16toASCII(tmp
).get(), out
);
3329 if (NS_SUCCEEDED(child
->IsVisibleForPainting(aPresContext
, *aRendContext
, PR_TRUE
, &isSelected
))) {
3330 fprintf(out
, " %p %s", child
, isSelected
?"VIS":"UVS");
3331 nsRect rect
= child
->GetRect();
3332 fprintf(out
, "[%d,%d,%d,%d] ", rect
.x
, rect
.y
, rect
.width
, rect
.height
);
3333 fprintf(out
, "v: %p ", (void*)child
->GetView());
3335 DumpFrames(out
, aPresContext
, aRendContext
, child
, aLevel
+1);
3336 child
= child
->GetNextSibling();
3342 /** ---------------------------------------------------
3343 * Dumps the Views from the DocShell
3346 DumpViews(nsIDocShell
* aDocShell
, FILE* out
)
3348 NS_ASSERTION(aDocShell
, "Pointer is null!");
3349 NS_ASSERTION(out
, "Pointer is null!");
3351 if (nsnull
!= aDocShell
) {
3352 fprintf(out
, "docshell=%p \n", aDocShell
);
3353 nsIPresShell
* shell
= nsPrintEngine::GetPresShellFor(aDocShell
);
3355 nsIViewManager
* vm
= shell
->GetViewManager();
3358 vm
->GetRootView(root
);
3359 if (nsnull
!= root
) {
3365 fputs("null pres shell\n", out
);
3368 // dump the views of the sub documents
3370 nsCOMPtr
<nsIDocShellTreeNode
> docShellAsNode(do_QueryInterface(aDocShell
));
3371 docShellAsNode
->GetChildCount(&n
);
3372 for (i
= 0; i
< n
; i
++) {
3373 nsCOMPtr
<nsIDocShellTreeItem
> child
;
3374 docShellAsNode
->GetChildAt(i
, getter_AddRefs(child
));
3375 nsCOMPtr
<nsIDocShell
> childAsShell(do_QueryInterface(child
));
3377 DumpViews(childAsShell
, out
);
3383 /** ---------------------------------------------------
3384 * Dumps the Views and Frames
3386 void DumpLayoutData(char* aTitleStr
,
3388 nsPresContext
* aPresContext
,
3389 nsIDeviceContext
* aDC
,
3390 nsIFrame
* aRootFrame
,
3391 nsIDocShekk
* aDocShell
,
3394 if (!kPrintingLogMod
|| kPrintingLogMod
->level
!= DUMP_LAYOUT_LEVEL
) return;
3396 if (aPresContext
== nsnull
|| aDC
== nsnull
) {
3400 #ifdef NS_PRINT_PREVIEW
3401 if (aPresContext
->Type() == nsPresContext::eContext_PrintPreview
) {
3406 NS_ASSERTION(aRootFrame
, "Pointer is null!");
3407 NS_ASSERTION(aDocShell
, "Pointer is null!");
3409 // Dump all the frames and view to a a file
3411 sprintf(filename
, "print_dump_layout_%d.txt", gDumpLOFileNameCnt
++);
3412 FILE * fd
= aFD
?aFD
:fopen(filename
, "w");
3414 fprintf(fd
, "Title: %s\n", aTitleStr
?aTitleStr
:"");
3415 fprintf(fd
, "URL: %s\n", aURLStr
?aURLStr
:"");
3416 fprintf(fd
, "--------------- Frames ----------------\n");
3417 fprintf(fd
, "--------------- Frames ----------------\n");
3418 nsCOMPtr
<nsIRenderingContext
> renderingContext
;
3419 aDC
->CreateRenderingContext(*getter_AddRefs(renderingContext
));
3420 RootFrameList(aPresContext
, fd
, 0);
3421 //DumpFrames(fd, aPresContext, renderingContext, aRootFrame, 0);
3422 fprintf(fd
, "---------------------------------------\n\n");
3423 fprintf(fd
, "--------------- Views From Root Frame----------------\n");
3424 nsIView
* v
= aRootFrame
->GetView();
3428 printf("View is null!\n");
3431 fprintf(fd
, "--------------- All Views ----------------\n");
3432 DumpViews(aDocShell
, fd
);
3433 fprintf(fd
, "---------------------------------------\n\n");
3435 if (aFD
== nsnull
) {
3441 //-------------------------------------------------------------
3442 static void DumpPrintObjectsList(nsVoidArray
* aDocList
)
3444 if (!kPrintingLogMod
|| kPrintingLogMod
->level
!= DUMP_LAYOUT_LEVEL
) return;
3446 NS_ASSERTION(aDocList
, "Pointer is null!");
3448 const char types
[][3] = {"DC", "FR", "IF", "FS"};
3449 PR_PL(("Doc List\n***************************************************\n"));
3450 PR_PL(("T P A H PO DocShell Seq Page Root Page# Rect\n"));
3451 PRInt32 cnt
= aDocList
->Count();
3452 for (PRInt32 i
=0;i
<cnt
;i
++) {
3453 nsPrintObject
* po
= (nsPrintObject
*)aDocList
->ElementAt(i
);
3454 NS_ASSERTION(po
, "nsPrintObject can't be null!");
3455 nsIFrame
* rootFrame
= nsnull
;
3456 if (po
->mPresShell
) {
3457 rootFrame
= po
->mPresShell
->FrameManager()->GetRootFrame();
3458 while (rootFrame
!= nsnull
) {
3459 nsIPageSequenceFrame
* sqf
= nsnull
;
3460 if (NS_SUCCEEDED(CallQueryInterface(rootFrame
, &sqf
))) {
3463 rootFrame
= rootFrame
->GetFirstChild(nsnull
);
3467 PR_PL(("%s %d %d %d %p %p %p %p %p %d %d,%d,%d,%d\n", types
[po
->mFrameType
],
3468 po
->IsPrintable(), po
->mPrintAsIs
, po
->mHasBeenPrinted
, po
, po
->mDocShell
.get(), po
->mSeqFrame
,
3469 po
->mPageFrame
, rootFrame
, po
->mPageNum
, po
->mRect
.x
, po
->mRect
.y
, po
->mRect
.width
, po
->mRect
.height
));
3473 //-------------------------------------------------------------
3474 static void DumpPrintObjectsTree(nsPrintObject
* aPO
, int aLevel
, FILE* aFD
)
3476 if (!kPrintingLogMod
|| kPrintingLogMod
->level
!= DUMP_LAYOUT_LEVEL
) return;
3478 NS_ASSERTION(aPO
, "Pointer is null!");
3480 FILE * fd
= aFD
?aFD
:stdout
;
3481 const char types
[][3] = {"DC", "FR", "IF", "FS"};
3483 fprintf(fd
, "DocTree\n***************************************************\n");
3484 fprintf(fd
, "T PO DocShell Seq Page Page# Rect\n");
3486 PRInt32 cnt
= aPO
->mKids
.Count();
3487 for (PRInt32 i
=0;i
<cnt
;i
++) {
3488 nsPrintObject
* po
= (nsPrintObject
*)aPO
->mKids
.ElementAt(i
);
3489 NS_ASSERTION(po
, "nsPrintObject can't be null!");
3490 for (PRInt32 k
=0;k
<aLevel
;k
++) fprintf(fd
, " ");
3491 fprintf(fd
, "%s %p %p %p %p %d %d,%d,%d,%d\n", types
[po
->mFrameType
], po
, po
->mDocShell
.get(), po
->mSeqFrame
,
3492 po
->mPageFrame
, po
->mPageNum
, po
->mRect
.x
, po
->mRect
.y
, po
->mRect
.width
, po
->mRect
.height
);
3496 //-------------------------------------------------------------
3497 static void GetDocTitleAndURL(nsPrintObject
* aPO
, char *& aDocStr
, char *& aURLStr
)
3502 PRUnichar
* docTitleStr
;
3503 PRUnichar
* docURLStr
;
3504 nsPrintEngine::GetDisplayTitleAndURL(aPO
,
3505 &docTitleStr
, &docURLStr
,
3506 nsPrintEngine::eDocTitleDefURLDoc
);
3509 nsAutoString
strDocTitle(docTitleStr
);
3510 aDocStr
= ToNewCString(strDocTitle
);
3511 nsMemory::Free(docTitleStr
);
3515 nsAutoString
strURL(docURLStr
);
3516 aURLStr
= ToNewCString(strURL
);
3517 nsMemory::Free(docURLStr
);
3521 //-------------------------------------------------------------
3522 static void DumpPrintObjectsTreeLayout(nsPrintObject
* aPO
,
3523 nsIDeviceContext
* aDC
,
3524 int aLevel
, FILE * aFD
)
3526 if (!kPrintingLogMod
|| kPrintingLogMod
->level
!= DUMP_LAYOUT_LEVEL
) return;
3528 NS_ASSERTION(aPO
, "Pointer is null!");
3529 NS_ASSERTION(aDC
, "Pointer is null!");
3531 const char types
[][3] = {"DC", "FR", "IF", "FS"};
3534 fd
= fopen("tree_layout.txt", "w");
3535 fprintf(fd
, "DocTree\n***************************************************\n");
3536 fprintf(fd
, "***************************************************\n");
3537 fprintf(fd
, "T PO DocShell Seq Page Page# Rect\n");
3542 nsIFrame
* rootFrame
= nsnull
;
3543 if (aPO
->mPresShell
) {
3544 rootFrame
= aPO
->mPresShell
->FrameManager()->GetRootFrame();
3546 for (PRInt32 k
=0;k
<aLevel
;k
++) fprintf(fd
, " ");
3547 fprintf(fd
, "%s %p %p %p %p %d %d,%d,%d,%d\n", types
[aPO
->mFrameType
], aPO
, aPO
->mDocShell
.get(), aPO
->mSeqFrame
,
3548 aPO
->mPageFrame
, aPO
->mPageNum
, aPO
->mRect
.x
, aPO
->mRect
.y
, aPO
->mRect
.width
, aPO
->mRect
.height
);
3549 if (aPO
->IsPrintable()) {
3552 GetDocTitleAndURL(aPO
, docStr
, urlStr
);
3553 DumpLayoutData(docStr
, urlStr
, aPO
->mPresContext
, aDC
, rootFrame
, aPO
->mDocShell
, fd
);
3554 if (docStr
) nsMemory::Free(docStr
);
3555 if (urlStr
) nsMemory::Free(urlStr
);
3557 fprintf(fd
, "<***************************************************>\n");
3559 PRInt32 cnt
= aPO
->mKids
.Count();
3560 for (PRInt32 i
=0;i
<cnt
;i
++) {
3561 nsPrintObject
* po
= (nsPrintObject
*)aPO
->mKids
.ElementAt(i
);
3562 NS_ASSERTION(po
, "nsPrintObject can't be null!");
3563 DumpPrintObjectsTreeLayout(po
, aDC
, aLevel
+1, fd
);
3566 if (aLevel
== 0 && fd
) {
3571 //-------------------------------------------------------------
3572 static void DumpPrintObjectsListStart(const char * aStr
, nsVoidArray
* aDocList
)
3574 if (!kPrintingLogMod
|| kPrintingLogMod
->level
!= DUMP_LAYOUT_LEVEL
) return;
3576 NS_ASSERTION(aStr
, "Pointer is null!");
3577 NS_ASSERTION(aDocList
, "Pointer is null!");
3579 PR_PL(("%s\n", aStr
));
3580 DumpPrintObjectsList(aDocList
);
3583 #define DUMP_DOC_LIST(_title) DumpPrintObjectsListStart((_title), mPrt->mPrintDocList);
3584 #define DUMP_DOC_TREE DumpPrintObjectsTree(mPrt->mPrintObject);
3585 #define DUMP_DOC_TREELAYOUT DumpPrintObjectsTreeLayout(mPrt->mPrintObject, mPrt->mPrintDC);
3588 #define DUMP_DOC_LIST(_title)
3589 #define DUMP_DOC_TREE
3590 #define DUMP_DOC_TREELAYOUT
3593 //---------------------------------------------------------------
3594 //---------------------------------------------------------------
3595 //-- End of debug helper routines
3596 //---------------------------------------------------------------