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 "nsIDOMNSDocument.h"
116 #include "nsIDOMNSHTMLDocument.h"
117 #include "nsIDOMHTMLCollection.h"
118 #include "nsIDOMHTMLElement.h"
119 #include "nsIDOMRange.h"
120 #include "nsContentCID.h"
121 #include "nsLayoutCID.h"
122 #include "nsContentUtils.h"
123 #include "nsIPresShell.h"
124 #include "nsLayoutUtils.h"
126 #include "nsViewsCID.h"
127 #include "nsWidgetsCID.h"
128 #include "nsIDeviceContext.h"
129 #include "nsIDeviceContextSpec.h"
130 #include "nsIViewManager.h"
133 #include "nsIPageSequenceFrame.h"
135 #include "nsIContentViewerEdit.h"
136 #include "nsIContentViewerFile.h"
137 #include "nsIMarkupDocumentViewer.h"
138 #include "nsIInterfaceRequestor.h"
139 #include "nsIInterfaceRequestorUtils.h"
140 #include "nsIDocShellTreeItem.h"
141 #include "nsIDocShellTreeNode.h"
142 #include "nsIDocShellTreeOwner.h"
143 #include "nsIWebBrowserChrome.h"
144 #include "nsIDocShell.h"
145 #include "nsIBaseWindow.h"
146 #include "nsIFrameDebug.h"
147 #include "nsILayoutHistoryState.h"
148 #include "nsFrameManager.h"
149 #include "nsIParser.h"
150 #include "nsGUIEvent.h"
151 #include "nsHTMLReflowState.h"
152 #include "nsIDOMHTMLAnchorElement.h"
153 #include "nsIDOMHTMLAreaElement.h"
154 #include "nsIDOMHTMLLinkElement.h"
155 #include "nsIDOMHTMLImageElement.h"
156 #include "nsIContentViewerContainer.h"
157 #include "nsIContentViewer.h"
158 #include "nsIDocumentViewerPrint.h"
160 #include "nsPIDOMWindow.h"
161 #include "nsIFocusController.h"
163 #include "nsCDefaultURIFixup.h"
164 #include "nsIURIFixup.h"
166 //-----------------------------------------------------
169 #define FORCE_PR_LOG /* Allow logging in the release build */
177 // PR_LOGGING is force to always be on (even in release builds)
178 // but we only want some of it on,
179 //#define EXTENDED_DEBUG_PRINTING
182 #define DUMP_LAYOUT_LEVEL 9 // this turns on the dumping of each doucment's layout info
184 static PRLogModuleInfo
* kPrintingLogMod
= PR_NewLogModule("printing");
185 #define PR_PL(_p1) PR_LOG(kPrintingLogMod, PR_LOG_DEBUG, _p1);
187 #ifdef EXTENDED_DEBUG_PRINTING
188 static PRUint32 gDumpFileNameCnt
= 0;
189 static PRUint32 gDumpLOFileNameCnt
= 0;
192 #define PRT_YESNO(_p) ((_p)?"YES":"NO")
193 static const char * gFrameTypesStr
[] = {"eDoc", "eFrame", "eIFrame", "eFrameSet"};
194 static const char * gPrintFrameTypeStr
[] = {"kNoFrames", "kFramesAsIs", "kSelectedFrame", "kEachFrameSep"};
195 static const char * gFrameHowToEnableStr
[] = {"kFrameEnableNone", "kFrameEnableAll", "kFrameEnableAsIsAndEach"};
196 static const char * gPrintRangeStr
[] = {"kRangeAllPages", "kRangeSpecifiedPageRange", "kRangeSelection", "kRangeFocusFrame"};
198 #define PRT_YESNO(_p)
202 #ifdef EXTENDED_DEBUG_PRINTING
203 // Forward Declarations
204 static void DumpPrintObjectsListStart(const char * aStr
, nsVoidArray
* aDocList
);
205 static void DumpPrintObjectsTree(nsPrintObject
* aPO
, int aLevel
= 0, FILE* aFD
= nsnull
);
206 static void DumpPrintObjectsTreeLayout(nsPrintObject
* aPO
,nsIDeviceContext
* aDC
, int aLevel
= 0, FILE * aFD
= nsnull
);
208 #define DUMP_DOC_LIST(_title) DumpPrintObjectsListStart((_title), mPrt->mPrintDocList);
209 #define DUMP_DOC_TREE DumpPrintObjectsTree(mPrt->mPrintObject);
210 #define DUMP_DOC_TREELAYOUT DumpPrintObjectsTreeLayout(mPrt->mPrintObject, mPrt->mPrintDC);
212 #define DUMP_DOC_LIST(_title)
213 #define DUMP_DOC_TREE
214 #define DUMP_DOC_TREELAYOUT
219 static NS_DEFINE_CID(kViewManagerCID
, NS_VIEW_MANAGER_CID
);
220 static NS_DEFINE_CID(kWidgetCID
, NS_CHILD_CID
);
222 NS_IMPL_ISUPPORTS1(nsPrintEngine
, nsIObserver
)
224 //---------------------------------------------------
225 //-- nsPrintEngine Class Impl
226 //---------------------------------------------------
227 nsPrintEngine::nsPrintEngine() :
228 mIsCreatingPrintPreview(PR_FALSE
),
229 mIsDoingPrinting(PR_FALSE
),
230 mIsDoingPrintPreview(PR_FALSE
),
231 mProgressDialogIsShown(PR_FALSE
),
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
;
271 mDocViewerPrint
= 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
;
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 nsAutoString docTitle
;
1157 nsCOMPtr
<nsIDOMNSDocument
> doc
= do_QueryInterface(aDoc
);
1158 doc
->GetTitle(docTitle
);
1159 if (!docTitle
.IsEmpty()) {
1160 *aTitle
= ToNewUnicode(docTitle
);
1163 nsIURI
* url
= aDoc
->GetDocumentURI();
1166 nsCOMPtr
<nsIURIFixup
> urifixup(do_GetService(NS_URIFIXUP_CONTRACTID
));
1167 if (!urifixup
) return;
1169 nsCOMPtr
<nsIURI
> exposableURI
;
1170 urifixup
->CreateExposableURI(url
, getter_AddRefs(exposableURI
));
1172 if (!exposableURI
) return;
1174 nsCAutoString urlCStr
;
1175 exposableURI
->GetSpec(urlCStr
);
1176 *aURLStr
= UTF8ToNewUnicode(urlCStr
);
1179 //---------------------------------------------------------------------
1180 // The walks the PO tree and for each document it walks the content
1181 // tree looking for any content that are sub-shells
1183 // It then sets the mContent pointer in the "found" PO object back to the
1184 // the document that contained it.
1186 nsPrintEngine::MapContentToWebShells(nsPrintObject
* aRootPO
,
1189 NS_ASSERTION(aRootPO
, "Pointer is null!");
1190 NS_ASSERTION(aPO
, "Pointer is null!");
1192 // Recursively walk the content from the root item
1193 // XXX Would be faster to enumerate the subdocuments, although right now
1194 // nsIDocument doesn't expose quite what would be needed.
1195 nsIContent
*rootContent
= aPO
->mDocument
->GetRootContent();
1197 MapContentForPO(aPO
, rootContent
);
1199 NS_WARNING("Null root content on (sub)document.");
1202 // Continue recursively walking the chilren of this PO
1203 for (PRInt32 i
=0;i
<aPO
->mKids
.Count();i
++) {
1204 MapContentToWebShells(aRootPO
, (nsPrintObject
*)aPO
->mKids
[i
]);
1209 //-------------------------------------------------------
1210 // A Frame's sub-doc may contain content or a FrameSet
1211 // When it contains a FrameSet the mFrameType for the PrintObject
1212 // is always set to an eFrame. Which is fine when printing "AsIs"
1213 // but is incorrect when when printing "Each Frame Separately".
1214 // When printing "Each Frame Separately" the Frame really acts like
1217 // This method walks the PO tree and checks to see if the PrintObject is
1218 // an eFrame and has children that are eFrames (meaning it's a Frame containing a FrameSet)
1219 // If so, then the mFrameType need to be changed to eFrameSet
1221 // Also note: We only want to call this we are printing "Each Frame Separately"
1222 // when printing "As Is" leave it as an eFrame
1224 nsPrintEngine::CheckForChildFrameSets(nsPrintObject
* aPO
)
1226 NS_ASSERTION(aPO
, "Pointer is null!");
1228 // Continue recursively walking the chilren of this PO
1229 PRBool hasChildFrames
= PR_FALSE
;
1230 for (PRInt32 i
=0;i
<aPO
->mKids
.Count();i
++) {
1231 nsPrintObject
* po
= (nsPrintObject
*)aPO
->mKids
[i
];
1232 if (po
->mFrameType
== eFrame
) {
1233 hasChildFrames
= PR_TRUE
;
1234 CheckForChildFrameSets(po
);
1238 if (hasChildFrames
&& aPO
->mFrameType
== eFrame
) {
1239 aPO
->mFrameType
= eFrameSet
;
1243 //---------------------------------------------------------------------
1244 // This method is key to the entire print mechanism.
1246 // This "maps" or figures out which sub-doc represents a
1247 // given Frame or IFrame in its parent sub-doc.
1249 // So the Mcontent pointer in the child sub-doc points to the
1250 // content in the its parent document, that caused it to be printed.
1251 // This is used later to (after reflow) to find the absolute location
1252 // of the sub-doc on its parent's page frame so it can be
1253 // printed in the correct location.
1255 // This method recursvely "walks" the content for a document finding
1256 // all the Frames and IFrames, then sets the "mFrameType" data member
1257 // which tells us what type of PO we have
1259 nsPrintEngine::MapContentForPO(nsPrintObject
* aPO
,
1260 nsIContent
* aContent
)
1262 NS_PRECONDITION(aPO
&& aContent
, "Null argument");
1264 nsIDocument
* doc
= aContent
->GetDocument();
1266 NS_ASSERTION(doc
, "Content without a document from a document tree?");
1268 nsIDocument
* subDoc
= doc
->GetSubDocumentFor(aContent
);
1271 nsCOMPtr
<nsISupports
> container
= subDoc
->GetContainer();
1272 nsCOMPtr
<nsIDocShell
> docShell(do_QueryInterface(container
));
1275 nsPrintObject
* po
= nsnull
;
1276 PRInt32 cnt
= aPO
->mKids
.Count();
1277 for (PRInt32 i
=0;i
<cnt
;i
++) {
1278 nsPrintObject
* kid
= (nsPrintObject
*)aPO
->mKids
.ElementAt(i
);
1279 if (kid
->mDocument
== subDoc
) {
1285 // XXX If a subdocument has no onscreen presentation, there will be no PO
1286 // This is even if there should be a print presentation
1288 po
->mContent
= aContent
;
1290 nsCOMPtr
<nsIDOMHTMLFrameElement
> frame(do_QueryInterface(aContent
));
1291 // "frame" elements not in a frameset context should be treated
1293 if (frame
&& po
->mParent
->mFrameType
== eFrameSet
) {
1294 po
->mFrameType
= eFrame
;
1296 // Assume something iframe-like, i.e. iframe, object, or embed
1297 po
->mFrameType
= eIFrame
;
1298 SetPrintAsIs(po
, PR_TRUE
);
1299 NS_ASSERTION(po
->mParent
, "The root must be a parent");
1300 po
->mParent
->mPrintAsIs
= PR_TRUE
;
1306 // walk children content
1307 PRUint32 count
= aContent
->GetChildCount();
1308 for (PRUint32 i
= 0; i
< count
; ++i
) {
1309 nsIContent
*child
= aContent
->GetChildAt(i
);
1310 MapContentForPO(aPO
, child
);
1314 //---------------------------------------------------------------------
1316 nsPrintEngine::IsThereAnIFrameSelected(nsIDocShell
* aDocShell
,
1317 nsIDOMWindow
* aDOMWin
,
1318 PRPackedBool
& aIsParentFrameSet
)
1320 aIsParentFrameSet
= IsParentAFrameSet(aDocShell
);
1321 PRBool iFrameIsSelected
= PR_FALSE
;
1322 if (mPrt
&& mPrt
->mPrintObject
) {
1323 nsPrintObject
* po
= FindPrintObjectByDOMWin(mPrt
->mPrintObject
, aDOMWin
);
1324 iFrameIsSelected
= po
&& po
->mFrameType
== eIFrame
;
1326 // First, check to see if we are a frameset
1327 if (!aIsParentFrameSet
) {
1328 // Check to see if there is a currenlt focused frame
1329 // if so, it means the selected frame is either the main docshell
1332 // Get the main docshell's DOMWin to see if it matches
1333 // the frame that is selected
1334 nsCOMPtr
<nsIDOMWindow
> domWin
= do_GetInterface(aDocShell
);
1335 if (domWin
!= aDOMWin
) {
1336 iFrameIsSelected
= PR_TRUE
; // we have a selected IFRAME
1342 return iFrameIsSelected
;
1345 //---------------------------------------------------------------------
1346 // Recursively sets all the PO items to be printed
1347 // from the given item down into the tree
1349 nsPrintEngine::SetPrintPO(nsPrintObject
* aPO
, PRBool aPrint
)
1351 NS_ASSERTION(aPO
, "Pointer is null!");
1353 // Set whether to print flag
1354 aPO
->mDontPrint
= !aPrint
;
1356 for (PRInt32 i
=0;i
<aPO
->mKids
.Count();i
++) {
1357 SetPrintPO((nsPrintObject
*)aPO
->mKids
[i
], aPrint
);
1361 //---------------------------------------------------------------------
1362 // This will first use a Title and/or URL from the PrintSettings
1363 // if one isn't set then it uses the one from the document
1364 // then if not title is there we will make sure we send something back
1365 // depending on the situation.
1367 nsPrintEngine::GetDisplayTitleAndURL(nsPrintObject
* aPO
,
1369 PRUnichar
** aURLStr
,
1370 eDocTitleDefault aDefType
)
1372 NS_ASSERTION(aPO
, "Pointer is null!");
1373 NS_ASSERTION(aTitle
, "Pointer is null!");
1374 NS_ASSERTION(aURLStr
, "Pointer is null!");
1382 // First check to see if the PrintSettings has defined an alternate title
1383 // and use that if it did
1384 PRUnichar
* docTitleStrPS
= nsnull
;
1385 PRUnichar
* docURLStrPS
= nsnull
;
1386 if (mPrt
->mPrintSettings
) {
1387 mPrt
->mPrintSettings
->GetTitle(&docTitleStrPS
);
1388 mPrt
->mPrintSettings
->GetDocURL(&docURLStrPS
);
1390 if (docTitleStrPS
&& *docTitleStrPS
) {
1391 *aTitle
= docTitleStrPS
;
1394 if (docURLStrPS
&& *docURLStrPS
) {
1395 *aURLStr
= docURLStrPS
;
1399 if (docTitleStrPS
&& docURLStrPS
) {
1404 PRUnichar
* docTitle
;
1406 GetDocumentTitleAndURL(aPO
->mDocument
, &docTitle
, &docUrl
);
1412 nsMemory::Free(docUrl
);
1419 nsMemory::Free(docTitle
);
1420 } else if (!docTitleStrPS
) {
1422 case eDocTitleDefBlank
: *aTitle
= ToNewUnicode(EmptyString());
1425 case eDocTitleDefURLDoc
:
1427 *aTitle
= NS_strdup(*aURLStr
);
1428 } else if (mPrt
->mBrandName
) {
1429 *aTitle
= NS_strdup(mPrt
->mBrandName
);
1432 case eDocTitleDefNone
:
1433 // *aTitle defaults to nsnull
1439 //---------------------------------------------------------------------
1440 nsresult
nsPrintEngine::DocumentReadyForPrinting()
1442 if (mPrt
->mPrintFrameType
== nsIPrintSettings::kEachFrameSep
) {
1443 CheckForChildFrameSets(mPrt
->mPrintObject
);
1447 // Send the document to the printer...
1449 nsresult rv
= SetupToPrintContent();
1450 if (NS_FAILED(rv
)) {
1451 // The print job was canceled or there was a problem
1452 // So remove all other documents from the print list
1453 DonePrintingPages(nsnull
, rv
);
1458 /** ---------------------------------------------------
1459 * Cleans up when an error occurred
1461 nsresult
nsPrintEngine::CleanupOnFailure(nsresult aResult
, PRBool aIsPrinting
)
1463 PR_PL(("**** Failed %s - rv 0x%X", aIsPrinting
?"Printing":"Print Preview", aResult
));
1466 if (mPagePrintTimer
) {
1467 mPagePrintTimer
->Stop();
1468 NS_RELEASE(mPagePrintTimer
);
1472 SetIsPrinting(PR_FALSE
);
1474 SetIsPrintPreview(PR_FALSE
);
1475 SetIsCreatingPrintPreview(PR_FALSE
);
1478 /* cleanup done, let's fire-up an error dialog to notify the user
1479 * what went wrong...
1481 * When rv == NS_ERROR_ABORT, it means we want out of the
1482 * print job without displaying any error messages
1484 if (aResult
!= NS_ERROR_ABORT
) {
1485 ShowPrintErrorDialog(aResult
, aIsPrinting
);
1488 FirePrintCompletionEvent();
1494 //---------------------------------------------------------------------
1496 nsPrintEngine::ShowPrintErrorDialog(nsresult aPrintError
, PRBool aIsPrinting
)
1499 PR_PL(("nsPrintEngine::ShowPrintErrorDialog(nsresult aPrintError=%lx, PRBool aIsPrinting=%d)\n", (long)aPrintError
, (int)aIsPrinting
));
1501 nsCAutoString stringName
;
1505 #define NS_ERROR_TO_LOCALIZED_PRINT_ERROR_MSG(nserr) case nserr: stringName.AssignLiteral(#nserr); break;
1506 NS_ERROR_TO_LOCALIZED_PRINT_ERROR_MSG(NS_ERROR_GFX_PRINTER_CMD_NOT_FOUND
)
1507 NS_ERROR_TO_LOCALIZED_PRINT_ERROR_MSG(NS_ERROR_GFX_PRINTER_CMD_FAILURE
)
1508 NS_ERROR_TO_LOCALIZED_PRINT_ERROR_MSG(NS_ERROR_GFX_PRINTER_NO_PRINTER_AVAILABLE
)
1509 NS_ERROR_TO_LOCALIZED_PRINT_ERROR_MSG(NS_ERROR_GFX_PRINTER_NAME_NOT_FOUND
)
1510 NS_ERROR_TO_LOCALIZED_PRINT_ERROR_MSG(NS_ERROR_GFX_PRINTER_ACCESS_DENIED
)
1511 NS_ERROR_TO_LOCALIZED_PRINT_ERROR_MSG(NS_ERROR_GFX_PRINTER_INVALID_ATTRIBUTE
)
1512 NS_ERROR_TO_LOCALIZED_PRINT_ERROR_MSG(NS_ERROR_GFX_PRINTER_PRINTER_NOT_READY
)
1513 NS_ERROR_TO_LOCALIZED_PRINT_ERROR_MSG(NS_ERROR_GFX_PRINTER_OUT_OF_PAPER
)
1514 NS_ERROR_TO_LOCALIZED_PRINT_ERROR_MSG(NS_ERROR_GFX_PRINTER_PRINTER_IO_ERROR
)
1515 NS_ERROR_TO_LOCALIZED_PRINT_ERROR_MSG(NS_ERROR_GFX_PRINTER_COULD_NOT_OPEN_FILE
)
1516 NS_ERROR_TO_LOCALIZED_PRINT_ERROR_MSG(NS_ERROR_GFX_PRINTER_FILE_IO_ERROR
)
1517 NS_ERROR_TO_LOCALIZED_PRINT_ERROR_MSG(NS_ERROR_GFX_PRINTER_PRINTPREVIEW
)
1518 NS_ERROR_TO_LOCALIZED_PRINT_ERROR_MSG(NS_ERROR_UNEXPECTED
)
1519 NS_ERROR_TO_LOCALIZED_PRINT_ERROR_MSG(NS_ERROR_OUT_OF_MEMORY
)
1520 NS_ERROR_TO_LOCALIZED_PRINT_ERROR_MSG(NS_ERROR_NOT_IMPLEMENTED
)
1521 NS_ERROR_TO_LOCALIZED_PRINT_ERROR_MSG(NS_ERROR_NOT_AVAILABLE
)
1522 NS_ERROR_TO_LOCALIZED_PRINT_ERROR_MSG(NS_ERROR_ABORT
)
1523 NS_ERROR_TO_LOCALIZED_PRINT_ERROR_MSG(NS_ERROR_GFX_PRINTER_STARTDOC
)
1524 NS_ERROR_TO_LOCALIZED_PRINT_ERROR_MSG(NS_ERROR_GFX_PRINTER_ENDDOC
)
1525 NS_ERROR_TO_LOCALIZED_PRINT_ERROR_MSG(NS_ERROR_GFX_PRINTER_STARTPAGE
)
1526 NS_ERROR_TO_LOCALIZED_PRINT_ERROR_MSG(NS_ERROR_GFX_PRINTER_ENDPAGE
)
1527 NS_ERROR_TO_LOCALIZED_PRINT_ERROR_MSG(NS_ERROR_GFX_PRINTER_PRINT_WHILE_PREVIEW
)
1528 NS_ERROR_TO_LOCALIZED_PRINT_ERROR_MSG(NS_ERROR_GFX_PRINTER_PAPER_SIZE_NOT_SUPPORTED
)
1529 NS_ERROR_TO_LOCALIZED_PRINT_ERROR_MSG(NS_ERROR_GFX_PRINTER_ORIENTATION_NOT_SUPPORTED
)
1530 NS_ERROR_TO_LOCALIZED_PRINT_ERROR_MSG(NS_ERROR_GFX_PRINTER_COLORSPACE_NOT_SUPPORTED
)
1531 NS_ERROR_TO_LOCALIZED_PRINT_ERROR_MSG(NS_ERROR_GFX_PRINTER_TOO_MANY_COPIES
)
1532 NS_ERROR_TO_LOCALIZED_PRINT_ERROR_MSG(NS_ERROR_GFX_PRINTER_DRIVER_CONFIGURATION_ERROR
)
1533 NS_ERROR_TO_LOCALIZED_PRINT_ERROR_MSG(NS_ERROR_GFX_PRINTER_DOC_IS_BUSY_PP
)
1534 NS_ERROR_TO_LOCALIZED_PRINT_ERROR_MSG(NS_ERROR_GFX_PRINTER_DOC_WAS_DESTORYED
)
1535 NS_ERROR_TO_LOCALIZED_PRINT_ERROR_MSG(NS_ERROR_GFX_NO_PRINTDIALOG_IN_TOOLKIT
)
1536 NS_ERROR_TO_LOCALIZED_PRINT_ERROR_MSG(NS_ERROR_GFX_NO_PRINTROMPTSERVICE
)
1537 NS_ERROR_TO_LOCALIZED_PRINT_ERROR_MSG(NS_ERROR_GFX_PRINTER_NO_XUL
) // Temporary code for Bug 136185 / bug 240490
1538 NS_ERROR_TO_LOCALIZED_PRINT_ERROR_MSG(NS_ERROR_GFX_PRINTER_PLEX_NOT_SUPPORTED
)
1539 NS_ERROR_TO_LOCALIZED_PRINT_ERROR_MSG(NS_ERROR_GFX_PRINTER_DOC_IS_BUSY
)
1540 NS_ERROR_TO_LOCALIZED_PRINT_ERROR_MSG(NS_ERROR_GFX_PRINTING_NOT_IMPLEMENTED
)
1541 NS_ERROR_TO_LOCALIZED_PRINT_ERROR_MSG(NS_ERROR_GFX_COULD_NOT_LOAD_PRINT_MODULE
)
1542 NS_ERROR_TO_LOCALIZED_PRINT_ERROR_MSG(NS_ERROR_GFX_PRINTER_RESOLUTION_NOT_SUPPORTED
)
1545 NS_ERROR_TO_LOCALIZED_PRINT_ERROR_MSG(NS_ERROR_FAILURE
)
1546 #undef NS_ERROR_TO_LOCALIZED_PRINT_ERROR_MSG
1549 PR_PL(("ShowPrintErrorDialog: stringName='%s'\n", stringName
.get()));
1551 nsXPIDLString msg
, title
;
1553 nsContentUtils::GetLocalizedString(nsContentUtils::ePRINTING_PROPERTIES
,
1554 stringName
.get(), msg
);
1555 if (NS_FAILED(rv
)) {
1556 PR_PL(("GetLocalizedString failed\n"));
1560 rv
= nsContentUtils::GetLocalizedString(nsContentUtils::ePRINTING_PROPERTIES
,
1561 aIsPrinting
? "print_error_dialog_title"
1562 : "printpreview_error_dialog_title",
1565 nsCOMPtr
<nsIWindowWatcher
> wwatch
= do_GetService(NS_WINDOWWATCHER_CONTRACTID
, &rv
);
1566 if (NS_FAILED(rv
)) {
1567 PR_PL(("ShowPrintErrorDialog(): wwatch==nsnull\n"));
1571 nsCOMPtr
<nsIDOMWindow
> active
;
1572 wwatch
->GetActiveWindow(getter_AddRefs(active
));
1574 nsCOMPtr
<nsIPrompt
> dialog
;
1575 /* |GetNewPrompter| allows that |active| is |nsnull|
1576 * (see bug 234982 ("nsPrintEngine::ShowPrintErrorDialog() fails in many cases")) */
1577 wwatch
->GetNewPrompter(active
, getter_AddRefs(dialog
));
1579 PR_PL(("ShowPrintErrorDialog(): dialog==nsnull\n"));
1583 dialog
->Alert(title
.get(), msg
.get());
1584 PR_PL(("ShowPrintErrorDialog(): alert displayed successfully.\n"));
1587 //-----------------------------------------------------------------
1588 //-- Section: Reflow Methods
1589 //-----------------------------------------------------------------
1591 //-------------------------------------------------------
1593 nsPrintEngine::SetupToPrintContent()
1595 // In this step we figure out which documents should be printed
1596 // i.e. if we are printing the selection then only enable that nsPrintObject
1598 if (NS_FAILED(EnablePOsForPrinting())) {
1599 return NS_ERROR_FAILURE
;
1601 DUMP_DOC_LIST("\nAfter Enable------------------------------------------");
1603 // This is an Optimization
1604 // If we are in PP then we already know all the shrinkage information
1605 // so just transfer it to the PrintData and we will skip the extra shrinkage reflow
1607 // doSetPixelScale tells Reflow whether to set the shrinkage value into the DC
1608 // The first time we do not want to do this, the second time through we do
1609 PRBool doSetPixelScale
= PR_FALSE
;
1610 PRBool ppIsShrinkToFit
= mPrtPreview
&& mPrtPreview
->mShrinkToFit
;
1611 if (ppIsShrinkToFit
) {
1612 mPrt
->mShrinkRatio
= mPrtPreview
->mShrinkRatio
;
1613 doSetPixelScale
= PR_TRUE
;
1616 // Here we reflow all the PrintObjects
1617 nsresult rv
= ReflowDocList(mPrt
->mPrintObject
, doSetPixelScale
);
1618 if (NS_FAILED(rv
)) {
1619 return NS_ERROR_FAILURE
;
1622 // Here is where we do the extra reflow for shrinking the content
1623 // But skip this step if we are in PrintPreview
1624 if (mPrt
->mShrinkToFit
&& !ppIsShrinkToFit
) {
1625 // Now look for the PO that has the smallest percent for shrink to fit
1626 if (mPrt
->mPrintDocList
->Count() > 1 && mPrt
->mPrintObject
->mFrameType
== eFrameSet
) {
1627 nsPrintObject
* smallestPO
= FindSmallestSTF();
1628 NS_ASSERTION(smallestPO
, "There must always be an XMost PO!");
1630 // Calc the shrinkage based on the entire content area
1631 mPrt
->mShrinkRatio
= smallestPO
->mShrinkRatio
;
1634 // Single document so use the Shrink as calculated for the PO
1635 mPrt
->mShrinkRatio
= mPrt
->mPrintObject
->mShrinkRatio
;
1638 // Only Shrink if we are smaller
1639 if (mPrt
->mShrinkRatio
< 0.998f
) {
1640 // Clamp Shrink to Fit to 60%
1641 mPrt
->mShrinkRatio
= PR_MAX(mPrt
->mShrinkRatio
, 0.60f
);
1643 for (PRInt32 i
=0;i
<mPrt
->mPrintDocList
->Count();i
++) {
1644 nsPrintObject
* po
= (nsPrintObject
*)mPrt
->mPrintDocList
->ElementAt(i
);
1645 NS_ASSERTION(po
, "nsPrintObject can't be null!");
1646 // Wipe out the presentation before we reflow
1647 po
->DestroyPresentation();
1650 #if (defined(XP_WIN) || defined(XP_OS2)) && defined(EXTENDED_DEBUG_PRINTING)
1651 // We need to clear all the output files here
1652 // because they will be re-created with second reflow of the docs
1653 if (kPrintingLogMod
&& kPrintingLogMod
->level
== DUMP_LAYOUT_LEVEL
) {
1654 RemoveFilesInDir(".\\");
1655 gDumpFileNameCnt
= 0;
1656 gDumpLOFileNameCnt
= 0;
1660 // Here we reflow all the PrintObjects a second time
1661 // this time using the shrinkage values
1662 // The last param here tells reflow to NOT calc the shrinkage values
1663 if (NS_FAILED(ReflowDocList(mPrt
->mPrintObject
, PR_TRUE
))) {
1664 return NS_ERROR_FAILURE
;
1670 float calcRatio
= 0.0f
;
1671 if (mPrt
->mPrintDocList
->Count() > 1 && mPrt
->mPrintObject
->mFrameType
== eFrameSet
) {
1672 nsPrintObject
* smallestPO
= FindSmallestSTF();
1673 NS_ASSERTION(smallestPO
, "There must always be an XMost PO!");
1675 // Calc the shrinkage based on the entire content area
1676 calcRatio
= smallestPO
->mShrinkRatio
;
1679 // Single document so use the Shrink as calculated for the PO
1680 calcRatio
= mPrt
->mPrintObject
->mShrinkRatio
;
1682 PR_PL(("**************************************************************************\n"));
1683 PR_PL(("STF Ratio is: %8.5f Effective Ratio: %8.5f Diff: %8.5f\n", mPrt
->mShrinkRatio
, calcRatio
, mPrt
->mShrinkRatio
-calcRatio
));
1684 PR_PL(("**************************************************************************\n"));
1689 DUMP_DOC_LIST(("\nAfter Reflow------------------------------------------"));
1691 PR_PL(("-------------------------------------------------------\n"));
1694 CalcNumPrintablePages(mPrt
->mNumPrintablePages
);
1696 PR_PL(("--- Printing %d pages\n", mPrt
->mNumPrintablePages
));
1697 DUMP_DOC_TREELAYOUT
;
1699 // Print listener setup...
1700 if (mPrt
!= nsnull
) {
1701 mPrt
->OnStartPrinting();
1704 PRUnichar
* fileName
= nsnull
;
1705 // check to see if we are printing to a file
1706 PRBool isPrintToFile
= PR_FALSE
;
1707 mPrt
->mPrintSettings
->GetPrintToFile(&isPrintToFile
);
1708 if (isPrintToFile
) {
1709 // On some platforms The BeginDocument needs to know the name of the file
1710 // and it uses the PrintService to get it, so we need to set it into the PrintService here
1711 mPrt
->mPrintSettings
->GetToFileName(&fileName
);
1714 PRUnichar
* docTitleStr
;
1715 PRUnichar
* docURLStr
;
1716 GetDisplayTitleAndURL(mPrt
->mPrintObject
, &docTitleStr
, &docURLStr
, eDocTitleDefURLDoc
);
1718 PRInt32 startPage
= 1;
1719 PRInt32 endPage
= mPrt
->mNumPrintablePages
;
1721 PRInt16 printRangeType
= nsIPrintSettings::kRangeAllPages
;
1722 mPrt
->mPrintSettings
->GetPrintRange(&printRangeType
);
1723 if (printRangeType
== nsIPrintSettings::kRangeSpecifiedPageRange
) {
1724 mPrt
->mPrintSettings
->GetStartPageRange(&startPage
);
1725 mPrt
->mPrintSettings
->GetEndPageRange(&endPage
);
1726 if (endPage
> mPrt
->mNumPrintablePages
) {
1727 endPage
= mPrt
->mNumPrintablePages
;
1732 // BeginDocument may pass back a FAILURE code
1733 // i.e. On Windows, if you are printing to a file and hit "Cancel"
1734 // to the "File Name" dialog, this comes back as an error
1735 // Don't start printing when regression test are executed
1736 if (!mPrt
->mDebugFilePtr
&& mIsDoingPrinting
) {
1737 rv
= mPrt
->mPrintDC
->BeginDocument(docTitleStr
, fileName
, startPage
, endPage
);
1740 if (mIsCreatingPrintPreview
) {
1741 // Print Preview -- Pass ownership of docTitleStr and docURLStr
1742 // to the pageSequenceFrame, to be displayed in the header
1743 nsIPageSequenceFrame
*seqFrame
= nsnull
;
1744 mPrt
->mPrintObject
->mPresShell
->GetPageSequenceFrame(&seqFrame
);
1746 seqFrame
->StartPrint(mPrt
->mPrintObject
->mPresContext
,
1747 mPrt
->mPrintSettings
, docTitleStr
, docURLStr
);
1750 if (docTitleStr
) nsMemory::Free(docTitleStr
);
1751 if (docURLStr
) nsMemory::Free(docURLStr
);
1754 PR_PL(("****************** Begin Document ************************\n"));
1756 NS_ENSURE_SUCCESS(rv
, rv
);
1758 // This will print the docshell document
1759 // when it completes asynchronously in the DonePrintingPages method
1760 // it will check to see if there are more docshells to be printed and
1761 // then PrintDocContent will be called again.
1763 if (mIsDoingPrinting
) {
1764 PrintDocContent(mPrt
->mPrintObject
, rv
); // ignore return value
1770 //-------------------------------------------------------
1771 // Recursively reflow each sub-doc and then calc
1772 // all the frame locations of the sub-docs
1774 nsPrintEngine::ReflowDocList(nsPrintObject
* aPO
, PRBool aSetPixelScale
)
1776 NS_ENSURE_ARG_POINTER(aPO
);
1778 // Check to see if the subdocument's element has been hidden by the parent document
1779 if (aPO
->mParent
&& aPO
->mParent
->mPresShell
) {
1781 aPO
->mParent
->mPresShell
->GetPrimaryFrameFor(aPO
->mContent
);
1783 if (!frame
->GetStyleVisibility()->IsVisible()) {
1784 aPO
->mDontPrint
= PR_TRUE
;
1785 aPO
->mInvisible
= PR_TRUE
;
1791 // Here is where we set the shrinkage value into the DC
1792 // and this is what actually makes it shrink
1793 if (aSetPixelScale
&& aPO
->mFrameType
!= eIFrame
) {
1795 if (mPrt
->mPrintFrameType
== nsIPrintSettings::kFramesAsIs
|| mPrt
->mPrintFrameType
== nsIPrintSettings::kNoFrames
) {
1796 ratio
= mPrt
->mShrinkRatio
- 0.005f
; // round down
1798 ratio
= aPO
->mShrinkRatio
- 0.005f
; // round down
1800 aPO
->mZoomRatio
= ratio
;
1801 } else if (!mPrt
->mShrinkToFit
) {
1803 mPrt
->mPrintSettings
->GetScaling(&scaling
);
1804 aPO
->mZoomRatio
= float(scaling
);
1809 rv
= ReflowPrintObject(aPO
);
1810 NS_ENSURE_SUCCESS(rv
, rv
);
1812 PRInt32 cnt
= aPO
->mKids
.Count();
1813 for (PRInt32 i
=0;i
<cnt
;i
++) {
1814 rv
= ReflowDocList((nsPrintObject
*)aPO
->mKids
[i
], aSetPixelScale
);
1815 NS_ENSURE_SUCCESS(rv
, rv
);
1820 //-------------------------------------------------------
1821 // Reflow a nsPrintObject
1823 nsPrintEngine::ReflowPrintObject(nsPrintObject
* aPO
)
1825 NS_ASSERTION(aPO
, "Pointer is null!");
1826 if (!aPO
) return NS_ERROR_FAILURE
;
1829 PRBool documentIsTopLevel
;
1830 nsIFrame
* frame
= nsnull
;
1831 if (!aPO
->IsPrintable())
1834 if (aPO
->mParent
&& aPO
->mParent
->IsPrintable()) {
1835 if (aPO
->mParent
->mPresShell
) {
1836 frame
= aPO
->mParent
->mPresShell
->FrameManager()->
1837 GetPrimaryFrameFor(aPO
->mContent
, -1);
1839 // Without a frame, this document can't be displayed; therefore, there is no
1840 // point to reflowing it
1844 adjSize
= frame
->GetContentRect().Size();
1845 documentIsTopLevel
= PR_FALSE
;
1846 // presshell exists because parent is printable
1848 nscoord pageWidth
, pageHeight
;
1849 mPrt
->mPrintDC
->GetDeviceSurfaceDimensions(pageWidth
, pageHeight
);
1850 #if defined(XP_UNIX) && !defined(XP_MACOSX)
1851 // If we're in landscape mode on Linux, the device surface will have
1852 // been rotated, so for the purposes of reflowing content, we'll
1853 // treat device's height as our width and its width as our height,
1854 PRInt32 orientation
;
1855 mPrt
->mPrintSettings
->GetOrientation(&orientation
);
1856 if (nsIPrintSettings::kLandscapeOrientation
== orientation
) {
1857 adjSize
= nsSize(pageHeight
, pageWidth
);
1859 adjSize
= nsSize(pageWidth
, pageHeight
);
1862 adjSize
= nsSize(pageWidth
, pageHeight
);
1863 #endif // XP_UNIX && !XP_MACOSX
1864 documentIsTopLevel
= PR_TRUE
;
1867 // create the PresContext
1868 aPO
->mPresContext
= new nsPresContext(aPO
->mDocument
,
1869 mIsCreatingPrintPreview
?
1870 nsPresContext::eContext_PrintPreview
:
1871 nsPresContext::eContext_Print
);
1872 NS_ENSURE_TRUE(aPO
->mPresContext
, NS_ERROR_OUT_OF_MEMORY
);
1873 aPO
->mPresContext
->SetPrintSettings(mPrt
->mPrintSettings
);
1875 // set the presentation context to the value in the print settings
1876 PRBool printBGColors
;
1877 mPrt
->mPrintSettings
->GetPrintBGColors(&printBGColors
);
1878 aPO
->mPresContext
->SetBackgroundColorDraw(printBGColors
);
1879 mPrt
->mPrintSettings
->GetPrintBGImages(&printBGColors
);
1880 aPO
->mPresContext
->SetBackgroundImageDraw(printBGColors
);
1882 // init it with the DC
1883 nsresult rv
= aPO
->mPresContext
->Init(mPrt
->mPrintDC
);
1884 NS_ENSURE_SUCCESS(rv
, rv
);
1886 aPO
->mViewManager
= do_CreateInstance(kViewManagerCID
, &rv
);
1887 NS_ENSURE_SUCCESS(rv
,rv
);
1889 rv
= aPO
->mViewManager
->Init(mPrt
->mPrintDC
);
1890 NS_ENSURE_SUCCESS(rv
,rv
);
1892 nsStyleSet
* styleSet
;
1893 rv
= mDocViewerPrint
->CreateStyleSet(aPO
->mDocument
, &styleSet
);
1894 NS_ENSURE_SUCCESS(rv
, rv
);
1896 rv
= aPO
->mDocument
->CreateShell(aPO
->mPresContext
, aPO
->mViewManager
,
1897 styleSet
, getter_AddRefs(aPO
->mPresShell
));
1898 if (NS_FAILED(rv
)) {
1903 styleSet
->EndUpdate();
1905 // The pres shell now owns the style set object.
1907 PR_PL(("In DV::ReflowPrintObject PO: %p (%9s) Setting w,h to %d,%d\n", aPO
,
1908 gFrameTypesStr
[aPO
->mFrameType
], adjSize
.width
, adjSize
.height
));
1910 // Here we decide whether we need scrollbars and
1911 // what the parent will be of the widget
1912 // How this logic presently works: Print Preview is always as-is (as far
1913 // as I can tell; not sure how it would work in other cases); only the root
1914 // is not eIFrame or eFrame. The child documents get a parent widget from
1915 // logic in nsFrameFrame. In any case, a child widget is created for the root
1916 // view of the document.
1917 PRBool canCreateScrollbars
= PR_FALSE
;
1918 nsIView
* parentView
;
1919 // the top nsPrintObject's widget will always have scrollbars
1921 nsIView
* view
= frame
->GetView();
1922 NS_ENSURE_TRUE(view
, NS_ERROR_FAILURE
);
1923 view
= view
->GetFirstChild();
1924 NS_ENSURE_TRUE(view
, NS_ERROR_FAILURE
);
1927 canCreateScrollbars
= PR_TRUE
;
1928 parentView
= nsnull
;
1931 // Create a child window of the parent that is our "root view/window"
1932 nsRect tbounds
= nsRect(nsPoint(0, 0), adjSize
);
1933 nsIView
* rootView
= aPO
->mViewManager
->CreateView(tbounds
, parentView
);
1934 NS_ENSURE_TRUE(rootView
, NS_ERROR_OUT_OF_MEMORY
);
1936 // Only create a widget for print preview; when printing, a widget is
1937 // unnecessary and unexpected
1938 // Also, no widget should be needed except for the top-level document
1939 if (mIsCreatingPrintPreview
&& documentIsTopLevel
) {
1940 nsNativeWidget widget
= nsnull
;
1942 widget
= mParentWidget
->GetNativeData(NS_NATIVE_WIDGET
);
1943 rv
= rootView
->CreateWidget(kWidgetCID
, nsnull
,
1944 widget
, PR_TRUE
, PR_TRUE
,
1945 eContentTypeContent
);
1946 NS_ENSURE_SUCCESS(rv
, rv
);
1947 aPO
->mWindow
= rootView
->GetWidget();
1948 aPO
->mPresContext
->SetPaginatedScrolling(canCreateScrollbars
);
1951 // Setup hierarchical relationship in view manager
1952 aPO
->mViewManager
->SetRootView(rootView
);
1954 // This docshell stuff is weird; will go away when we stop having multiple
1955 // presentations per document
1956 nsCOMPtr
<nsISupports
> supps(do_QueryInterface(aPO
->mDocShell
));
1957 aPO
->mPresContext
->SetContainer(supps
);
1959 aPO
->mPresShell
->BeginObservingDocument();
1961 aPO
->mPresContext
->SetPageSize(adjSize
);
1962 aPO
->mPresContext
->SetIsRootPaginatedDocument(documentIsTopLevel
);
1963 aPO
->mPresContext
->SetPageScale(aPO
->mZoomRatio
);
1964 // Calculate scale factor from printer to screen
1965 float printDPI
= float(mPrt
->mPrintDC
->AppUnitsPerInch()) /
1966 float(mPrt
->mPrintDC
->AppUnitsPerDevPixel());
1967 float screenDPI
= float(mDeviceContext
->AppUnitsPerInch()) /
1968 float(mDeviceContext
->AppUnitsPerDevPixel());
1969 aPO
->mPresContext
->SetPrintPreviewScale(screenDPI
/ printDPI
);
1971 rv
= aPO
->mPresShell
->InitialReflow(adjSize
.width
, adjSize
.height
);
1973 NS_ENSURE_SUCCESS(rv
, rv
);
1974 NS_ASSERTION(aPO
->mPresShell
, "Presshell should still be here");
1976 // Process the reflow event InitialReflow posted
1977 aPO
->mPresShell
->FlushPendingNotifications(Flush_Layout
);
1979 nsCOMPtr
<nsIPresShell
> displayShell
;
1980 aPO
->mDocShell
->GetPresShell(getter_AddRefs(displayShell
));
1981 // Transfer Selection Ranges to the new Print PresShell
1982 nsCOMPtr
<nsISelection
> selection
, selectionPS
;
1983 // It's okay if there is no display shell, just skip copying the selection
1985 selection
= displayShell
->GetCurrentSelection(nsISelectionController::SELECTION_NORMAL
);
1987 selectionPS
= aPO
->mPresShell
->GetCurrentSelection(nsISelectionController::SELECTION_NORMAL
);
1988 if (selection
&& selectionPS
) {
1990 selection
->GetRangeCount(&cnt
);
1992 for (inx
=0;inx
<cnt
;inx
++) {
1993 nsCOMPtr
<nsIDOMRange
> range
;
1994 if (NS_SUCCEEDED(selection
->GetRangeAt(inx
, getter_AddRefs(range
))))
1995 selectionPS
->AddRange(range
);
1999 // If we are trying to shrink the contents to fit on the page
2000 // we must first locate the "pageContent" frame
2001 // Then we walk the frame tree and look for the "xmost" frame
2002 // this is the frame where the right-hand side of the frame extends
2004 if (mPrt
->mShrinkToFit
&& documentIsTopLevel
) {
2005 nsIPageSequenceFrame
* pageSequence
;
2006 aPO
->mPresShell
->GetPageSequenceFrame(&pageSequence
);
2007 pageSequence
->GetSTFPercent(aPO
->mShrinkRatio
);
2010 #ifdef EXTENDED_DEBUG_PRINTING
2011 if (kPrintingLogMod
&& kPrintingLogMod
->level
== DUMP_LAYOUT_LEVEL
) {
2014 GetDocTitleAndURL(aPO
, docStr
, urlStr
);
2016 sprintf(filename
, "print_dump_%d.txt", gDumpFileNameCnt
++);
2017 // Dump all the frames and view to a a file
2018 FILE * fd
= fopen(filename
, "w");
2020 nsIFrame
*theRootFrame
=
2021 aPO
->mPresShell
->FrameManager()->GetRootFrame();
2022 fprintf(fd
, "Title: %s\n", docStr
?docStr
:"");
2023 fprintf(fd
, "URL: %s\n", urlStr
?urlStr
:"");
2024 fprintf(fd
, "--------------- Frames ----------------\n");
2025 nsCOMPtr
<nsIRenderingContext
> renderingContext
;
2026 mPrt
->mPrintDocDC
->CreateRenderingContext(*getter_AddRefs(renderingContext
));
2027 RootFrameList(aPO
->mPresContext
, fd
, 0);
2028 //DumpFrames(fd, aPO->mPresContext, renderingContext, theRootFrame, 0);
2029 fprintf(fd
, "---------------------------------------\n\n");
2030 fprintf(fd
, "--------------- Views From Root Frame----------------\n");
2031 nsIView
* v
= theRootFrame
->GetView();
2035 printf("View is null!\n");
2038 fprintf(fd
, "--------------- All Views ----------------\n");
2039 DumpViews(docShell
, fd
);
2040 fprintf(fd
, "---------------------------------------\n\n");
2044 if (docStr
) nsMemory::Free(docStr
);
2045 if (urlStr
) nsMemory::Free(urlStr
);
2052 //-------------------------------------------------------
2053 // Figure out how many documents and how many total pages we are printing
2055 nsPrintEngine::CalcNumPrintablePages(PRInt32
& aNumPages
)
2058 // Count the number of printable documents
2059 // and printable pages
2061 for (i
=0; i
<mPrt
->mPrintDocList
->Count(); i
++) {
2062 nsPrintObject
* po
= (nsPrintObject
*)mPrt
->mPrintDocList
->ElementAt(i
);
2063 NS_ASSERTION(po
, "nsPrintObject can't be null!");
2064 if (po
->mPresContext
&& po
->mPresContext
->IsRootPaginatedDocument()) {
2065 nsIPageSequenceFrame
* pageSequence
;
2066 po
->mPresShell
->GetPageSequenceFrame(&pageSequence
);
2067 nsIFrame
* seqFrame
;
2068 if (NS_SUCCEEDED(CallQueryInterface(pageSequence
, &seqFrame
))) {
2069 nsIFrame
* frame
= seqFrame
->GetFirstChild(nsnull
);
2072 frame
= frame
->GetNextSibling();
2078 //-----------------------------------------------------------------
2079 //-- Done: Reflow Methods
2080 //-----------------------------------------------------------------
2082 //-----------------------------------------------------------------
2083 //-- Section: Printing Methods
2084 //-----------------------------------------------------------------
2086 //-------------------------------------------------------
2087 // Called for each DocShell that needs to be printed
2089 nsPrintEngine::PrintDocContent(nsPrintObject
* aPO
, nsresult
& aStatus
)
2091 NS_ASSERTION(aPO
, "Pointer is null!");
2094 if (!aPO
->mHasBeenPrinted
&& aPO
->IsPrintable()) {
2095 aStatus
= DoPrint(aPO
);
2099 // If |aPO->mPrintAsIs| and |aPO->mHasBeenPrinted| are true,
2100 // the kids frames are already processed in |PrintPage|.
2101 if (!aPO
->mInvisible
&& !(aPO
->mPrintAsIs
&& aPO
->mHasBeenPrinted
)) {
2102 for (PRInt32 i
=0;i
<aPO
->mKids
.Count();i
++) {
2103 nsPrintObject
* po
= (nsPrintObject
*)aPO
->mKids
[i
];
2104 PRBool printed
= PrintDocContent(po
, aStatus
);
2105 if (printed
|| NS_FAILED(aStatus
)) {
2113 //-------------------------------------------------------
2115 nsPrintEngine::DoPrint(nsPrintObject
* aPO
)
2118 PR_PL(("**************************** %s ****************************\n", gFrameTypesStr
[aPO
->mFrameType
]));
2119 PR_PL(("****** In DV::DoPrint PO: %p \n", aPO
));
2121 nsIPresShell
* poPresShell
= aPO
->mPresShell
;
2122 nsPresContext
* poPresContext
= aPO
->mPresContext
;
2124 NS_ASSERTION(poPresContext
, "PrintObject has not been reflowed");
2125 NS_ASSERTION(poPresContext
->Type() != nsPresContext::eContext_PrintPreview
,
2126 "How did this context end up here?");
2128 if (mPrt
->mPrintProgressParams
) {
2129 SetDocAndURLIntoProgress(aPO
, mPrt
->mPrintProgressParams
);
2133 PRInt16 printRangeType
= nsIPrintSettings::kRangeAllPages
;
2135 if (mPrt
->mPrintSettings
!= nsnull
) {
2136 mPrt
->mPrintSettings
->GetPrintRange(&printRangeType
);
2139 // Ask the page sequence frame to print all the pages
2140 nsIPageSequenceFrame
* pageSequence
;
2141 poPresShell
->GetPageSequenceFrame(&pageSequence
);
2142 NS_ASSERTION(nsnull
!= pageSequence
, "no page sequence frame");
2144 // We are done preparing for printing, so we can turn this off
2145 mPrt
->mPreparingForPrint
= PR_FALSE
;
2147 // mPrt->mDebugFilePtr this is onlu non-null when compiled for debugging
2148 if (nsnull
!= mPrt
->mDebugFilePtr
) {
2150 // output the regression test
2151 nsIFrameDebug
* fdbg
;
2152 nsIFrame
* root
= poPresShell
->FrameManager()->GetRootFrame();
2154 if (NS_SUCCEEDED(CallQueryInterface(root
, &fdbg
))) {
2155 fdbg
->DumpRegressionData(poPresContext
, mPrt
->mDebugFilePtr
, 0, PR_TRUE
);
2157 fclose(mPrt
->mDebugFilePtr
);
2158 SetIsPrinting(PR_FALSE
);
2161 #ifdef EXTENDED_DEBUG_PRINTING
2162 nsIFrame
* rootFrame
= poPresShell
->FrameManager()->GetRootFrame();
2163 if (aPO
->IsPrintable()) {
2166 GetDocTitleAndURL(aPO
, docStr
, urlStr
);
2167 DumpLayoutData(docStr
, urlStr
, poPresContext
, mPrt
->mPrintDocDC
, rootFrame
, docShell
, nsnull
);
2168 if (docStr
) nsMemory::Free(docStr
);
2169 if (urlStr
) nsMemory::Free(urlStr
);
2173 if (mPrt
->mPrintSettings
) {
2174 PRUnichar
* docTitleStr
= nsnull
;
2175 PRUnichar
* docURLStr
= nsnull
;
2177 GetDisplayTitleAndURL(aPO
, &docTitleStr
, &docURLStr
, eDocTitleDefBlank
);
2179 if (nsIPrintSettings::kRangeSelection
== printRangeType
) {
2180 poPresContext
->SetIsRenderingOnlySelection(PR_TRUE
);
2181 // temporarily creating rendering context
2182 // which is needed to dinf the selection frames
2183 nsCOMPtr
<nsIRenderingContext
> rc
;
2184 mPrt
->mPrintDC
->CreateRenderingContext(*getter_AddRefs(rc
));
2186 // find the starting and ending page numbers
2187 // via the selection
2188 nsIFrame
* startFrame
;
2190 PRInt32 startPageNum
;
2195 nsCOMPtr
<nsISelection
> selectionPS
;
2196 selectionPS
= poPresShell
->GetCurrentSelection(nsISelectionController::SELECTION_NORMAL
);
2198 rv
= GetPageRangeForSelection(poPresShell
, poPresContext
, *rc
, selectionPS
, pageSequence
,
2199 &startFrame
, startPageNum
, startRect
,
2200 &endFrame
, endPageNum
, endRect
);
2201 if (NS_SUCCEEDED(rv
)) {
2202 mPrt
->mPrintSettings
->SetStartPageRange(startPageNum
);
2203 mPrt
->mPrintSettings
->SetEndPageRange(endPageNum
);
2204 nsMargin
marginTwips(0,0,0,0);
2205 nsMargin
unwrtMarginTwips(0,0,0,0);
2206 mPrt
->mPrintSettings
->GetMarginInTwips(marginTwips
);
2207 mPrt
->mPrintSettings
->GetUnwriteableMarginInTwips(unwrtMarginTwips
);
2208 nsMargin totalMargin
= poPresContext
->TwipsToAppUnits(marginTwips
+
2210 if (startPageNum
== endPageNum
) {
2212 startRect
.y
-= totalMargin
.top
;
2213 endRect
.y
-= totalMargin
.top
;
2215 // Clip out selection regions above the top of the first page
2216 if (startRect
.y
< 0) {
2217 // Reduce height to be the height of the positive-territory
2218 // region of original rect
2219 startRect
.height
= PR_MAX(0, startRect
.YMost());
2222 if (endRect
.y
< 0) {
2223 // Reduce height to be the height of the positive-territory
2224 // region of original rect
2225 endRect
.height
= PR_MAX(0, endRect
.YMost());
2228 NS_ASSERTION(endRect
.y
>= startRect
.y
,
2229 "Selection end point should be after start point");
2230 NS_ASSERTION(startRect
.height
>= 0,
2231 "rect should have non-negative height.");
2232 NS_ASSERTION(endRect
.height
>= 0,
2233 "rect should have non-negative height.");
2235 nscoord selectionHgt
= endRect
.y
+ endRect
.height
- startRect
.y
;
2236 // XXX This is temporary fix for printing more than one page of a selection
2237 pageSequence
->SetSelectionHeight(startRect
.y
* aPO
->mZoomRatio
,
2238 selectionHgt
* aPO
->mZoomRatio
);
2240 // calc total pages by getting calculating the selection's height
2241 // and then dividing it by how page content frames will fit.
2242 nscoord pageWidth
, pageHeight
;
2243 mPrt
->mPrintDC
->GetDeviceSurfaceDimensions(pageWidth
, pageHeight
);
2244 pageHeight
-= totalMargin
.top
+ totalMargin
.bottom
;
2245 PRInt32 totalPages
= NSToIntCeil(float(selectionHgt
) * aPO
->mZoomRatio
/ float(pageHeight
));
2246 pageSequence
->SetTotalNumPages(totalPages
);
2252 nsIFrame
* seqFrame
;
2253 if (NS_FAILED(CallQueryInterface(pageSequence
, &seqFrame
))) {
2254 SetIsPrinting(PR_FALSE
);
2255 return NS_ERROR_FAILURE
;
2258 mPageSeqFrame
= pageSequence
;
2259 mPageSeqFrame
->StartPrint(poPresContext
, mPrt
->mPrintSettings
, docTitleStr
, docURLStr
);
2261 // Schedule Page to Print
2262 PR_PL(("Scheduling Print of PO: %p (%s) \n", aPO
, gFrameTypesStr
[aPO
->mFrameType
]));
2263 StartPagePrintTimer(aPO
);
2265 // not sure what to do here!
2266 SetIsPrinting(PR_FALSE
);
2267 return NS_ERROR_FAILURE
;
2275 //---------------------------------------------------------------------
2277 nsPrintEngine::SetDocAndURLIntoProgress(nsPrintObject
* aPO
,
2278 nsIPrintProgressParams
* aParams
)
2280 NS_ASSERTION(aPO
, "Must have vaild nsPrintObject");
2281 NS_ASSERTION(aParams
, "Must have vaild nsIPrintProgressParams");
2283 if (!aPO
|| !aPO
->mDocShell
|| !aParams
) {
2286 const PRUint32 kTitleLength
= 64;
2288 PRUnichar
* docTitleStr
;
2289 PRUnichar
* docURLStr
;
2290 GetDisplayTitleAndURL(aPO
, &docTitleStr
, &docURLStr
, eDocTitleDefURLDoc
);
2292 // Make sure the Titles & URLS don't get too long for the progress dialog
2293 ElipseLongString(docTitleStr
, kTitleLength
, PR_FALSE
);
2294 ElipseLongString(docURLStr
, kTitleLength
, PR_TRUE
);
2296 aParams
->SetDocTitle(docTitleStr
);
2297 aParams
->SetDocURL(docURLStr
);
2299 if (docTitleStr
!= nsnull
) nsMemory::Free(docTitleStr
);
2300 if (docURLStr
!= nsnull
) nsMemory::Free(docURLStr
);
2303 //---------------------------------------------------------------------
2305 nsPrintEngine::ElipseLongString(PRUnichar
*& aStr
, const PRUint32 aLen
, PRBool aDoFront
)
2307 // Make sure the URLS don't get too long for the progress dialog
2308 if (aStr
&& nsCRT::strlen(aStr
) > aLen
) {
2310 PRUnichar
* ptr
= &aStr
[nsCRT::strlen(aStr
)-aLen
+3];
2311 nsAutoString newStr
;
2312 newStr
.AppendLiteral("...");
2314 nsMemory::Free(aStr
);
2315 aStr
= ToNewUnicode(newStr
);
2317 nsAutoString
newStr(aStr
);
2318 newStr
.SetLength(aLen
-3);
2319 newStr
.AppendLiteral("...");
2320 nsMemory::Free(aStr
);
2321 aStr
= ToNewUnicode(newStr
);
2326 //-------------------------------------------------------
2328 nsPrintEngine::PrintPage(nsPrintObject
* aPO
,
2331 NS_ASSERTION(aPO
, "aPO is null!");
2332 NS_ASSERTION(mPageSeqFrame
, "mPageSeqFrame is null!");
2333 NS_ASSERTION(mPrt
, "mPrt is null!");
2335 // Although these should NEVER be NULL
2336 // This is added insurance, to make sure we don't crash in optimized builds
2337 if (!mPrt
|| !aPO
|| !mPageSeqFrame
) {
2338 ShowPrintErrorDialog(NS_ERROR_FAILURE
);
2339 return PR_TRUE
; // means we are done printing
2342 PR_PL(("-----------------------------------\n"));
2343 PR_PL(("------ In DV::PrintPage PO: %p (%s)\n", aPO
, gFrameTypesStr
[aPO
->mFrameType
]));
2345 // Check setting to see if someone request it be cancelled
2346 PRBool isCancelled
= PR_FALSE
;
2347 mPrt
->mPrintSettings
->GetIsCancelled(&isCancelled
);
2351 PRInt32 pageNum
, numPages
, endPage
;
2352 mPageSeqFrame
->GetCurrentPageNum(&pageNum
);
2353 mPageSeqFrame
->GetNumPages(&numPages
);
2355 PRBool donePrinting
;
2356 PRBool isDoingPrintRange
;
2357 mPageSeqFrame
->IsDoingPrintRange(&isDoingPrintRange
);
2358 if (isDoingPrintRange
) {
2361 mPageSeqFrame
->GetPrintRange(&fromPage
, &toPage
);
2363 if (fromPage
> numPages
) {
2366 if (toPage
> numPages
) {
2370 PR_PL(("****** Printing Page %d printing from %d to page %d\n", pageNum
, fromPage
, toPage
));
2372 donePrinting
= pageNum
>= toPage
;
2373 aInRange
= pageNum
>= fromPage
&& pageNum
<= toPage
;
2374 endPage
= (toPage
- fromPage
)+1;
2376 PR_PL(("****** Printing Page %d of %d page(s)\n", pageNum
, numPages
));
2378 donePrinting
= pageNum
>= numPages
;
2383 // XXX This is wrong, but the actual behavior in the presence of a print
2385 if (mPrt
->mPrintFrameType
== nsIPrintSettings::kEachFrameSep
)
2386 endPage
= mPrt
->mNumPrintablePages
;
2388 mPrt
->DoOnProgressChange(++mPrt
->mNumPagesPrinted
, endPage
, PR_FALSE
, 0);
2391 // if a print job was cancelled externally, an EndPage or BeginPage may
2392 // fail and the failure is passed back here.
2393 // Returning PR_TRUE means we are done printing.
2395 // When rv == NS_ERROR_ABORT, it means we want out of the
2396 // print job without displaying any error messages
2397 nsresult rv
= mPageSeqFrame
->PrintNextPage();
2398 if (NS_FAILED(rv
)) {
2399 if (rv
!= NS_ERROR_ABORT
) {
2400 ShowPrintErrorDialog(rv
);
2401 mPrt
->mIsAborted
= PR_TRUE
;
2406 mPageSeqFrame
->DoPageEnd();
2408 return donePrinting
;
2411 /** ---------------------------------------------------
2412 * Find by checking frames type
2415 nsPrintEngine::FindSelectionBoundsWithList(nsPresContext
* aPresContext
,
2416 nsIRenderingContext
& aRC
,
2418 nsIFrame
* aParentFrame
,
2420 nsIFrame
*& aStartFrame
,
2422 nsIFrame
*& aEndFrame
,
2425 NS_ASSERTION(aPresContext
, "Pointer is null!");
2426 NS_ASSERTION(aParentFrame
, "Pointer is null!");
2428 nsIFrame
* child
= aParentFrame
->GetFirstChild(aList
);
2429 aRect
+= aParentFrame
->GetPosition();
2431 // only leaf frames have this bit flipped
2432 // then check the hard way
2433 PRBool isSelected
= (child
->GetStateBits() & NS_FRAME_SELECTED_CONTENT
)
2434 == NS_FRAME_SELECTED_CONTENT
;
2436 isSelected
= child
->IsVisibleForPainting();
2440 nsRect r
= child
->GetRect();
2441 if (aStartFrame
== nsnull
) {
2442 aStartFrame
= child
;
2443 aStartRect
.SetRect(aRect
.x
+ r
.x
, aRect
.y
+ r
.y
, r
.width
, r
.height
);
2446 aEndRect
.SetRect(aRect
.x
+ r
.x
, aRect
.y
+ r
.y
, r
.width
, r
.height
);
2449 FindSelectionBounds(aPresContext
, aRC
, child
, aRect
, aStartFrame
, aStartRect
, aEndFrame
, aEndRect
);
2450 child
= child
->GetNextSibling();
2452 aRect
-= aParentFrame
->GetPosition();
2456 //-------------------------------------------------------
2457 // Find the Frame that is XMost
2459 nsPrintEngine::FindSelectionBounds(nsPresContext
* aPresContext
,
2460 nsIRenderingContext
& aRC
,
2461 nsIFrame
* aParentFrame
,
2463 nsIFrame
*& aStartFrame
,
2465 nsIFrame
*& aEndFrame
,
2468 NS_ASSERTION(aPresContext
, "Pointer is null!");
2469 NS_ASSERTION(aParentFrame
, "Pointer is null!");
2471 // loop through named child lists
2472 nsIAtom
* childListName
= nsnull
;
2473 PRInt32 childListIndex
= 0;
2475 nsresult rv
= FindSelectionBoundsWithList(aPresContext
, aRC
, childListName
, aParentFrame
, aRect
, aStartFrame
, aStartRect
, aEndFrame
, aEndRect
);
2476 NS_ENSURE_SUCCESS(rv
, rv
);
2477 childListName
= aParentFrame
->GetAdditionalChildListName(childListIndex
++);
2478 } while (childListName
);
2482 /** ---------------------------------------------------
2483 * This method finds the starting and ending page numbers
2484 * of the selection and also returns rect for each where
2485 * the x,y of the rect is relative to the very top of the
2486 * frame tree (absolutely positioned)
2489 nsPrintEngine::GetPageRangeForSelection(nsIPresShell
* aPresShell
,
2490 nsPresContext
* aPresContext
,
2491 nsIRenderingContext
& aRC
,
2492 nsISelection
* aSelection
,
2493 nsIPageSequenceFrame
* aPageSeqFrame
,
2494 nsIFrame
** aStartFrame
,
2495 PRInt32
& aStartPageNum
,
2497 nsIFrame
** aEndFrame
,
2498 PRInt32
& aEndPageNum
,
2501 NS_ASSERTION(aPresShell
, "Pointer is null!");
2502 NS_ASSERTION(aPresContext
, "Pointer is null!");
2503 NS_ASSERTION(aSelection
, "Pointer is null!");
2504 NS_ASSERTION(aPageSeqFrame
, "Pointer is null!");
2505 NS_ASSERTION(aStartFrame
, "Pointer is null!");
2506 NS_ASSERTION(aEndFrame
, "Pointer is null!");
2508 nsIFrame
* seqFrame
;
2509 if (NS_FAILED(CallQueryInterface(aPageSeqFrame
, &seqFrame
))) {
2510 return NS_ERROR_FAILURE
;
2513 nsIFrame
* startFrame
= nsnull
;
2514 nsIFrame
* endFrame
= nsnull
;
2516 // start out with the sequence frame and search the entire frame tree
2517 // capturing the starting and ending child frames of the selection
2519 nsRect r
= seqFrame
->GetRect();
2520 FindSelectionBounds(aPresContext
, aRC
, seqFrame
, r
,
2521 startFrame
, aStartRect
, endFrame
, aEndRect
);
2524 printf("Start Frame: %p\n", startFrame
);
2525 printf("End Frame: %p\n", endFrame
);
2528 // initial the page numbers here
2529 // in case we don't find and frames
2533 nsIFrame
* startPageFrame
;
2534 nsIFrame
* endPageFrame
;
2536 // check to make sure we found a starting frame
2537 if (startFrame
!= nsnull
) {
2538 // Now search up the tree to find what page the
2539 // start/ending selections frames are on
2541 // Check to see if start should be same as end if
2542 // the end frame comes back null
2543 if (endFrame
== nsnull
) {
2544 // XXX the "GetPageFrame" step could be integrated into
2545 // the FindSelectionBounds step, but walking up to find
2546 // the parent of a child frame isn't expensive and it makes
2547 // FindSelectionBounds a little easier to understand
2548 startPageFrame
= nsLayoutUtils::GetPageFrame(startFrame
);
2549 endPageFrame
= startPageFrame
;
2550 aEndRect
= aStartRect
;
2552 startPageFrame
= nsLayoutUtils::GetPageFrame(startFrame
);
2553 endPageFrame
= nsLayoutUtils::GetPageFrame(endFrame
);
2556 return NS_ERROR_FAILURE
;
2560 printf("Start Page: %p\n", startPageFrame
);
2561 printf("End Page: %p\n", endPageFrame
);
2563 // dump all the pages and their pointers
2565 PRInt32 pageNum
= 1;
2566 nsIFrame
* child
= seqFrame
->GetFirstChild(nsnull
);
2567 while (child
!= nsnull
) {
2568 printf("Page: %d - %p\n", pageNum
, child
);
2570 child
= child
->GetNextSibling();
2575 // Now that we have the page frames
2576 // find out what the page numbers are for each frame
2577 PRInt32 pageNum
= 1;
2578 nsIFrame
* page
= seqFrame
->GetFirstChild(nsnull
);
2579 while (page
!= nsnull
) {
2580 if (page
== startPageFrame
) {
2581 aStartPageNum
= pageNum
;
2583 if (page
== endPageFrame
) {
2584 aEndPageNum
= pageNum
;
2587 page
= page
->GetNextSibling();
2591 printf("Start Page No: %d\n", aStartPageNum
);
2592 printf("End Page No: %d\n", aEndPageNum
);
2595 *aStartFrame
= startPageFrame
;
2596 *aEndFrame
= endPageFrame
;
2601 //-----------------------------------------------------------------
2602 //-- Done: Printing Methods
2603 //-----------------------------------------------------------------
2606 //-----------------------------------------------------------------
2607 //-- Section: Misc Support Methods
2608 //-----------------------------------------------------------------
2610 //---------------------------------------------------------------------
2611 void nsPrintEngine::SetIsPrinting(PRBool aIsPrinting
)
2613 mIsDoingPrinting
= aIsPrinting
;
2614 if (mDocViewerPrint
) {
2615 mDocViewerPrint
->SetIsPrinting(aIsPrinting
);
2617 if (mPrt
&& aIsPrinting
) {
2618 mPrt
->mPreparingForPrint
= PR_TRUE
;
2622 //---------------------------------------------------------------------
2623 void nsPrintEngine::SetIsPrintPreview(PRBool aIsPrintPreview
)
2625 mIsDoingPrintPreview
= aIsPrintPreview
;
2627 if (mDocViewerPrint
) {
2628 mDocViewerPrint
->SetIsPrintPreview(aIsPrintPreview
);
2632 //---------------------------------------------------------------------
2634 nsPrintEngine::CleanupDocTitleArray(PRUnichar
**& aArray
, PRInt32
& aCount
)
2636 for (PRInt32 i
= aCount
- 1; i
>= 0; i
--) {
2637 nsMemory::Free(aArray
[i
]);
2639 nsMemory::Free(aArray
);
2644 //---------------------------------------------------------------------
2646 PRBool
nsPrintEngine::HasFramesetChild(nsIContent
* aContent
)
2652 PRUint32 numChildren
= aContent
->GetChildCount();
2654 // do a breadth search across all siblings
2655 for (PRUint32 i
= 0; i
< numChildren
; ++i
) {
2656 nsIContent
*child
= aContent
->GetChildAt(i
);
2657 if (child
->Tag() == nsGkAtoms::frameset
&&
2658 child
->IsNodeOfType(nsINode::eHTML
)) {
2668 /** ---------------------------------------------------
2669 * Get the Focused Frame for a documentviewer
2671 already_AddRefed
<nsIDOMWindow
>
2672 nsPrintEngine::FindFocusedDOMWindow()
2674 nsIDOMWindow
* domWin
= nsnull
;
2676 nsPIDOMWindow
*theDOMWindow
= mDocument
->GetWindow();
2678 nsIFocusController
*focusController
=
2679 theDOMWindow
->GetRootFocusController();
2680 if (focusController
) {
2681 nsCOMPtr
<nsIDOMWindowInternal
> theDOMWin
;
2682 focusController
->GetFocusedWindow(getter_AddRefs(theDOMWin
));
2683 if(theDOMWin
&& IsWindowsInOurSubTree(theDOMWin
)){
2684 NS_ADDREF(domWin
= theDOMWin
);
2692 //---------------------------------------------------------------------
2694 nsPrintEngine::IsWindowsInOurSubTree(nsIDOMWindow
* aDOMWindow
)
2696 PRBool found
= PR_FALSE
;
2698 // now check to make sure it is in "our" tree of docshells
2699 nsCOMPtr
<nsPIDOMWindow
> window(do_QueryInterface(aDOMWindow
));
2701 nsCOMPtr
<nsIDocShellTreeItem
> docShellAsItem
=
2702 do_QueryInterface(window
->GetDocShell());
2704 if (docShellAsItem
) {
2705 // get this DocViewer docshell
2706 nsCOMPtr
<nsIDocShell
> thisDVDocShell(do_QueryInterface(mContainer
));
2708 nsCOMPtr
<nsIDocShell
> parentDocshell(do_QueryInterface(docShellAsItem
));
2709 if (parentDocshell
) {
2710 if (parentDocshell
== thisDVDocShell
) {
2715 break; // at top of tree
2717 nsCOMPtr
<nsIDocShellTreeItem
> docShellParent
;
2718 docShellAsItem
->GetSameTypeParent(getter_AddRefs(docShellParent
));
2719 docShellAsItem
= docShellParent
;
2727 //-------------------------------------------------------
2729 nsPrintEngine::DonePrintingPages(nsPrintObject
* aPO
, nsresult aResult
)
2731 //NS_ASSERTION(aPO, "Pointer is null!");
2732 PR_PL(("****** In DV::DonePrintingPages PO: %p (%s)\n", aPO
, aPO
?gFrameTypesStr
[aPO
->mFrameType
]:""));
2734 if (aPO
!= nsnull
) {
2735 aPO
->mHasBeenPrinted
= PR_TRUE
;
2737 PRBool didPrint
= PrintDocContent(mPrt
->mPrintObject
, rv
);
2738 if (NS_SUCCEEDED(rv
) && didPrint
) {
2739 PR_PL(("****** In DV::DonePrintingPages PO: %p (%s) didPrint:%s (Not Done Printing)\n", aPO
, gFrameTypesStr
[aPO
->mFrameType
], PRT_YESNO(didPrint
)));
2744 if (NS_SUCCEEDED(aResult
)) {
2745 FirePrintCompletionEvent();
2748 SetIsPrinting(PR_FALSE
);
2750 // Release reference to mPagePrintTimer; the timer object destroys itself
2751 // after this returns true
2752 NS_IF_RELEASE(mPagePrintTimer
);
2757 //-------------------------------------------------------
2758 // Recursively sets the PO items to be printed "As Is"
2759 // from the given item down into the tree
2761 nsPrintEngine::SetPrintAsIs(nsPrintObject
* aPO
, PRBool aAsIs
)
2763 NS_ASSERTION(aPO
, "Pointer is null!");
2765 aPO
->mPrintAsIs
= aAsIs
;
2766 for (PRInt32 i
=0;i
<aPO
->mKids
.Count();i
++) {
2767 SetPrintAsIs((nsPrintObject
*)aPO
->mKids
[i
], aAsIs
);
2771 //-------------------------------------------------------
2772 // Given a DOMWindow it recursively finds the PO object that matches
2774 nsPrintEngine::FindPrintObjectByDOMWin(nsPrintObject
* aPO
,
2775 nsIDOMWindow
* aDOMWin
)
2777 NS_ASSERTION(aPO
, "Pointer is null!");
2779 // Often the CurFocused DOMWindow is passed in
2780 // andit is valid for it to be null, so short circut
2785 nsCOMPtr
<nsIDOMWindow
> domWin(do_GetInterface(aPO
->mDocShell
));
2786 if (domWin
&& domWin
== aDOMWin
) {
2790 PRInt32 cnt
= aPO
->mKids
.Count();
2791 for (PRInt32 i
= 0; i
< cnt
; ++i
) {
2792 nsPrintObject
* po
= FindPrintObjectByDOMWin((nsPrintObject
*)aPO
->mKids
[i
],
2802 //-------------------------------------------------------
2804 nsPrintEngine::EnablePOsForPrinting()
2806 // NOTE: All POs have been "turned off" for printing
2807 // this is where we decided which POs get printed.
2808 mPrt
->mSelectedPO
= nsnull
;
2810 if (mPrt
->mPrintSettings
== nsnull
) {
2811 return NS_ERROR_FAILURE
;
2814 mPrt
->mPrintFrameType
= nsIPrintSettings::kNoFrames
;
2815 mPrt
->mPrintSettings
->GetPrintFrameType(&mPrt
->mPrintFrameType
);
2817 PRInt16 printHowEnable
= nsIPrintSettings::kFrameEnableNone
;
2818 mPrt
->mPrintSettings
->GetHowToEnableFrameUI(&printHowEnable
);
2820 PRInt16 printRangeType
= nsIPrintSettings::kRangeAllPages
;
2821 mPrt
->mPrintSettings
->GetPrintRange(&printRangeType
);
2824 PR_PL(("********* nsPrintEngine::EnablePOsForPrinting *********\n"));
2825 PR_PL(("PrintFrameType: %s \n", gPrintFrameTypeStr
[mPrt
->mPrintFrameType
]));
2826 PR_PL(("HowToEnableFrameUI: %s \n", gFrameHowToEnableStr
[printHowEnable
]));
2827 PR_PL(("PrintRange: %s \n", gPrintRangeStr
[printRangeType
]));
2830 // ***** This is the ultimate override *****
2831 // if we are printing the selection (either an IFrame or selection range)
2832 // then set the mPrintFrameType as if it were the selected frame
2833 if (printRangeType
== nsIPrintSettings::kRangeSelection
) {
2834 mPrt
->mPrintFrameType
= nsIPrintSettings::kSelectedFrame
;
2835 printHowEnable
= nsIPrintSettings::kFrameEnableNone
;
2838 // This tells us that the "Frame" UI has turned off,
2839 // so therefore there are no FrameSets/Frames/IFrames to be printed
2841 // This means there are not FrameSets,
2842 // but the document could contain an IFrame
2843 if (printHowEnable
== nsIPrintSettings::kFrameEnableNone
) {
2845 // Print all the pages or a sub range of pages
2846 if (printRangeType
== nsIPrintSettings::kRangeAllPages
||
2847 printRangeType
== nsIPrintSettings::kRangeSpecifiedPageRange
) {
2848 SetPrintPO(mPrt
->mPrintObject
, PR_TRUE
);
2850 // Set the children so they are PrinAsIs
2851 // In this case, the children are probably IFrames
2852 if (mPrt
->mPrintObject
->mKids
.Count() > 0) {
2853 for (PRInt32 i
=0;i
<mPrt
->mPrintObject
->mKids
.Count();i
++) {
2854 nsPrintObject
* po
= (nsPrintObject
*)mPrt
->mPrintObject
->mKids
[i
];
2855 NS_ASSERTION(po
, "nsPrintObject can't be null!");
2859 // ***** Another override *****
2860 mPrt
->mPrintFrameType
= nsIPrintSettings::kFramesAsIs
;
2862 PR_PL(("PrintFrameType: %s \n", gPrintFrameTypeStr
[mPrt
->mPrintFrameType
]));
2863 PR_PL(("HowToEnableFrameUI: %s \n", gFrameHowToEnableStr
[printHowEnable
]));
2864 PR_PL(("PrintRange: %s \n", gPrintRangeStr
[printRangeType
]));
2868 // This means we are either printed a selected IFrame or
2869 // we are printing the current selection
2870 if (printRangeType
== nsIPrintSettings::kRangeSelection
) {
2872 // If the currentFocusDOMWin can'r be null if something is selected
2873 if (mPrt
->mCurrentFocusWin
) {
2874 // Find the selected IFrame
2875 nsPrintObject
* po
= FindPrintObjectByDOMWin(mPrt
->mPrintObject
, mPrt
->mCurrentFocusWin
);
2877 mPrt
->mSelectedPO
= po
;
2878 // Makes sure all of its children are be printed "AsIs"
2881 // Now, only enable this POs (the selected PO) and all of its children
2882 SetPrintPO(po
, PR_TRUE
);
2884 // check to see if we have a range selection,
2885 // as oppose to a insert selection
2886 // this means if the user just clicked on the IFrame then
2887 // there will not be a selection so we want the entire page to print
2889 // XXX this is sort of a hack right here to make the page
2890 // not try to reposition itself when printing selection
2891 nsCOMPtr
<nsIDOMWindow
> domWin
= do_GetInterface(po
->mDocShell
);
2892 if (!IsThereARangeSelection(domWin
)) {
2893 printRangeType
= nsIPrintSettings::kRangeAllPages
;
2894 mPrt
->mPrintSettings
->SetPrintRange(printRangeType
);
2896 PR_PL(("PrintFrameType: %s \n", gPrintFrameTypeStr
[mPrt
->mPrintFrameType
]));
2897 PR_PL(("HowToEnableFrameUI: %s \n", gFrameHowToEnableStr
[printHowEnable
]));
2898 PR_PL(("PrintRange: %s \n", gPrintRangeStr
[printRangeType
]));
2902 for (PRInt32 i
=0;i
<mPrt
->mPrintDocList
->Count();i
++) {
2903 nsPrintObject
* po
= (nsPrintObject
*)mPrt
->mPrintDocList
->ElementAt(i
);
2904 NS_ASSERTION(po
, "nsPrintObject can't be null!");
2905 nsCOMPtr
<nsIDOMWindow
> domWin
= do_GetInterface(po
->mDocShell
);
2906 if (IsThereARangeSelection(domWin
)) {
2907 mPrt
->mCurrentFocusWin
= domWin
;
2908 SetPrintPO(po
, PR_TRUE
);
2917 // check to see if there is a selection when a FrameSet is present
2918 if (printRangeType
== nsIPrintSettings::kRangeSelection
) {
2919 // If the currentFocusDOMWin can'r be null if something is selected
2920 if (mPrt
->mCurrentFocusWin
) {
2921 // Find the selected IFrame
2922 nsPrintObject
* po
= FindPrintObjectByDOMWin(mPrt
->mPrintObject
, mPrt
->mCurrentFocusWin
);
2924 mPrt
->mSelectedPO
= po
;
2925 // Makes sure all of its children are be printed "AsIs"
2928 // Now, only enable this POs (the selected PO) and all of its children
2929 SetPrintPO(po
, PR_TRUE
);
2931 // check to see if we have a range selection,
2932 // as oppose to a insert selection
2933 // this means if the user just clicked on the IFrame then
2934 // there will not be a selection so we want the entire page to print
2936 // XXX this is sort of a hack right here to make the page
2937 // not try to reposition itself when printing selection
2938 nsCOMPtr
<nsIDOMWindow
> domWin
= do_GetInterface(po
->mDocShell
);
2939 if (!IsThereARangeSelection(domWin
)) {
2940 printRangeType
= nsIPrintSettings::kRangeAllPages
;
2941 mPrt
->mPrintSettings
->SetPrintRange(printRangeType
);
2943 PR_PL(("PrintFrameType: %s \n", gPrintFrameTypeStr
[mPrt
->mPrintFrameType
]));
2944 PR_PL(("HowToEnableFrameUI: %s \n", gFrameHowToEnableStr
[printHowEnable
]));
2945 PR_PL(("PrintRange: %s \n", gPrintRangeStr
[printRangeType
]));
2951 // If we are printing "AsIs" then sets all the POs to be printed as is
2952 if (mPrt
->mPrintFrameType
== nsIPrintSettings::kFramesAsIs
) {
2953 SetPrintAsIs(mPrt
->mPrintObject
);
2954 SetPrintPO(mPrt
->mPrintObject
, PR_TRUE
);
2958 // If we are printing the selected Frame then
2959 // find that PO for that selected DOMWin and set it all of its
2960 // children to be printed
2961 if (mPrt
->mPrintFrameType
== nsIPrintSettings::kSelectedFrame
) {
2963 if ((mPrt
->mIsParentAFrameSet
&& mPrt
->mCurrentFocusWin
) || mPrt
->mIsIFrameSelected
) {
2964 nsPrintObject
* po
= FindPrintObjectByDOMWin(mPrt
->mPrintObject
, mPrt
->mCurrentFocusWin
);
2966 mPrt
->mSelectedPO
= po
;
2967 // NOTE: Calling this sets the "po" and
2968 // we don't want to do this for documents that have no children,
2969 // because then the "DoEndPage" gets called and it shouldn't
2970 if (po
->mKids
.Count() > 0) {
2971 // Makes sure that itself, and all of its children are printed "AsIs"
2975 // Now, only enable this POs (the selected PO) and all of its children
2976 SetPrintPO(po
, PR_TRUE
);
2982 // If we are print each subdoc separately,
2983 // then don't print any of the FraneSet Docs
2984 if (mPrt
->mPrintFrameType
== nsIPrintSettings::kEachFrameSep
) {
2985 SetPrintPO(mPrt
->mPrintObject
, PR_TRUE
);
2986 PRInt32 cnt
= mPrt
->mPrintDocList
->Count();
2987 for (PRInt32 i
=0;i
<cnt
;i
++) {
2988 nsPrintObject
* po
= (nsPrintObject
*)mPrt
->mPrintDocList
->ElementAt(i
);
2989 NS_ASSERTION(po
, "nsPrintObject can't be null!");
2990 if (po
->mFrameType
== eFrameSet
) {
2991 po
->mDontPrint
= PR_TRUE
;
2999 //-------------------------------------------------------
3000 // Return the nsPrintObject with that is XMost (The widest frameset frame) AND
3001 // contains the XMost (widest) layout frame
3003 nsPrintEngine::FindSmallestSTF()
3005 float smallestRatio
= 1.0f
;
3006 nsPrintObject
* smallestPO
= nsnull
;
3008 for (PRInt32 i
=0;i
<mPrt
->mPrintDocList
->Count();i
++) {
3009 nsPrintObject
* po
= (nsPrintObject
*)mPrt
->mPrintDocList
->ElementAt(i
);
3010 NS_ASSERTION(po
, "nsPrintObject can't be null!");
3011 if (po
->mFrameType
!= eFrameSet
&& po
->mFrameType
!= eIFrame
) {
3012 if (po
->mShrinkRatio
< smallestRatio
) {
3013 smallestRatio
= po
->mShrinkRatio
;
3019 #ifdef EXTENDED_DEBUG_PRINTING
3020 if (smallestPO
) printf("*PO: %p Type: %d %10.3f\n", smallestPO
, smallestPO
->mFrameType
, smallestPO
->mShrinkRatio
);
3025 //-------------------------------------------------------
3027 nsPrintEngine::TurnScriptingOn(PRBool aDoTurnOn
)
3029 nsPrintData
* prt
= mPrt
;
3030 #ifdef NS_PRINT_PREVIEW
3039 NS_ASSERTION(mDocument
, "We MUST have a document.");
3040 // First, get the script global object from the document...
3042 for (PRInt32 i
=0;i
<prt
->mPrintDocList
->Count();i
++) {
3043 nsPrintObject
* po
= (nsPrintObject
*)prt
->mPrintDocList
->ElementAt(i
);
3044 NS_ASSERTION(po
, "nsPrintObject can't be null!");
3046 nsIDocument
* doc
= po
->mDocument
;
3048 // get the script global object
3049 nsIScriptGlobalObject
*scriptGlobalObj
= doc
->GetScriptGlobalObject();
3051 if (scriptGlobalObj
) {
3052 nsIScriptContext
*scx
= scriptGlobalObj
->GetContext();
3053 NS_ASSERTION(scx
, "Can't get nsIScriptContext");
3055 doc
->DeleteProperty(nsGkAtoms::scriptEnabledBeforePrintPreview
);
3057 // Have to be careful, because people call us over and over again with
3058 // aDoTurnOn == PR_FALSE. So don't set the property if it's already
3059 // set, since in that case we'd set it to the wrong value.
3061 doc
->GetProperty(nsGkAtoms::scriptEnabledBeforePrintPreview
,
3063 if (propThere
== NS_PROPTABLE_PROP_NOT_THERE
) {
3064 // Stash the current value of IsScriptEnabled on the document, so
3065 // that layout code running in print preview doesn't get confused.
3066 doc
->SetProperty(nsGkAtoms::scriptEnabledBeforePrintPreview
,
3067 NS_INT32_TO_PTR(doc
->IsScriptEnabled()));
3070 scx
->SetScriptsEnabled(aDoTurnOn
, PR_TRUE
);
3075 //-----------------------------------------------------------------
3076 //-- Done: Misc Support Methods
3077 //-----------------------------------------------------------------
3080 //-----------------------------------------------------------------
3081 //-- Section: Finishing up or Cleaning up
3082 //-----------------------------------------------------------------
3084 //-----------------------------------------------------------------
3086 nsPrintEngine::CloseProgressDialog(nsIWebProgressListener
* aWebProgressListener
)
3088 if (aWebProgressListener
) {
3089 aWebProgressListener
->OnStateChange(nsnull
, nsnull
, nsIWebProgressListener::STATE_STOP
|nsIWebProgressListener::STATE_IS_DOCUMENT
, nsnull
);
3093 //-----------------------------------------------------------------
3095 nsPrintEngine::FinishPrintPreview()
3097 nsresult rv
= NS_OK
;
3099 #ifdef NS_PRINT_PREVIEW
3102 /* we're already finished with print preview */
3106 rv
= DocumentReadyForPrinting();
3108 SetIsCreatingPrintPreview(PR_FALSE
);
3110 /* cleaup on failure + notify user */
3111 if (NS_FAILED(rv
)) {
3112 /* cleanup done, let's fire-up an error dialog to notify the user
3113 * what went wrong...
3115 mPrt
->OnEndPrinting();
3116 TurnScriptingOn(PR_TRUE
);
3121 // At this point we are done preparing everything
3122 // before it is to be created
3125 if (mIsDoingPrintPreview
&& mOldPrtPreview
) {
3126 delete mOldPrtPreview
;
3127 mOldPrtPreview
= nsnull
;
3130 InstallPrintPreviewListener();
3132 mPrt
->OnEndPrinting();
3134 // PrintPreview was built using the mPrt (code reuse)
3135 // then we assign it over
3139 #endif // NS_PRINT_PREVIEW
3144 //-----------------------------------------------------------------
3145 //-- Done: Finishing up or Cleaning up
3146 //-----------------------------------------------------------------
3149 /*=============== Timer Related Code ======================*/
3151 nsPrintEngine::StartPagePrintTimer(nsPrintObject
* aPO
)
3153 if (!mPagePrintTimer
) {
3154 nsresult rv
= NS_NewPagePrintTimer(&mPagePrintTimer
);
3155 NS_ENSURE_SUCCESS(rv
, rv
);
3157 // Get the delay time in between the printing of each page
3158 // this gives the user more time to press cancel
3159 PRInt32 printPageDelay
= 500;
3160 mPrt
->mPrintSettings
->GetPrintPageDelay(&printPageDelay
);
3162 mPagePrintTimer
->Init(this, mDocViewerPrint
, printPageDelay
);
3165 return mPagePrintTimer
->Start(aPO
);
3168 /*=============== nsIObserver Interface ======================*/
3170 nsPrintEngine::Observe(nsISupports
*aSubject
, const char *aTopic
, const PRUnichar
*aData
)
3172 nsresult rv
= NS_ERROR_FAILURE
;
3174 if (mIsDoingPrinting
) {
3175 rv
= DocumentReadyForPrinting();
3177 /* cleaup on failure + notify user */
3178 if (NS_FAILED(rv
)) {
3179 CleanupOnFailure(rv
, PR_TRUE
);
3182 rv
= FinishPrintPreview();
3183 if (NS_FAILED(rv
)) {
3184 CleanupOnFailure(rv
, PR_FALSE
);
3187 mPrtPreview
->OnEndPrinting();
3196 //---------------------------------------------------------------
3197 //-- PLEvent Notification
3198 //---------------------------------------------------------------
3199 class nsPrintCompletionEvent
: public nsRunnable
{
3201 nsPrintCompletionEvent(nsIDocumentViewerPrint
*docViewerPrint
)
3202 : mDocViewerPrint(docViewerPrint
) {
3203 NS_ASSERTION(mDocViewerPrint
, "mDocViewerPrint is null.");
3207 if (mDocViewerPrint
)
3208 mDocViewerPrint
->OnDonePrinting();
3213 nsCOMPtr
<nsIDocumentViewerPrint
> mDocViewerPrint
;
3216 //-----------------------------------------------------------
3218 nsPrintEngine::FirePrintCompletionEvent()
3220 nsCOMPtr
<nsIRunnable
> event
= new nsPrintCompletionEvent(mDocViewerPrint
);
3221 if (NS_FAILED(NS_DispatchToCurrentThread(event
)))
3222 NS_WARNING("failed to dispatch print completion event");
3225 //---------------------------------------------------------------
3226 //---------------------------------------------------------------
3227 //-- Debug helper routines
3228 //---------------------------------------------------------------
3229 //---------------------------------------------------------------
3230 #if (defined(XP_WIN) || defined(XP_OS2)) && defined(EXTENDED_DEBUG_PRINTING)
3231 #include "windows.h"
3232 #include "process.h"
3235 #define MY_FINDFIRST(a,b) FindFirstFile(a,b)
3236 #define MY_FINDNEXT(a,b) FindNextFile(a,b)
3237 #define ISDIR(a) (a.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
3238 #define MY_FINDCLOSE(a) FindClose(a)
3239 #define MY_FILENAME(a) a.cFileName
3240 #define MY_FILESIZE(a) (a.nFileSizeHigh * MAXDWORD) + a.nFileSizeLow
3242 int RemoveFilesInDir(const char * aDir
)
3244 WIN32_FIND_DATA data_ptr
;
3247 char path
[MAX_PATH
];
3251 // Append slash to the end of the directory names if not there
3252 if (path
[strlen(path
)-1] != '\\')
3255 char findPath
[MAX_PATH
];
3256 strcpy(findPath
, path
);
3257 strcat(findPath
, "*.*");
3259 find_handle
= MY_FINDFIRST(findPath
, &data_ptr
);
3261 if (find_handle
!= INVALID_HANDLE_VALUE
) {
3264 && (stricmp(MY_FILENAME(data_ptr
),"."))
3265 && (stricmp(MY_FILENAME(data_ptr
),".."))) {
3268 else if (!ISDIR(data_ptr
)) {
3269 if (!strncmp(MY_FILENAME(data_ptr
), "print_dump", 10)) {
3270 char fileName
[MAX_PATH
];
3271 strcpy(fileName
, aDir
);
3272 strcat(fileName
, "\\");
3273 strcat(fileName
, MY_FILENAME(data_ptr
));
3274 printf("Removing %s\n", fileName
);
3278 } while(MY_FINDNEXT(find_handle
,&data_ptr
));
3279 MY_FINDCLOSE(find_handle
);
3285 #ifdef EXTENDED_DEBUG_PRINTING
3287 /** ---------------------------------------------------
3288 * Dumps Frames for Printing
3290 static void RootFrameList(nsPresContext
* aPresContext
, FILE* out
, PRInt32 aIndent
)
3292 if (!aPresContext
|| !out
)
3295 nsIPresShell
*shell
= aPresContext
->GetPresShell();
3297 nsIFrame
* frame
= shell
->FrameManager()->GetRootFrame();
3299 nsIFrameDebug
* debugFrame
;
3300 nsresult rv
= CallQueryInterface(frame
, &debugFrame
);
3301 if (NS_SUCCEEDED(rv
))
3302 debugFrame
->List(aPresContext
, out
, aIndent
);
3307 /** ---------------------------------------------------
3308 * Dumps Frames for Printing
3310 static void DumpFrames(FILE* out
,
3311 nsPresContext
* aPresContext
,
3312 nsIRenderingContext
* aRendContext
,
3316 NS_ASSERTION(out
, "Pointer is null!");
3317 NS_ASSERTION(aPresContext
, "Pointer is null!");
3318 NS_ASSERTION(aRendContext
, "Pointer is null!");
3319 NS_ASSERTION(aFrame
, "Pointer is null!");
3321 nsIFrame
* child
= aFrame
->GetFirstChild(nsnull
);
3322 while (child
!= nsnull
) {
3323 for (PRInt32 i
=0;i
<aLevel
;i
++) {
3327 nsIFrameDebug
* frameDebug
;
3329 if (NS_SUCCEEDED(CallQueryInterface(child
, &frameDebug
))) {
3330 frameDebug
->GetFrameName(tmp
);
3332 fputs(NS_LossyConvertUTF16toASCII(tmp
).get(), out
);
3334 if (NS_SUCCEEDED(child
->IsVisibleForPainting(aPresContext
, *aRendContext
, PR_TRUE
, &isSelected
))) {
3335 fprintf(out
, " %p %s", child
, isSelected
?"VIS":"UVS");
3336 nsRect rect
= child
->GetRect();
3337 fprintf(out
, "[%d,%d,%d,%d] ", rect
.x
, rect
.y
, rect
.width
, rect
.height
);
3338 fprintf(out
, "v: %p ", (void*)child
->GetView());
3340 DumpFrames(out
, aPresContext
, aRendContext
, child
, aLevel
+1);
3341 child
= child
->GetNextSibling();
3347 /** ---------------------------------------------------
3348 * Dumps the Views from the DocShell
3351 DumpViews(nsIDocShell
* aDocShell
, FILE* out
)
3353 NS_ASSERTION(aDocShell
, "Pointer is null!");
3354 NS_ASSERTION(out
, "Pointer is null!");
3356 if (nsnull
!= aDocShell
) {
3357 fprintf(out
, "docshell=%p \n", aDocShell
);
3358 nsIPresShell
* shell
= nsPrintEngine::GetPresShellFor(aDocShell
);
3360 nsIViewManager
* vm
= shell
->GetViewManager();
3363 vm
->GetRootView(root
);
3364 if (nsnull
!= root
) {
3370 fputs("null pres shell\n", out
);
3373 // dump the views of the sub documents
3375 nsCOMPtr
<nsIDocShellTreeNode
> docShellAsNode(do_QueryInterface(aDocShell
));
3376 docShellAsNode
->GetChildCount(&n
);
3377 for (i
= 0; i
< n
; i
++) {
3378 nsCOMPtr
<nsIDocShellTreeItem
> child
;
3379 docShellAsNode
->GetChildAt(i
, getter_AddRefs(child
));
3380 nsCOMPtr
<nsIDocShell
> childAsShell(do_QueryInterface(child
));
3382 DumpViews(childAsShell
, out
);
3388 /** ---------------------------------------------------
3389 * Dumps the Views and Frames
3391 void DumpLayoutData(char* aTitleStr
,
3393 nsPresContext
* aPresContext
,
3394 nsIDeviceContext
* aDC
,
3395 nsIFrame
* aRootFrame
,
3396 nsIDocShekk
* aDocShell
,
3399 if (!kPrintingLogMod
|| kPrintingLogMod
->level
!= DUMP_LAYOUT_LEVEL
) return;
3401 if (aPresContext
== nsnull
|| aDC
== nsnull
) {
3405 #ifdef NS_PRINT_PREVIEW
3406 if (aPresContext
->Type() == nsPresContext::eContext_PrintPreview
) {
3411 NS_ASSERTION(aRootFrame
, "Pointer is null!");
3412 NS_ASSERTION(aDocShell
, "Pointer is null!");
3414 // Dump all the frames and view to a a file
3416 sprintf(filename
, "print_dump_layout_%d.txt", gDumpLOFileNameCnt
++);
3417 FILE * fd
= aFD
?aFD
:fopen(filename
, "w");
3419 fprintf(fd
, "Title: %s\n", aTitleStr
?aTitleStr
:"");
3420 fprintf(fd
, "URL: %s\n", aURLStr
?aURLStr
:"");
3421 fprintf(fd
, "--------------- Frames ----------------\n");
3422 fprintf(fd
, "--------------- Frames ----------------\n");
3423 nsCOMPtr
<nsIRenderingContext
> renderingContext
;
3424 aDC
->CreateRenderingContext(*getter_AddRefs(renderingContext
));
3425 RootFrameList(aPresContext
, fd
, 0);
3426 //DumpFrames(fd, aPresContext, renderingContext, aRootFrame, 0);
3427 fprintf(fd
, "---------------------------------------\n\n");
3428 fprintf(fd
, "--------------- Views From Root Frame----------------\n");
3429 nsIView
* v
= aRootFrame
->GetView();
3433 printf("View is null!\n");
3436 fprintf(fd
, "--------------- All Views ----------------\n");
3437 DumpViews(aDocShell
, fd
);
3438 fprintf(fd
, "---------------------------------------\n\n");
3440 if (aFD
== nsnull
) {
3446 //-------------------------------------------------------------
3447 static void DumpPrintObjectsList(nsVoidArray
* aDocList
)
3449 if (!kPrintingLogMod
|| kPrintingLogMod
->level
!= DUMP_LAYOUT_LEVEL
) return;
3451 NS_ASSERTION(aDocList
, "Pointer is null!");
3453 const char types
[][3] = {"DC", "FR", "IF", "FS"};
3454 PR_PL(("Doc List\n***************************************************\n"));
3455 PR_PL(("T P A H PO DocShell Seq Page Root Page# Rect\n"));
3456 PRInt32 cnt
= aDocList
->Count();
3457 for (PRInt32 i
=0;i
<cnt
;i
++) {
3458 nsPrintObject
* po
= (nsPrintObject
*)aDocList
->ElementAt(i
);
3459 NS_ASSERTION(po
, "nsPrintObject can't be null!");
3460 nsIFrame
* rootFrame
= nsnull
;
3461 if (po
->mPresShell
) {
3462 rootFrame
= po
->mPresShell
->FrameManager()->GetRootFrame();
3463 while (rootFrame
!= nsnull
) {
3464 nsIPageSequenceFrame
* sqf
= nsnull
;
3465 if (NS_SUCCEEDED(CallQueryInterface(rootFrame
, &sqf
))) {
3468 rootFrame
= rootFrame
->GetFirstChild(nsnull
);
3472 PR_PL(("%s %d %d %d %p %p %p %p %p %d %d,%d,%d,%d\n", types
[po
->mFrameType
],
3473 po
->IsPrintable(), po
->mPrintAsIs
, po
->mHasBeenPrinted
, po
, po
->mDocShell
.get(), po
->mSeqFrame
,
3474 po
->mPageFrame
, rootFrame
, po
->mPageNum
, po
->mRect
.x
, po
->mRect
.y
, po
->mRect
.width
, po
->mRect
.height
));
3478 //-------------------------------------------------------------
3479 static void DumpPrintObjectsTree(nsPrintObject
* aPO
, int aLevel
, FILE* aFD
)
3481 if (!kPrintingLogMod
|| kPrintingLogMod
->level
!= DUMP_LAYOUT_LEVEL
) return;
3483 NS_ASSERTION(aPO
, "Pointer is null!");
3485 FILE * fd
= aFD
?aFD
:stdout
;
3486 const char types
[][3] = {"DC", "FR", "IF", "FS"};
3488 fprintf(fd
, "DocTree\n***************************************************\n");
3489 fprintf(fd
, "T PO DocShell Seq Page Page# Rect\n");
3491 PRInt32 cnt
= aPO
->mKids
.Count();
3492 for (PRInt32 i
=0;i
<cnt
;i
++) {
3493 nsPrintObject
* po
= (nsPrintObject
*)aPO
->mKids
.ElementAt(i
);
3494 NS_ASSERTION(po
, "nsPrintObject can't be null!");
3495 for (PRInt32 k
=0;k
<aLevel
;k
++) fprintf(fd
, " ");
3496 fprintf(fd
, "%s %p %p %p %p %d %d,%d,%d,%d\n", types
[po
->mFrameType
], po
, po
->mDocShell
.get(), po
->mSeqFrame
,
3497 po
->mPageFrame
, po
->mPageNum
, po
->mRect
.x
, po
->mRect
.y
, po
->mRect
.width
, po
->mRect
.height
);
3501 //-------------------------------------------------------------
3502 static void GetDocTitleAndURL(nsPrintObject
* aPO
, char *& aDocStr
, char *& aURLStr
)
3507 PRUnichar
* docTitleStr
;
3508 PRUnichar
* docURLStr
;
3509 nsPrintEngine::GetDisplayTitleAndURL(aPO
,
3510 &docTitleStr
, &docURLStr
,
3511 nsPrintEngine::eDocTitleDefURLDoc
);
3514 nsAutoString
strDocTitle(docTitleStr
);
3515 aDocStr
= ToNewCString(strDocTitle
);
3516 nsMemory::Free(docTitleStr
);
3520 nsAutoString
strURL(docURLStr
);
3521 aURLStr
= ToNewCString(strURL
);
3522 nsMemory::Free(docURLStr
);
3526 //-------------------------------------------------------------
3527 static void DumpPrintObjectsTreeLayout(nsPrintObject
* aPO
,
3528 nsIDeviceContext
* aDC
,
3529 int aLevel
, FILE * aFD
)
3531 if (!kPrintingLogMod
|| kPrintingLogMod
->level
!= DUMP_LAYOUT_LEVEL
) return;
3533 NS_ASSERTION(aPO
, "Pointer is null!");
3534 NS_ASSERTION(aDC
, "Pointer is null!");
3536 const char types
[][3] = {"DC", "FR", "IF", "FS"};
3539 fd
= fopen("tree_layout.txt", "w");
3540 fprintf(fd
, "DocTree\n***************************************************\n");
3541 fprintf(fd
, "***************************************************\n");
3542 fprintf(fd
, "T PO DocShell Seq Page Page# Rect\n");
3547 nsIFrame
* rootFrame
= nsnull
;
3548 if (aPO
->mPresShell
) {
3549 rootFrame
= aPO
->mPresShell
->FrameManager()->GetRootFrame();
3551 for (PRInt32 k
=0;k
<aLevel
;k
++) fprintf(fd
, " ");
3552 fprintf(fd
, "%s %p %p %p %p %d %d,%d,%d,%d\n", types
[aPO
->mFrameType
], aPO
, aPO
->mDocShell
.get(), aPO
->mSeqFrame
,
3553 aPO
->mPageFrame
, aPO
->mPageNum
, aPO
->mRect
.x
, aPO
->mRect
.y
, aPO
->mRect
.width
, aPO
->mRect
.height
);
3554 if (aPO
->IsPrintable()) {
3557 GetDocTitleAndURL(aPO
, docStr
, urlStr
);
3558 DumpLayoutData(docStr
, urlStr
, aPO
->mPresContext
, aDC
, rootFrame
, aPO
->mDocShell
, fd
);
3559 if (docStr
) nsMemory::Free(docStr
);
3560 if (urlStr
) nsMemory::Free(urlStr
);
3562 fprintf(fd
, "<***************************************************>\n");
3564 PRInt32 cnt
= aPO
->mKids
.Count();
3565 for (PRInt32 i
=0;i
<cnt
;i
++) {
3566 nsPrintObject
* po
= (nsPrintObject
*)aPO
->mKids
.ElementAt(i
);
3567 NS_ASSERTION(po
, "nsPrintObject can't be null!");
3568 DumpPrintObjectsTreeLayout(po
, aDC
, aLevel
+1, fd
);
3571 if (aLevel
== 0 && fd
) {
3576 //-------------------------------------------------------------
3577 static void DumpPrintObjectsListStart(const char * aStr
, nsVoidArray
* aDocList
)
3579 if (!kPrintingLogMod
|| kPrintingLogMod
->level
!= DUMP_LAYOUT_LEVEL
) return;
3581 NS_ASSERTION(aStr
, "Pointer is null!");
3582 NS_ASSERTION(aDocList
, "Pointer is null!");
3584 PR_PL(("%s\n", aStr
));
3585 DumpPrintObjectsList(aDocList
);
3588 #define DUMP_DOC_LIST(_title) DumpPrintObjectsListStart((_title), mPrt->mPrintDocList);
3589 #define DUMP_DOC_TREE DumpPrintObjectsTree(mPrt->mPrintObject);
3590 #define DUMP_DOC_TREELAYOUT DumpPrintObjectsTreeLayout(mPrt->mPrintObject, mPrt->mPrintDC);
3593 #define DUMP_DOC_LIST(_title)
3594 #define DUMP_DOC_TREE
3595 #define DUMP_DOC_TREELAYOUT
3598 //---------------------------------------------------------------
3599 //---------------------------------------------------------------
3600 //-- End of debug helper routines
3601 //---------------------------------------------------------------