For Bug 428063, need oldAppVersion for update verify when testing 3.0rc1 --> 3.0rc2
[mozilla-1.9.git] / layout / printing / nsPrintEngine.cpp
blob972a55e3c215ad636bc0a3d786e5475d5d26c107
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
13 * License.
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.
22 * Contributor(s):
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"
43 #include "nsCRT.h"
45 #include "nsISelection.h"
46 #include "nsIScriptGlobalObject.h"
47 #include "nsPIDOMWindow.h"
48 #include "nsIDocShell.h"
49 #include "nsIURI.h"
50 #include "nsContentErrors.h"
52 // Print Options
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"
60 #include "nsXPCOM.h"
61 #include "nsISupportsPrimitives.h"
63 static const char sPrintSettingsServiceContractID[] = "@mozilla.org/gfx/printsettings-service;1";
65 // Printing Events
66 #include "nsPrintPreviewListener.h"
67 #include "nsThreadUtils.h"
69 // Printing
70 #include "nsIWebBrowserPrint.h"
71 #include "nsIDOMHTMLFrameElement.h"
72 #include "nsIDOMHTMLFrameSetElement.h"
73 #include "nsIDOMHTMLIFrameElement.h"
74 #include "nsIDOMHTMLObjectElement.h"
75 #include "nsIDOMHTMLEmbedElement.h"
77 // Print Preview
78 #include "imgIContainer.h" // image animation mode constants
79 #include "nsIWebBrowserPrint.h" // needed for PrintPreview Navigation constants
81 // Print Progress
82 #include "nsIPrintProgress.h"
83 #include "nsIPrintProgressParams.h"
84 #include "nsIObserver.h"
86 // Print error dialog
87 #include "nsIPrompt.h"
88 #include "nsIWindowWatcher.h"
89 #include "nsIStringBundle.h"
91 // Printing Prompts
92 #include "nsIPrintingPromptService.h"
93 static const char kPrintingPromptService[] = "@mozilla.org/embedcomp/printingprompt-service;1";
95 // Printing Timer
96 #include "nsPagePrintTimer.h"
98 // FrameSet
99 #include "nsIDocument.h"
101 // Focus
102 #include "nsIDOMEventTarget.h"
103 #include "nsIDOMFocusListener.h"
104 #include "nsISelectionController.h"
106 // Misc
107 #include "nsISupportsUtils.h"
108 #include "nsIFrame.h"
109 #include "nsIScriptContext.h"
110 #include "nsILinkHandler.h"
111 #include "nsIDOMDocument.h"
112 #include "nsISelectionListener.h"
113 #include "nsISelectionPrivate.h"
114 #include "nsIDOMHTMLDocument.h"
115 #include "nsIDOMNSHTMLDocument.h"
116 #include "nsIDOMHTMLCollection.h"
117 #include "nsIDOMHTMLElement.h"
118 #include "nsIDOMRange.h"
119 #include "nsContentCID.h"
120 #include "nsLayoutCID.h"
121 #include "nsContentUtils.h"
122 #include "nsIPresShell.h"
123 #include "nsLayoutUtils.h"
125 #include "nsViewsCID.h"
126 #include "nsWidgetsCID.h"
127 #include "nsIDeviceContext.h"
128 #include "nsIDeviceContextSpec.h"
129 #include "nsIViewManager.h"
130 #include "nsIView.h"
132 #include "nsIPageSequenceFrame.h"
133 #include "nsIURL.h"
134 #include "nsIContentViewerEdit.h"
135 #include "nsIContentViewerFile.h"
136 #include "nsIMarkupDocumentViewer.h"
137 #include "nsIInterfaceRequestor.h"
138 #include "nsIInterfaceRequestorUtils.h"
139 #include "nsIDocShellTreeItem.h"
140 #include "nsIDocShellTreeNode.h"
141 #include "nsIDocShellTreeOwner.h"
142 #include "nsIWebBrowserChrome.h"
143 #include "nsIDocShell.h"
144 #include "nsIBaseWindow.h"
145 #include "nsIFrameDebug.h"
146 #include "nsILayoutHistoryState.h"
147 #include "nsFrameManager.h"
148 #include "nsIParser.h"
149 #include "nsGUIEvent.h"
150 #include "nsHTMLReflowState.h"
151 #include "nsIDOMHTMLAnchorElement.h"
152 #include "nsIDOMHTMLAreaElement.h"
153 #include "nsIDOMHTMLLinkElement.h"
154 #include "nsIDOMHTMLImageElement.h"
155 #include "nsIContentViewerContainer.h"
156 #include "nsIContentViewer.h"
157 #include "nsIDocumentViewerPrint.h"
159 #include "nsPIDOMWindow.h"
160 #include "nsIFocusController.h"
162 #include "nsCDefaultURIFixup.h"
163 #include "nsIURIFixup.h"
165 //-----------------------------------------------------
166 // PR LOGGING
167 #ifdef MOZ_LOGGING
168 #define FORCE_PR_LOG /* Allow logging in the release build */
169 #endif
171 #include "prlog.h"
173 #ifdef PR_LOGGING
175 #ifdef NS_DEBUG
176 // PR_LOGGING is force to always be on (even in release builds)
177 // but we only want some of it on,
178 //#define EXTENDED_DEBUG_PRINTING
179 #endif
181 #define DUMP_LAYOUT_LEVEL 9 // this turns on the dumping of each doucment's layout info
183 static PRLogModuleInfo * kPrintingLogMod = PR_NewLogModule("printing");
184 #define PR_PL(_p1) PR_LOG(kPrintingLogMod, PR_LOG_DEBUG, _p1);
186 #ifdef EXTENDED_DEBUG_PRINTING
187 static PRUint32 gDumpFileNameCnt = 0;
188 static PRUint32 gDumpLOFileNameCnt = 0;
189 #endif
191 #define PRT_YESNO(_p) ((_p)?"YES":"NO")
192 static const char * gFrameTypesStr[] = {"eDoc", "eFrame", "eIFrame", "eFrameSet"};
193 static const char * gPrintFrameTypeStr[] = {"kNoFrames", "kFramesAsIs", "kSelectedFrame", "kEachFrameSep"};
194 static const char * gFrameHowToEnableStr[] = {"kFrameEnableNone", "kFrameEnableAll", "kFrameEnableAsIsAndEach"};
195 static const char * gPrintRangeStr[] = {"kRangeAllPages", "kRangeSpecifiedPageRange", "kRangeSelection", "kRangeFocusFrame"};
196 #else
197 #define PRT_YESNO(_p)
198 #define PR_PL(_p1)
199 #endif
201 #ifdef EXTENDED_DEBUG_PRINTING
202 // Forward Declarations
203 static void DumpPrintObjectsListStart(const char * aStr, nsVoidArray * aDocList);
204 static void DumpPrintObjectsTree(nsPrintObject * aPO, int aLevel= 0, FILE* aFD = nsnull);
205 static void DumpPrintObjectsTreeLayout(nsPrintObject * aPO,nsIDeviceContext * aDC, int aLevel= 0, FILE * aFD = nsnull);
207 #define DUMP_DOC_LIST(_title) DumpPrintObjectsListStart((_title), mPrt->mPrintDocList);
208 #define DUMP_DOC_TREE DumpPrintObjectsTree(mPrt->mPrintObject);
209 #define DUMP_DOC_TREELAYOUT DumpPrintObjectsTreeLayout(mPrt->mPrintObject, mPrt->mPrintDC);
210 #else
211 #define DUMP_DOC_LIST(_title)
212 #define DUMP_DOC_TREE
213 #define DUMP_DOC_TREELAYOUT
214 #endif
217 // Class IDs
218 static NS_DEFINE_CID(kViewManagerCID, NS_VIEW_MANAGER_CID);
219 static NS_DEFINE_CID(kWidgetCID, NS_CHILD_CID);
221 NS_IMPL_ISUPPORTS1(nsPrintEngine, nsIObserver)
223 //---------------------------------------------------
224 //-- nsPrintEngine Class Impl
225 //---------------------------------------------------
226 nsPrintEngine::nsPrintEngine() :
227 mIsCreatingPrintPreview(PR_FALSE),
228 mIsDoingPrinting(PR_FALSE),
229 mIsDoingPrintPreview(PR_FALSE),
230 mProgressDialogIsShown(PR_FALSE),
231 mDocViewerPrint(nsnull),
232 mContainer(nsnull),
233 mDeviceContext(nsnull),
234 mPrt(nsnull),
235 mPagePrintTimer(nsnull),
236 mPageSeqFrame(nsnull),
237 mParentWidget(nsnull),
238 mPrtPreview(nsnull),
239 mOldPrtPreview(nsnull),
240 mDebugFile(nsnull)
244 //-------------------------------------------------------
245 nsPrintEngine::~nsPrintEngine()
247 Destroy(); // for insurance
250 //-------------------------------------------------------
251 void nsPrintEngine::Destroy()
253 if (mPrt) {
254 delete mPrt;
255 mPrt = nsnull;
258 #ifdef NS_PRINT_PREVIEW
259 if (mPrtPreview) {
260 delete mPrtPreview;
261 mPrtPreview = nsnull;
264 // This is insruance
265 if (mOldPrtPreview) {
266 delete mOldPrtPreview;
267 mOldPrtPreview = nsnull;
270 #endif
274 //-------------------------------------------------------
275 void nsPrintEngine::DestroyPrintingData()
277 if (mPrt) {
278 delete mPrt;
279 mPrt = nsnull;
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,
293 FILE* aDebugFile)
295 NS_ENSURE_ARG_POINTER(aDocViewerPrint);
296 NS_ENSURE_ARG_POINTER(aContainer);
297 NS_ENSURE_ARG_POINTER(aDocument);
298 NS_ENSURE_ARG_POINTER(aDevContext);
299 NS_ENSURE_ARG_POINTER(aParentWidget);
301 mDocViewerPrint = aDocViewerPrint; // weak reference
302 mContainer = aContainer; // weak reference
303 mDocument = aDocument;
304 mDeviceContext = aDevContext; // weak reference
305 mParentWidget = aParentWidget;
307 mDebugFile = aDebugFile; // ok to be NULL
309 return NS_OK;
312 //-------------------------------------------------------
313 PRBool
314 nsPrintEngine::CheckBeforeDestroy()
316 if (mPrt && mPrt->mPreparingForPrint) {
317 mPrt->mDocWasToBeDestroyed = PR_TRUE;
318 return PR_TRUE;
320 return PR_FALSE;
323 //-------------------------------------------------------
324 nsresult
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
338 void
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 //----------------------------------------------------------------------
353 nsresult
354 nsPrintEngine::GetSeqFrameAndCountPagesInternal(nsPrintObject* aPO,
355 nsIFrame*& aSeqFrame,
356 PRInt32& aCount)
358 NS_ENSURE_ARG_POINTER(aPO);
360 // Finds the SimplePageSequencer frame
361 nsIPageSequenceFrame* seqFrame = nsnull;
362 aPO->mPresShell->GetPageSequenceFrame(&seqFrame);
363 if (seqFrame) {
364 CallQueryInterface(seqFrame, &aSeqFrame);
365 } else {
366 aSeqFrame = nsnull;
368 if (aSeqFrame == nsnull) return NS_ERROR_FAILURE;
370 // first count the total number of pages
371 aCount = 0;
372 nsIFrame* pageFrame = aSeqFrame->GetFirstChild(nsnull);
373 while (pageFrame != nsnull) {
374 aCount++;
375 pageFrame = pageFrame->GetNextSibling();
378 return NS_OK;
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);
409 #endif
411 //--------------------------------------------------------------------------------
413 nsresult
414 nsPrintEngine::CommonPrint(PRBool aIsPrintPreview,
415 nsIPrintSettings* aPrintSettings,
416 nsIWebProgressListener* aWebProgressListener) {
417 nsresult rv = DoCommonPrint(aIsPrintPreview, aPrintSettings,
418 aWebProgressListener);
419 if (NS_FAILED(rv)) {
420 if (aIsPrintPreview) {
421 SetIsCreatingPrintPreview(PR_FALSE);
422 SetIsPrintPreview(PR_FALSE);
423 } else {
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);
430 delete mPrt;
431 mPrt = nsnull;
434 return rv;
437 nsresult
438 nsPrintEngine::DoCommonPrint(PRBool aIsPrintPreview,
439 nsIPrintSettings* aPrintSettings,
440 nsIWebProgressListener* aWebProgressListener)
442 nsresult rv;
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;
454 } else {
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);
480 if (viewer) {
481 viewer->SetTextZoom(1.0f);
482 viewer->SetFullZoom(1.0f);
484 } else {
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);
547 } else {
548 mPrt->mPrintSettings->SetHowToEnableFrameUI(nsIPrintSettings::kFrameEnableAsIsAndEach);
550 } else {
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) {
561 #ifdef NS_DEBUG
562 mPrt->mDebugFilePtr = mDebugFile;
563 #endif
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",
570 printSilently);
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
594 rv = NS_OK;
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);
602 } else {
603 rv = NS_ERROR_GFX_NO_PRINTROMPTSERVICE;
605 } else {
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)
611 return rv;
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);
629 } else {
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);
652 } else {
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;
661 break;
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;
669 break;
670 } // switch
671 mPrt->mPrintSettings->SetPrintFrameType(mPrt->mPrintFrameType);
674 } else {
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);
686 if (!notifyOnInit) {
687 rv = FinishPrintPreview();
688 } else {
689 rv = NS_OK;
691 NS_ENSURE_SUCCESS(rv, rv);
692 } else {
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);
706 PRBool doNotify;
707 ShowPrintProgress(PR_TRUE, doNotify);
708 if (!doNotify) {
709 // Print listener setup...
710 mPrt->OnStartPrinting();
711 rv = DocumentReadyForPrinting();
712 NS_ENSURE_SUCCESS(rv, rv);
716 return NS_OK;
719 //---------------------------------------------------------------------------------
720 NS_IMETHODIMP
721 nsPrintEngine::Print(nsIPrintSettings* aPrintSettings,
722 nsIWebProgressListener* aWebProgressListener)
724 return CommonPrint(PR_FALSE, aPrintSettings, aWebProgressListener);
727 NS_IMETHODIMP
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; */
751 NS_IMETHODIMP
752 nsPrintEngine::GetIsFramesetDocument(PRBool *aIsFramesetDocument)
754 nsCOMPtr<nsIDocShell> webContainer(do_QueryInterface(mContainer));
755 *aIsFramesetDocument = IsParentAFrameSet(webContainer);
756 return NS_OK;
759 //----------------------------------------------------------------------------------
760 /* readonly attribute boolean isIFrameSelected; */
761 NS_IMETHODIMP
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);
777 return NS_OK;
780 //----------------------------------------------------------------------------------
781 /* readonly attribute boolean isRangeSelection; */
782 NS_IMETHODIMP
783 nsPrintEngine::GetIsRangeSelection(PRBool *aIsRangeSelection)
785 // Get the currently focused window
786 nsCOMPtr<nsIDOMWindow> currentFocusWin = FindFocusedDOMWindow();
787 *aIsRangeSelection = IsThereARangeSelection(currentFocusWin);
788 return NS_OK;
791 //----------------------------------------------------------------------------------
792 /* readonly attribute boolean isFramesetFrameSelected; */
793 NS_IMETHODIMP
794 nsPrintEngine::GetIsFramesetFrameSelected(PRBool *aIsFramesetFrameSelected)
796 // Get the currently focused window
797 nsCOMPtr<nsIDOMWindow> currentFocusWin = FindFocusedDOMWindow();
798 *aIsFramesetFrameSelected = currentFocusWin != nsnull;
799 return NS_OK;
802 //----------------------------------------------------------------------------------
803 /* readonly attribute long printPreviewNumPages; */
804 NS_IMETHODIMP
805 nsPrintEngine::GetPrintPreviewNumPages(PRInt32 *aPrintPreviewNumPages)
807 NS_ENSURE_ARG_POINTER(aPrintPreviewNumPages);
809 nsIFrame* seqFrame = nsnull;
810 *aPrintPreviewNumPages = 0;
811 if (!mPrtPreview ||
812 NS_FAILED(GetSeqFrameAndCountPagesInternal(mPrtPreview->mPrintObject, seqFrame, *aPrintPreviewNumPages))) {
813 return NS_ERROR_FAILURE;
815 return NS_OK;
818 //----------------------------------------------------------------------------------
819 // Enumerate all the documents for their titles
820 NS_IMETHODIMP
821 nsPrintEngine::EnumerateDocumentNames(PRUint32* aCount,
822 PRUnichar*** aResult)
824 NS_ENSURE_ARG(aCount);
825 NS_ENSURE_ARG_POINTER(aResult);
827 *aCount = 0;
828 *aResult = nsnull;
830 PRInt32 numDocs = mPrt->mPrintDocList->Count();
831 PRUnichar** array = (PRUnichar**) nsMemory::Alloc(numDocs * sizeof(PRUnichar*));
832 if (!array)
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;
847 } else {
848 nsMemory::Free(docURLStr);
850 docURLStr = nsnull;
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);
859 *aCount = numDocs;
860 *aResult = array;
862 return NS_OK;
866 //----------------------------------------------------------------------------------
867 /* readonly attribute nsIPrintSettings globalPrintSettings; */
868 nsresult
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);
879 return rv;
882 //----------------------------------------------------------------------------------
883 /* readonly attribute boolean doingPrint; */
884 NS_IMETHODIMP
885 nsPrintEngine::GetDoingPrint(PRBool *aDoingPrint)
887 NS_ENSURE_ARG_POINTER(aDoingPrint);
888 *aDoingPrint = mIsDoingPrinting;
889 return NS_OK;
892 //----------------------------------------------------------------------------------
893 /* readonly attribute boolean doingPrintPreview; */
894 NS_IMETHODIMP
895 nsPrintEngine::GetDoingPrintPreview(PRBool *aDoingPrintPreview)
897 NS_ENSURE_ARG_POINTER(aDoingPrintPreview);
898 *aDoingPrintPreview = mIsDoingPrintPreview;
899 return NS_OK;
902 //----------------------------------------------------------------------------------
903 /* readonly attribute nsIPrintSettings currentPrintSettings; */
904 NS_IMETHODIMP
905 nsPrintEngine::GetCurrentPrintSettings(nsIPrintSettings * *aCurrentPrintSettings)
907 NS_ENSURE_ARG_POINTER(aCurrentPrintSettings);
909 if (mPrt) {
910 *aCurrentPrintSettings = mPrt->mPrintSettings;
912 } else if (mPrtPreview) {
913 *aCurrentPrintSettings = mPrtPreview->mPrintSettings;
915 } else {
916 *aCurrentPrintSettings = nsnull;
918 NS_IF_ADDREF(*aCurrentPrintSettings);
919 return NS_OK;
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
930 nsresult
931 nsPrintEngine::CheckForPrinters(nsIPrintSettings* aPrintSettings)
933 #ifdef XP_MACOSX
934 // Mac doesn't support retrieving a printer list.
935 return NS_OK;
936 #else
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()) {
943 return NS_OK;
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());
955 return rv;
956 #endif
959 //----------------------------------------------------------------------
960 // Set up to use the "pluggable" Print Progress Dialog
961 void
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();
992 if (!domWin) return;
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);
1003 if (isModal) {
1004 // Showing a print progress dialog when printing a modal window
1005 // isn't supported. See bug 301560.
1006 return;
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),
1015 &aDoNotify);
1016 if (NS_SUCCEEDED(rv)) {
1017 if (printProgressListener && mPrt->mPrintProgressParams) {
1018 mPrt->mPrintProgressListeners.AppendObject(printProgressListener);
1019 SetDocAndURLIntoProgress(mPrt->mPrintObject, mPrt->mPrintProgressParams);
1026 //---------------------------------------------------------------------
1027 PRBool
1028 nsPrintEngine::IsThereARangeSelection(nsIDOMWindow* aDOMWin)
1030 nsCOMPtr<nsIPresShell> presShell;
1031 if (aDOMWin) {
1032 nsCOMPtr<nsPIDOMWindow> window(do_QueryInterface(aDOMWin));
1033 window->GetDocShell()->GetPresShell(getter_AddRefs(presShell));
1036 if (!presShell)
1037 return PR_FALSE;
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);
1043 if (selection) {
1044 PRInt32 count;
1045 selection->GetRangeCount(&count);
1046 if (count == 1) {
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
1050 PRBool isCollapsed;
1051 selection->GetIsCollapsed(&isCollapsed);
1052 return !isCollapsed;
1055 if (count > 1) return PR_TRUE;
1057 return PR_FALSE;
1060 //---------------------------------------------------------------------
1061 PRBool
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
1089 if (shell) {
1090 nsIDocument *doc = shell->GetDocument();
1091 if (doc) {
1092 nsIContent *rootContent = doc->GetRootContent();
1093 if (rootContent) {
1094 isFrameSet = HasFramesetChild(rootContent);
1098 return isFrameSet;
1102 //---------------------------------------------------------------------
1103 // Recursively build a list of sub documents to be printed
1104 // that mirrors the document tree
1105 void
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));
1124 if (viewer) {
1125 nsCOMPtr<nsIContentViewerFile> viewerFile(do_QueryInterface(viewer));
1126 if (viewerFile) {
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);
1131 if (NS_FAILED(rv))
1132 NS_NOTREACHED("Init failed?");
1133 po->mParent = aPO;
1134 aPO->mKids.AppendElement(po);
1135 aDocList->AppendElement(po);
1136 BuildDocTree(childNode, aDocList, po);
1143 //---------------------------------------------------------------------
1144 void
1145 nsPrintEngine::GetDocumentTitleAndURL(nsIDocument* aDoc,
1146 PRUnichar** aTitle,
1147 PRUnichar** aURLStr)
1149 NS_ASSERTION(aDoc, "Pointer is null!");
1150 NS_ASSERTION(aTitle, "Pointer is null!");
1151 NS_ASSERTION(aURLStr, "Pointer is null!");
1153 *aTitle = nsnull;
1154 *aURLStr = nsnull;
1156 const nsAString &docTitle = aDoc->GetDocumentTitle();
1157 if (!docTitle.IsEmpty()) {
1158 *aTitle = ToNewUnicode(docTitle);
1161 nsIURI* url = aDoc->GetDocumentURI();
1162 if (!url) return;
1164 nsCOMPtr<nsIURIFixup> urifixup(do_GetService(NS_URIFIXUP_CONTRACTID));
1165 if (!urifixup) return;
1167 nsCOMPtr<nsIURI> exposableURI;
1168 urifixup->CreateExposableURI(url, getter_AddRefs(exposableURI));
1170 if (!exposableURI) return;
1172 nsCAutoString urlCStr;
1173 exposableURI->GetSpec(urlCStr);
1174 *aURLStr = UTF8ToNewUnicode(urlCStr);
1177 //---------------------------------------------------------------------
1178 // The walks the PO tree and for each document it walks the content
1179 // tree looking for any content that are sub-shells
1181 // It then sets the mContent pointer in the "found" PO object back to the
1182 // the document that contained it.
1183 void
1184 nsPrintEngine::MapContentToWebShells(nsPrintObject* aRootPO,
1185 nsPrintObject* aPO)
1187 NS_ASSERTION(aRootPO, "Pointer is null!");
1188 NS_ASSERTION(aPO, "Pointer is null!");
1190 // Recursively walk the content from the root item
1191 // XXX Would be faster to enumerate the subdocuments, although right now
1192 // nsIDocument doesn't expose quite what would be needed.
1193 MapContentForPO(aPO, aPO->mDocument->GetRootContent());
1195 // Continue recursively walking the chilren of this PO
1196 for (PRInt32 i=0;i<aPO->mKids.Count();i++) {
1197 MapContentToWebShells(aRootPO, (nsPrintObject*)aPO->mKids[i]);
1202 //-------------------------------------------------------
1203 // A Frame's sub-doc may contain content or a FrameSet
1204 // When it contains a FrameSet the mFrameType for the PrintObject
1205 // is always set to an eFrame. Which is fine when printing "AsIs"
1206 // but is incorrect when when printing "Each Frame Separately".
1207 // When printing "Each Frame Separately" the Frame really acts like
1208 // a frameset.
1210 // This method walks the PO tree and checks to see if the PrintObject is
1211 // an eFrame and has children that are eFrames (meaning it's a Frame containing a FrameSet)
1212 // If so, then the mFrameType need to be changed to eFrameSet
1214 // Also note: We only want to call this we are printing "Each Frame Separately"
1215 // when printing "As Is" leave it as an eFrame
1216 void
1217 nsPrintEngine::CheckForChildFrameSets(nsPrintObject* aPO)
1219 NS_ASSERTION(aPO, "Pointer is null!");
1221 // Continue recursively walking the chilren of this PO
1222 PRBool hasChildFrames = PR_FALSE;
1223 for (PRInt32 i=0;i<aPO->mKids.Count();i++) {
1224 nsPrintObject* po = (nsPrintObject*)aPO->mKids[i];
1225 if (po->mFrameType == eFrame) {
1226 hasChildFrames = PR_TRUE;
1227 CheckForChildFrameSets(po);
1231 if (hasChildFrames && aPO->mFrameType == eFrame) {
1232 aPO->mFrameType = eFrameSet;
1236 //---------------------------------------------------------------------
1237 // This method is key to the entire print mechanism.
1239 // This "maps" or figures out which sub-doc represents a
1240 // given Frame or IFrame in its parent sub-doc.
1242 // So the Mcontent pointer in the child sub-doc points to the
1243 // content in the its parent document, that caused it to be printed.
1244 // This is used later to (after reflow) to find the absolute location
1245 // of the sub-doc on its parent's page frame so it can be
1246 // printed in the correct location.
1248 // This method recursvely "walks" the content for a document finding
1249 // all the Frames and IFrames, then sets the "mFrameType" data member
1250 // which tells us what type of PO we have
1251 void
1252 nsPrintEngine::MapContentForPO(nsPrintObject* aPO,
1253 nsIContent* aContent)
1255 NS_PRECONDITION(aPO && aContent, "Null argument");
1257 nsIDocument* doc = aContent->GetDocument();
1259 NS_ASSERTION(doc, "Content without a document from a document tree?");
1261 nsIDocument* subDoc = doc->GetSubDocumentFor(aContent);
1263 if (subDoc) {
1264 nsCOMPtr<nsISupports> container = subDoc->GetContainer();
1265 nsCOMPtr<nsIDocShell> docShell(do_QueryInterface(container));
1267 if (docShell) {
1268 nsPrintObject * po = nsnull;
1269 PRInt32 cnt = aPO->mKids.Count();
1270 for (PRInt32 i=0;i<cnt;i++) {
1271 nsPrintObject* kid = (nsPrintObject*)aPO->mKids.ElementAt(i);
1272 if (kid->mDocument == subDoc) {
1273 po = kid;
1274 break;
1278 // XXX If a subdocument has no onscreen presentation, there will be no PO
1279 // This is even if there should be a print presentation
1280 if (po) {
1281 po->mContent = aContent;
1283 nsCOMPtr<nsIDOMHTMLFrameElement> frame(do_QueryInterface(aContent));
1284 // "frame" elements not in a frameset context should be treated
1285 // as iframes
1286 if (frame && po->mParent->mFrameType == eFrameSet) {
1287 po->mFrameType = eFrame;
1288 } else {
1289 // Assume something iframe-like, i.e. iframe, object, or embed
1290 po->mFrameType = eIFrame;
1291 SetPrintAsIs(po, PR_TRUE);
1292 NS_ASSERTION(po->mParent, "The root must be a parent");
1293 po->mParent->mPrintAsIs = PR_TRUE;
1299 // walk children content
1300 PRUint32 count = aContent->GetChildCount();
1301 for (PRUint32 i = 0; i < count; ++i) {
1302 nsIContent *child = aContent->GetChildAt(i);
1303 MapContentForPO(aPO, child);
1307 //---------------------------------------------------------------------
1308 PRBool
1309 nsPrintEngine::IsThereAnIFrameSelected(nsIDocShell* aDocShell,
1310 nsIDOMWindow* aDOMWin,
1311 PRPackedBool& aIsParentFrameSet)
1313 aIsParentFrameSet = IsParentAFrameSet(aDocShell);
1314 PRBool iFrameIsSelected = PR_FALSE;
1315 if (mPrt && mPrt->mPrintObject) {
1316 nsPrintObject* po = FindPrintObjectByDOMWin(mPrt->mPrintObject, aDOMWin);
1317 iFrameIsSelected = po && po->mFrameType == eIFrame;
1318 } else {
1319 // First, check to see if we are a frameset
1320 if (!aIsParentFrameSet) {
1321 // Check to see if there is a currenlt focused frame
1322 // if so, it means the selected frame is either the main docshell
1323 // or an IFRAME
1324 if (aDOMWin) {
1325 // Get the main docshell's DOMWin to see if it matches
1326 // the frame that is selected
1327 nsCOMPtr<nsIDOMWindow> domWin = do_GetInterface(aDocShell);
1328 if (domWin != aDOMWin) {
1329 iFrameIsSelected = PR_TRUE; // we have a selected IFRAME
1335 return iFrameIsSelected;
1338 //---------------------------------------------------------------------
1339 // Recursively sets all the PO items to be printed
1340 // from the given item down into the tree
1341 void
1342 nsPrintEngine::SetPrintPO(nsPrintObject* aPO, PRBool aPrint)
1344 NS_ASSERTION(aPO, "Pointer is null!");
1346 // Set whether to print flag
1347 aPO->mDontPrint = !aPrint;
1349 for (PRInt32 i=0;i<aPO->mKids.Count();i++) {
1350 SetPrintPO((nsPrintObject*)aPO->mKids[i], aPrint);
1354 //---------------------------------------------------------------------
1355 // This will first use a Title and/or URL from the PrintSettings
1356 // if one isn't set then it uses the one from the document
1357 // then if not title is there we will make sure we send something back
1358 // depending on the situation.
1359 void
1360 nsPrintEngine::GetDisplayTitleAndURL(nsPrintObject* aPO,
1361 PRUnichar** aTitle,
1362 PRUnichar** aURLStr,
1363 eDocTitleDefault aDefType)
1365 NS_ASSERTION(aPO, "Pointer is null!");
1366 NS_ASSERTION(aTitle, "Pointer is null!");
1367 NS_ASSERTION(aURLStr, "Pointer is null!");
1369 *aTitle = nsnull;
1370 *aURLStr = nsnull;
1372 if (!mPrt)
1373 return;
1375 // First check to see if the PrintSettings has defined an alternate title
1376 // and use that if it did
1377 PRUnichar * docTitleStrPS = nsnull;
1378 PRUnichar * docURLStrPS = nsnull;
1379 if (mPrt->mPrintSettings) {
1380 mPrt->mPrintSettings->GetTitle(&docTitleStrPS);
1381 mPrt->mPrintSettings->GetDocURL(&docURLStrPS);
1383 if (docTitleStrPS && *docTitleStrPS) {
1384 *aTitle = docTitleStrPS;
1387 if (docURLStrPS && *docURLStrPS) {
1388 *aURLStr = docURLStrPS;
1391 // short circut
1392 if (docTitleStrPS && docURLStrPS) {
1393 return;
1397 PRUnichar* docTitle;
1398 PRUnichar* docUrl;
1399 GetDocumentTitleAndURL(aPO->mDocument, &docTitle, &docUrl);
1401 if (docUrl) {
1402 if (!docURLStrPS)
1403 *aURLStr = docUrl;
1404 else
1405 nsMemory::Free(docUrl);
1408 if (docTitle) {
1409 if (!docTitleStrPS)
1410 *aTitle = docTitle;
1411 else
1412 nsMemory::Free(docTitle);
1413 } else if (!docTitleStrPS) {
1414 switch (aDefType) {
1415 case eDocTitleDefBlank: *aTitle = ToNewUnicode(EmptyString());
1416 break;
1418 case eDocTitleDefURLDoc:
1419 if (*aURLStr) {
1420 *aTitle = NS_strdup(*aURLStr);
1421 } else if (mPrt->mBrandName) {
1422 *aTitle = NS_strdup(mPrt->mBrandName);
1424 break;
1429 //---------------------------------------------------------------------
1430 nsresult nsPrintEngine::DocumentReadyForPrinting()
1432 if (mPrt->mPrintFrameType == nsIPrintSettings::kEachFrameSep) {
1433 CheckForChildFrameSets(mPrt->mPrintObject);
1437 // Send the document to the printer...
1439 nsresult rv = SetupToPrintContent();
1440 if (NS_FAILED(rv)) {
1441 // The print job was canceled or there was a problem
1442 // So remove all other documents from the print list
1443 DonePrintingPages(nsnull, rv);
1445 return rv;
1448 /** ---------------------------------------------------
1449 * Cleans up when an error occurred
1451 nsresult nsPrintEngine::CleanupOnFailure(nsresult aResult, PRBool aIsPrinting)
1453 PR_PL(("**** Failed %s - rv 0x%X", aIsPrinting?"Printing":"Print Preview", aResult));
1455 /* cleanup... */
1456 if (mPagePrintTimer) {
1457 mPagePrintTimer->Stop();
1458 NS_RELEASE(mPagePrintTimer);
1461 if (aIsPrinting) {
1462 SetIsPrinting(PR_FALSE);
1463 } else {
1464 SetIsPrintPreview(PR_FALSE);
1465 SetIsCreatingPrintPreview(PR_FALSE);
1468 /* cleanup done, let's fire-up an error dialog to notify the user
1469 * what went wrong...
1471 * When rv == NS_ERROR_ABORT, it means we want out of the
1472 * print job without displaying any error messages
1474 if (aResult != NS_ERROR_ABORT) {
1475 ShowPrintErrorDialog(aResult, aIsPrinting);
1478 FirePrintCompletionEvent();
1480 return aResult;
1484 //---------------------------------------------------------------------
1485 void
1486 nsPrintEngine::ShowPrintErrorDialog(nsresult aPrintError, PRBool aIsPrinting)
1489 PR_PL(("nsPrintEngine::ShowPrintErrorDialog(nsresult aPrintError=%lx, PRBool aIsPrinting=%d)\n", (long)aPrintError, (int)aIsPrinting));
1491 nsCAutoString stringName;
1493 switch(aPrintError)
1495 #define NS_ERROR_TO_LOCALIZED_PRINT_ERROR_MSG(nserr) case nserr: stringName.AssignLiteral(#nserr); break;
1496 NS_ERROR_TO_LOCALIZED_PRINT_ERROR_MSG(NS_ERROR_GFX_PRINTER_CMD_NOT_FOUND)
1497 NS_ERROR_TO_LOCALIZED_PRINT_ERROR_MSG(NS_ERROR_GFX_PRINTER_CMD_FAILURE)
1498 NS_ERROR_TO_LOCALIZED_PRINT_ERROR_MSG(NS_ERROR_GFX_PRINTER_NO_PRINTER_AVAILABLE)
1499 NS_ERROR_TO_LOCALIZED_PRINT_ERROR_MSG(NS_ERROR_GFX_PRINTER_NAME_NOT_FOUND)
1500 NS_ERROR_TO_LOCALIZED_PRINT_ERROR_MSG(NS_ERROR_GFX_PRINTER_ACCESS_DENIED)
1501 NS_ERROR_TO_LOCALIZED_PRINT_ERROR_MSG(NS_ERROR_GFX_PRINTER_INVALID_ATTRIBUTE)
1502 NS_ERROR_TO_LOCALIZED_PRINT_ERROR_MSG(NS_ERROR_GFX_PRINTER_PRINTER_NOT_READY)
1503 NS_ERROR_TO_LOCALIZED_PRINT_ERROR_MSG(NS_ERROR_GFX_PRINTER_OUT_OF_PAPER)
1504 NS_ERROR_TO_LOCALIZED_PRINT_ERROR_MSG(NS_ERROR_GFX_PRINTER_PRINTER_IO_ERROR)
1505 NS_ERROR_TO_LOCALIZED_PRINT_ERROR_MSG(NS_ERROR_GFX_PRINTER_COULD_NOT_OPEN_FILE)
1506 NS_ERROR_TO_LOCALIZED_PRINT_ERROR_MSG(NS_ERROR_GFX_PRINTER_FILE_IO_ERROR)
1507 NS_ERROR_TO_LOCALIZED_PRINT_ERROR_MSG(NS_ERROR_GFX_PRINTER_PRINTPREVIEW)
1508 NS_ERROR_TO_LOCALIZED_PRINT_ERROR_MSG(NS_ERROR_UNEXPECTED)
1509 NS_ERROR_TO_LOCALIZED_PRINT_ERROR_MSG(NS_ERROR_OUT_OF_MEMORY)
1510 NS_ERROR_TO_LOCALIZED_PRINT_ERROR_MSG(NS_ERROR_NOT_IMPLEMENTED)
1511 NS_ERROR_TO_LOCALIZED_PRINT_ERROR_MSG(NS_ERROR_NOT_AVAILABLE)
1512 NS_ERROR_TO_LOCALIZED_PRINT_ERROR_MSG(NS_ERROR_ABORT)
1513 NS_ERROR_TO_LOCALIZED_PRINT_ERROR_MSG(NS_ERROR_GFX_PRINTER_STARTDOC)
1514 NS_ERROR_TO_LOCALIZED_PRINT_ERROR_MSG(NS_ERROR_GFX_PRINTER_ENDDOC)
1515 NS_ERROR_TO_LOCALIZED_PRINT_ERROR_MSG(NS_ERROR_GFX_PRINTER_STARTPAGE)
1516 NS_ERROR_TO_LOCALIZED_PRINT_ERROR_MSG(NS_ERROR_GFX_PRINTER_ENDPAGE)
1517 NS_ERROR_TO_LOCALIZED_PRINT_ERROR_MSG(NS_ERROR_GFX_PRINTER_PRINT_WHILE_PREVIEW)
1518 NS_ERROR_TO_LOCALIZED_PRINT_ERROR_MSG(NS_ERROR_GFX_PRINTER_PAPER_SIZE_NOT_SUPPORTED)
1519 NS_ERROR_TO_LOCALIZED_PRINT_ERROR_MSG(NS_ERROR_GFX_PRINTER_ORIENTATION_NOT_SUPPORTED)
1520 NS_ERROR_TO_LOCALIZED_PRINT_ERROR_MSG(NS_ERROR_GFX_PRINTER_COLORSPACE_NOT_SUPPORTED)
1521 NS_ERROR_TO_LOCALIZED_PRINT_ERROR_MSG(NS_ERROR_GFX_PRINTER_TOO_MANY_COPIES)
1522 NS_ERROR_TO_LOCALIZED_PRINT_ERROR_MSG(NS_ERROR_GFX_PRINTER_DRIVER_CONFIGURATION_ERROR)
1523 NS_ERROR_TO_LOCALIZED_PRINT_ERROR_MSG(NS_ERROR_GFX_PRINTER_DOC_IS_BUSY_PP)
1524 NS_ERROR_TO_LOCALIZED_PRINT_ERROR_MSG(NS_ERROR_GFX_PRINTER_DOC_WAS_DESTORYED)
1525 NS_ERROR_TO_LOCALIZED_PRINT_ERROR_MSG(NS_ERROR_GFX_NO_PRINTDIALOG_IN_TOOLKIT)
1526 NS_ERROR_TO_LOCALIZED_PRINT_ERROR_MSG(NS_ERROR_GFX_NO_PRINTROMPTSERVICE)
1527 NS_ERROR_TO_LOCALIZED_PRINT_ERROR_MSG(NS_ERROR_GFX_PRINTER_NO_XUL) // Temporary code for Bug 136185 / bug 240490
1528 NS_ERROR_TO_LOCALIZED_PRINT_ERROR_MSG(NS_ERROR_GFX_PRINTER_PLEX_NOT_SUPPORTED)
1529 NS_ERROR_TO_LOCALIZED_PRINT_ERROR_MSG(NS_ERROR_GFX_PRINTER_DOC_IS_BUSY)
1530 NS_ERROR_TO_LOCALIZED_PRINT_ERROR_MSG(NS_ERROR_GFX_PRINTING_NOT_IMPLEMENTED)
1531 NS_ERROR_TO_LOCALIZED_PRINT_ERROR_MSG(NS_ERROR_GFX_COULD_NOT_LOAD_PRINT_MODULE)
1532 NS_ERROR_TO_LOCALIZED_PRINT_ERROR_MSG(NS_ERROR_GFX_PRINTER_RESOLUTION_NOT_SUPPORTED)
1534 default:
1535 NS_ERROR_TO_LOCALIZED_PRINT_ERROR_MSG(NS_ERROR_FAILURE)
1536 #undef NS_ERROR_TO_LOCALIZED_PRINT_ERROR_MSG
1539 PR_PL(("ShowPrintErrorDialog: stringName='%s'\n", stringName.get()));
1541 nsXPIDLString msg, title;
1542 nsresult rv =
1543 nsContentUtils::GetLocalizedString(nsContentUtils::ePRINTING_PROPERTIES,
1544 stringName.get(), msg);
1545 if (NS_FAILED(rv)) {
1546 PR_PL(("GetLocalizedString failed\n"));
1547 return;
1550 rv = nsContentUtils::GetLocalizedString(nsContentUtils::ePRINTING_PROPERTIES,
1551 aIsPrinting ? "print_error_dialog_title"
1552 : "printpreview_error_dialog_title",
1553 title);
1555 nsCOMPtr<nsIWindowWatcher> wwatch = do_GetService(NS_WINDOWWATCHER_CONTRACTID, &rv);
1556 if (NS_FAILED(rv)) {
1557 PR_PL(("ShowPrintErrorDialog(): wwatch==nsnull\n"));
1558 return;
1561 nsCOMPtr<nsIDOMWindow> active;
1562 wwatch->GetActiveWindow(getter_AddRefs(active));
1564 nsCOMPtr<nsIPrompt> dialog;
1565 /* |GetNewPrompter| allows that |active| is |nsnull|
1566 * (see bug 234982 ("nsPrintEngine::ShowPrintErrorDialog() fails in many cases")) */
1567 wwatch->GetNewPrompter(active, getter_AddRefs(dialog));
1568 if (!dialog) {
1569 PR_PL(("ShowPrintErrorDialog(): dialog==nsnull\n"));
1570 return;
1573 dialog->Alert(title.get(), msg.get());
1574 PR_PL(("ShowPrintErrorDialog(): alert displayed successfully.\n"));
1577 //-----------------------------------------------------------------
1578 //-- Section: Reflow Methods
1579 //-----------------------------------------------------------------
1581 //-------------------------------------------------------
1582 nsresult
1583 nsPrintEngine::SetupToPrintContent()
1585 // In this step we figure out which documents should be printed
1586 // i.e. if we are printing the selection then only enable that nsPrintObject
1587 // for printing
1588 if (NS_FAILED(EnablePOsForPrinting())) {
1589 return NS_ERROR_FAILURE;
1591 DUMP_DOC_LIST("\nAfter Enable------------------------------------------");
1593 // This is an Optimization
1594 // If we are in PP then we already know all the shrinkage information
1595 // so just transfer it to the PrintData and we will skip the extra shrinkage reflow
1597 // doSetPixelScale tells Reflow whether to set the shrinkage value into the DC
1598 // The first time we do not want to do this, the second time through we do
1599 PRBool doSetPixelScale = PR_FALSE;
1600 PRBool ppIsShrinkToFit = mPrtPreview && mPrtPreview->mShrinkToFit;
1601 if (ppIsShrinkToFit) {
1602 mPrt->mShrinkRatio = mPrtPreview->mShrinkRatio;
1603 doSetPixelScale = PR_TRUE;
1606 // Here we reflow all the PrintObjects
1607 nsresult rv = ReflowDocList(mPrt->mPrintObject, doSetPixelScale);
1608 if (NS_FAILED(rv)) {
1609 return NS_ERROR_FAILURE;
1612 // Here is where we do the extra reflow for shrinking the content
1613 // But skip this step if we are in PrintPreview
1614 if (mPrt->mShrinkToFit && !ppIsShrinkToFit) {
1615 // Now look for the PO that has the smallest percent for shrink to fit
1616 if (mPrt->mPrintDocList->Count() > 1 && mPrt->mPrintObject->mFrameType == eFrameSet) {
1617 nsPrintObject* smallestPO = FindSmallestSTF();
1618 NS_ASSERTION(smallestPO, "There must always be an XMost PO!");
1619 if (smallestPO) {
1620 // Calc the shrinkage based on the entire content area
1621 mPrt->mShrinkRatio = smallestPO->mShrinkRatio;
1623 } else {
1624 // Single document so use the Shrink as calculated for the PO
1625 mPrt->mShrinkRatio = mPrt->mPrintObject->mShrinkRatio;
1628 // Only Shrink if we are smaller
1629 if (mPrt->mShrinkRatio < 0.998f) {
1630 // Clamp Shrink to Fit to 60%
1631 mPrt->mShrinkRatio = PR_MAX(mPrt->mShrinkRatio, 0.60f);
1633 for (PRInt32 i=0;i<mPrt->mPrintDocList->Count();i++) {
1634 nsPrintObject* po = (nsPrintObject*)mPrt->mPrintDocList->ElementAt(i);
1635 NS_ASSERTION(po, "nsPrintObject can't be null!");
1636 // Wipe out the presentation before we reflow
1637 po->DestroyPresentation();
1640 #if (defined(XP_WIN) || defined(XP_OS2)) && defined(EXTENDED_DEBUG_PRINTING)
1641 // We need to clear all the output files here
1642 // because they will be re-created with second reflow of the docs
1643 if (kPrintingLogMod && kPrintingLogMod->level == DUMP_LAYOUT_LEVEL) {
1644 RemoveFilesInDir(".\\");
1645 gDumpFileNameCnt = 0;
1646 gDumpLOFileNameCnt = 0;
1648 #endif
1650 // Here we reflow all the PrintObjects a second time
1651 // this time using the shrinkage values
1652 // The last param here tells reflow to NOT calc the shrinkage values
1653 if (NS_FAILED(ReflowDocList(mPrt->mPrintObject, PR_TRUE))) {
1654 return NS_ERROR_FAILURE;
1658 #ifdef PR_LOGGING
1660 float calcRatio = 0.0f;
1661 if (mPrt->mPrintDocList->Count() > 1 && mPrt->mPrintObject->mFrameType == eFrameSet) {
1662 nsPrintObject* smallestPO = FindSmallestSTF();
1663 NS_ASSERTION(smallestPO, "There must always be an XMost PO!");
1664 if (smallestPO) {
1665 // Calc the shrinkage based on the entire content area
1666 calcRatio = smallestPO->mShrinkRatio;
1668 } else {
1669 // Single document so use the Shrink as calculated for the PO
1670 calcRatio = mPrt->mPrintObject->mShrinkRatio;
1672 PR_PL(("**************************************************************************\n"));
1673 PR_PL(("STF Ratio is: %8.5f Effective Ratio: %8.5f Diff: %8.5f\n", mPrt->mShrinkRatio, calcRatio, mPrt->mShrinkRatio-calcRatio));
1674 PR_PL(("**************************************************************************\n"));
1676 #endif
1679 DUMP_DOC_LIST(("\nAfter Reflow------------------------------------------"));
1680 PR_PL(("\n"));
1681 PR_PL(("-------------------------------------------------------\n"));
1682 PR_PL(("\n"));
1684 CalcNumPrintablePages(mPrt->mNumPrintablePages);
1686 PR_PL(("--- Printing %d pages\n", mPrt->mNumPrintablePages));
1687 DUMP_DOC_TREELAYOUT;
1689 // Print listener setup...
1690 if (mPrt != nsnull) {
1691 mPrt->OnStartPrinting();
1694 PRUnichar* fileName = nsnull;
1695 // check to see if we are printing to a file
1696 PRBool isPrintToFile = PR_FALSE;
1697 mPrt->mPrintSettings->GetPrintToFile(&isPrintToFile);
1698 if (isPrintToFile) {
1699 // On some platforms The BeginDocument needs to know the name of the file
1700 // and it uses the PrintService to get it, so we need to set it into the PrintService here
1701 mPrt->mPrintSettings->GetToFileName(&fileName);
1704 PRUnichar * docTitleStr;
1705 PRUnichar * docURLStr;
1706 GetDisplayTitleAndURL(mPrt->mPrintObject, &docTitleStr, &docURLStr, eDocTitleDefURLDoc);
1708 PRInt32 startPage = 1;
1709 PRInt32 endPage = mPrt->mNumPrintablePages;
1711 PRInt16 printRangeType = nsIPrintSettings::kRangeAllPages;
1712 mPrt->mPrintSettings->GetPrintRange(&printRangeType);
1713 if (printRangeType == nsIPrintSettings::kRangeSpecifiedPageRange) {
1714 mPrt->mPrintSettings->GetStartPageRange(&startPage);
1715 mPrt->mPrintSettings->GetEndPageRange(&endPage);
1716 if (endPage > mPrt->mNumPrintablePages) {
1717 endPage = mPrt->mNumPrintablePages;
1721 rv = NS_OK;
1722 // BeginDocument may pass back a FAILURE code
1723 // i.e. On Windows, if you are printing to a file and hit "Cancel"
1724 // to the "File Name" dialog, this comes back as an error
1725 // Don't start printing when regression test are executed
1726 if (!mPrt->mDebugFilePtr && mIsDoingPrinting) {
1727 rv = mPrt->mPrintDC->BeginDocument(docTitleStr, fileName, startPage, endPage);
1730 if (mIsCreatingPrintPreview) {
1731 // Print Preview -- Pass ownership of docTitleStr and docURLStr
1732 // to the pageSequenceFrame, to be displayed in the header
1733 nsIPageSequenceFrame *seqFrame = nsnull;
1734 mPrt->mPrintObject->mPresShell->GetPageSequenceFrame(&seqFrame);
1735 if (seqFrame) {
1736 seqFrame->StartPrint(mPrt->mPrintObject->mPresContext,
1737 mPrt->mPrintSettings, docTitleStr, docURLStr);
1739 } else {
1740 if (docTitleStr) nsMemory::Free(docTitleStr);
1741 if (docURLStr) nsMemory::Free(docURLStr);
1744 PR_PL(("****************** Begin Document ************************\n"));
1746 NS_ENSURE_SUCCESS(rv, rv);
1748 // This will print the docshell document
1749 // when it completes asynchronously in the DonePrintingPages method
1750 // it will check to see if there are more docshells to be printed and
1751 // then PrintDocContent will be called again.
1753 if (mIsDoingPrinting) {
1754 PrintDocContent(mPrt->mPrintObject, rv); // ignore return value
1757 return rv;
1760 //-------------------------------------------------------
1761 // Recursively reflow each sub-doc and then calc
1762 // all the frame locations of the sub-docs
1763 nsresult
1764 nsPrintEngine::ReflowDocList(nsPrintObject* aPO, PRBool aSetPixelScale)
1766 NS_ENSURE_ARG_POINTER(aPO);
1768 // Check to see if the subdocument's element has been hidden by the parent document
1769 if (aPO->mParent && aPO->mParent->mPresShell) {
1770 nsIFrame * frame =
1771 aPO->mParent->mPresShell->GetPrimaryFrameFor(aPO->mContent);
1772 if (frame) {
1773 if (!frame->GetStyleVisibility()->IsVisible()) {
1774 aPO->mDontPrint = PR_TRUE;
1775 aPO->mInvisible = PR_TRUE;
1776 return NS_OK;
1781 // Here is where we set the shrinkage value into the DC
1782 // and this is what actually makes it shrink
1783 if (aSetPixelScale && aPO->mFrameType != eIFrame) {
1784 float ratio;
1785 if (mPrt->mPrintFrameType == nsIPrintSettings::kFramesAsIs || mPrt->mPrintFrameType == nsIPrintSettings::kNoFrames) {
1786 ratio = mPrt->mShrinkRatio - 0.005f; // round down
1787 } else {
1788 ratio = aPO->mShrinkRatio - 0.005f; // round down
1790 aPO->mZoomRatio = ratio;
1791 } else if (!mPrt->mShrinkToFit) {
1792 double scaling;
1793 mPrt->mPrintSettings->GetScaling(&scaling);
1794 aPO->mZoomRatio = float(scaling);
1797 nsresult rv;
1798 // Reflow the PO
1799 rv = ReflowPrintObject(aPO);
1800 NS_ENSURE_SUCCESS(rv, rv);
1802 PRInt32 cnt = aPO->mKids.Count();
1803 for (PRInt32 i=0;i<cnt;i++) {
1804 rv = ReflowDocList((nsPrintObject *)aPO->mKids[i], aSetPixelScale);
1805 NS_ENSURE_SUCCESS(rv, rv);
1807 return NS_OK;
1810 //-------------------------------------------------------
1811 // Reflow a nsPrintObject
1812 nsresult
1813 nsPrintEngine::ReflowPrintObject(nsPrintObject * aPO)
1815 NS_ASSERTION(aPO, "Pointer is null!");
1816 if (!aPO) return NS_ERROR_FAILURE;
1818 nsSize adjSize;
1819 PRBool documentIsTopLevel;
1820 nsIFrame* frame = nsnull;
1821 if (!aPO->IsPrintable())
1822 return NS_OK;
1824 if (aPO->mParent && aPO->mParent->IsPrintable()) {
1825 if (aPO->mParent->mPresShell) {
1826 frame = aPO->mParent->mPresShell->FrameManager()->
1827 GetPrimaryFrameFor(aPO->mContent, -1);
1829 // Without a frame, this document can't be displayed; therefore, there is no
1830 // point to reflowing it
1831 if (!frame)
1832 return NS_OK;
1834 adjSize = frame->GetContentRect().Size();
1835 documentIsTopLevel = PR_FALSE;
1836 // presshell exists because parent is printable
1837 } else {
1838 nscoord pageWidth, pageHeight;
1839 mPrt->mPrintDC->GetDeviceSurfaceDimensions(pageWidth, pageHeight);
1840 #if defined(XP_UNIX) && !defined(XP_MACOSX)
1841 // If we're in landscape mode on Linux, the device surface will have
1842 // been rotated, so for the purposes of reflowing content, we'll
1843 // treat device's height as our width and its width as our height,
1844 PRInt32 orientation;
1845 mPrt->mPrintSettings->GetOrientation(&orientation);
1846 if (nsIPrintSettings::kLandscapeOrientation == orientation) {
1847 adjSize = nsSize(pageHeight, pageWidth);
1848 } else {
1849 adjSize = nsSize(pageWidth, pageHeight);
1851 #else
1852 adjSize = nsSize(pageWidth, pageHeight);
1853 #endif // XP_UNIX && !XP_MACOSX
1854 documentIsTopLevel = PR_TRUE;
1857 // create the PresContext
1858 aPO->mPresContext = new nsPresContext(aPO->mDocument,
1859 mIsCreatingPrintPreview ?
1860 nsPresContext::eContext_PrintPreview:
1861 nsPresContext::eContext_Print);
1862 NS_ENSURE_TRUE(aPO->mPresContext, NS_ERROR_OUT_OF_MEMORY);
1863 aPO->mPresContext->SetPrintSettings(mPrt->mPrintSettings);
1865 // set the presentation context to the value in the print settings
1866 PRBool printBGColors;
1867 mPrt->mPrintSettings->GetPrintBGColors(&printBGColors);
1868 aPO->mPresContext->SetBackgroundColorDraw(printBGColors);
1869 mPrt->mPrintSettings->GetPrintBGImages(&printBGColors);
1870 aPO->mPresContext->SetBackgroundImageDraw(printBGColors);
1872 // init it with the DC
1873 nsresult rv = aPO->mPresContext->Init(mPrt->mPrintDC);
1874 NS_ENSURE_SUCCESS(rv, rv);
1876 aPO->mViewManager = do_CreateInstance(kViewManagerCID, &rv);
1877 NS_ENSURE_SUCCESS(rv,rv);
1879 rv = aPO->mViewManager->Init(mPrt->mPrintDC);
1880 NS_ENSURE_SUCCESS(rv,rv);
1882 nsStyleSet* styleSet;
1883 rv = mDocViewerPrint->CreateStyleSet(aPO->mDocument, &styleSet);
1884 NS_ENSURE_SUCCESS(rv, rv);
1886 rv = aPO->mDocument->CreateShell(aPO->mPresContext, aPO->mViewManager,
1887 styleSet, getter_AddRefs(aPO->mPresShell));
1888 if (NS_FAILED(rv)) {
1889 delete styleSet;
1890 return rv;
1893 styleSet->EndUpdate();
1895 // The pres shell now owns the style set object.
1897 PR_PL(("In DV::ReflowPrintObject PO: %p (%9s) Setting w,h to %d,%d\n", aPO,
1898 gFrameTypesStr[aPO->mFrameType], adjSize.width, adjSize.height));
1900 // Here we decide whether we need scrollbars and
1901 // what the parent will be of the widget
1902 // How this logic presently works: Print Preview is always as-is (as far
1903 // as I can tell; not sure how it would work in other cases); only the root
1904 // is not eIFrame or eFrame. The child documents get a parent widget from
1905 // logic in nsFrameFrame. In any case, a child widget is created for the root
1906 // view of the document.
1907 PRBool canCreateScrollbars = PR_FALSE;
1908 nsIView* parentView;
1909 // the top nsPrintObject's widget will always have scrollbars
1910 if (frame) {
1911 nsIView* view = frame->GetView();
1912 NS_ENSURE_TRUE(view, NS_ERROR_FAILURE);
1913 view = view->GetFirstChild();
1914 NS_ENSURE_TRUE(view, NS_ERROR_FAILURE);
1915 parentView = view;
1916 } else {
1917 canCreateScrollbars = PR_TRUE;
1918 parentView = nsnull;
1921 // Create a child window of the parent that is our "root view/window"
1922 nsRect tbounds = nsRect(nsPoint(0, 0), adjSize);
1923 nsIView* rootView = aPO->mViewManager->CreateView(tbounds, parentView);
1924 NS_ENSURE_TRUE(rootView, NS_ERROR_OUT_OF_MEMORY);
1926 // Only create a widget for print preview; when printing, a widget is
1927 // unnecessary and unexpected
1928 // Also, no widget should be needed except for the top-level document
1929 if (mIsCreatingPrintPreview && documentIsTopLevel) {
1930 nsNativeWidget widget = nsnull;
1931 if (!frame)
1932 widget = mParentWidget->GetNativeData(NS_NATIVE_WIDGET);
1933 rv = rootView->CreateWidget(kWidgetCID, nsnull,
1934 widget, PR_TRUE, PR_TRUE,
1935 eContentTypeContent);
1936 NS_ENSURE_SUCCESS(rv, rv);
1937 aPO->mWindow = rootView->GetWidget();
1938 aPO->mPresContext->SetPaginatedScrolling(canCreateScrollbars);
1941 // Setup hierarchical relationship in view manager
1942 aPO->mViewManager->SetRootView(rootView);
1944 // This docshell stuff is weird; will go away when we stop having multiple
1945 // presentations per document
1946 nsCOMPtr<nsISupports> supps(do_QueryInterface(aPO->mDocShell));
1947 aPO->mPresContext->SetContainer(supps);
1949 aPO->mPresShell->BeginObservingDocument();
1951 aPO->mPresContext->SetPageSize(adjSize);
1952 aPO->mPresContext->SetIsRootPaginatedDocument(documentIsTopLevel);
1953 aPO->mPresContext->SetPageScale(aPO->mZoomRatio);
1954 // Calculate scale factor from printer to screen
1955 float printDPI = float(mPrt->mPrintDC->AppUnitsPerInch()) /
1956 float(mPrt->mPrintDC->AppUnitsPerDevPixel());
1957 float screenDPI = float(mDeviceContext->AppUnitsPerInch()) /
1958 float(mDeviceContext->AppUnitsPerDevPixel());
1959 aPO->mPresContext->SetPrintPreviewScale(screenDPI / printDPI);
1961 rv = aPO->mPresShell->InitialReflow(adjSize.width, adjSize.height);
1963 NS_ENSURE_SUCCESS(rv, rv);
1964 NS_ASSERTION(aPO->mPresShell, "Presshell should still be here");
1966 // Process the reflow event InitialReflow posted
1967 aPO->mPresShell->FlushPendingNotifications(Flush_Layout);
1969 nsCOMPtr<nsIPresShell> displayShell;
1970 aPO->mDocShell->GetPresShell(getter_AddRefs(displayShell));
1971 // Transfer Selection Ranges to the new Print PresShell
1972 nsCOMPtr<nsISelection> selection, selectionPS;
1973 // It's okay if there is no display shell, just skip copying the selection
1974 if (displayShell) {
1975 selection = displayShell->GetCurrentSelection(nsISelectionController::SELECTION_NORMAL);
1977 selectionPS = aPO->mPresShell->GetCurrentSelection(nsISelectionController::SELECTION_NORMAL);
1978 if (selection && selectionPS) {
1979 PRInt32 cnt;
1980 selection->GetRangeCount(&cnt);
1981 PRInt32 inx;
1982 for (inx=0;inx<cnt;inx++) {
1983 nsCOMPtr<nsIDOMRange> range;
1984 if (NS_SUCCEEDED(selection->GetRangeAt(inx, getter_AddRefs(range))))
1985 selectionPS->AddRange(range);
1989 // If we are trying to shrink the contents to fit on the page
1990 // we must first locate the "pageContent" frame
1991 // Then we walk the frame tree and look for the "xmost" frame
1992 // this is the frame where the right-hand side of the frame extends
1993 // the furthest
1994 if (mPrt->mShrinkToFit && documentIsTopLevel) {
1995 nsIPageSequenceFrame* pageSequence;
1996 aPO->mPresShell->GetPageSequenceFrame(&pageSequence);
1997 pageSequence->GetSTFPercent(aPO->mShrinkRatio);
2000 #ifdef EXTENDED_DEBUG_PRINTING
2001 if (kPrintingLogMod && kPrintingLogMod->level == DUMP_LAYOUT_LEVEL) {
2002 char * docStr;
2003 char * urlStr;
2004 GetDocTitleAndURL(aPO, docStr, urlStr);
2005 char filename[256];
2006 sprintf(filename, "print_dump_%d.txt", gDumpFileNameCnt++);
2007 // Dump all the frames and view to a a file
2008 FILE * fd = fopen(filename, "w");
2009 if (fd) {
2010 nsIFrame *theRootFrame =
2011 aPO->mPresShell->FrameManager()->GetRootFrame();
2012 fprintf(fd, "Title: %s\n", docStr?docStr:"");
2013 fprintf(fd, "URL: %s\n", urlStr?urlStr:"");
2014 fprintf(fd, "--------------- Frames ----------------\n");
2015 nsCOMPtr<nsIRenderingContext> renderingContext;
2016 mPrt->mPrintDocDC->CreateRenderingContext(*getter_AddRefs(renderingContext));
2017 RootFrameList(aPO->mPresContext, fd, 0);
2018 //DumpFrames(fd, aPO->mPresContext, renderingContext, theRootFrame, 0);
2019 fprintf(fd, "---------------------------------------\n\n");
2020 fprintf(fd, "--------------- Views From Root Frame----------------\n");
2021 nsIView* v = theRootFrame->GetView();
2022 if (v) {
2023 v->List(fd);
2024 } else {
2025 printf("View is null!\n");
2027 if (docShell) {
2028 fprintf(fd, "--------------- All Views ----------------\n");
2029 DumpViews(docShell, fd);
2030 fprintf(fd, "---------------------------------------\n\n");
2032 fclose(fd);
2034 if (docStr) nsMemory::Free(docStr);
2035 if (urlStr) nsMemory::Free(urlStr);
2037 #endif
2039 return NS_OK;
2042 //-------------------------------------------------------
2043 // Figure out how many documents and how many total pages we are printing
2044 void
2045 nsPrintEngine::CalcNumPrintablePages(PRInt32& aNumPages)
2047 aNumPages = 0;
2048 // Count the number of printable documents
2049 // and printable pages
2050 PRInt32 i;
2051 for (i=0; i<mPrt->mPrintDocList->Count(); i++) {
2052 nsPrintObject* po = (nsPrintObject*)mPrt->mPrintDocList->ElementAt(i);
2053 NS_ASSERTION(po, "nsPrintObject can't be null!");
2054 if (po->mPresContext && po->mPresContext->IsRootPaginatedDocument()) {
2055 nsIPageSequenceFrame* pageSequence;
2056 po->mPresShell->GetPageSequenceFrame(&pageSequence);
2057 nsIFrame * seqFrame;
2058 if (NS_SUCCEEDED(CallQueryInterface(pageSequence, &seqFrame))) {
2059 nsIFrame* frame = seqFrame->GetFirstChild(nsnull);
2060 while (frame) {
2061 aNumPages++;
2062 frame = frame->GetNextSibling();
2068 //-----------------------------------------------------------------
2069 //-- Done: Reflow Methods
2070 //-----------------------------------------------------------------
2072 //-----------------------------------------------------------------
2073 //-- Section: Printing Methods
2074 //-----------------------------------------------------------------
2076 //-------------------------------------------------------
2077 // Called for each DocShell that needs to be printed
2078 PRBool
2079 nsPrintEngine::PrintDocContent(nsPrintObject* aPO, nsresult& aStatus)
2081 NS_ASSERTION(aPO, "Pointer is null!");
2082 aStatus = NS_OK;
2084 if (!aPO->mHasBeenPrinted && aPO->IsPrintable()) {
2085 aStatus = DoPrint(aPO);
2086 return PR_TRUE;
2089 // If |aPO->mPrintAsIs| and |aPO->mHasBeenPrinted| are true,
2090 // the kids frames are already processed in |PrintPage|.
2091 if (!aPO->mInvisible && !(aPO->mPrintAsIs && aPO->mHasBeenPrinted)) {
2092 for (PRInt32 i=0;i<aPO->mKids.Count();i++) {
2093 nsPrintObject* po = (nsPrintObject*)aPO->mKids[i];
2094 PRBool printed = PrintDocContent(po, aStatus);
2095 if (printed || NS_FAILED(aStatus)) {
2096 return PR_TRUE;
2100 return PR_FALSE;
2103 //-------------------------------------------------------
2104 nsresult
2105 nsPrintEngine::DoPrint(nsPrintObject * aPO)
2107 PR_PL(("\n"));
2108 PR_PL(("**************************** %s ****************************\n", gFrameTypesStr[aPO->mFrameType]));
2109 PR_PL(("****** In DV::DoPrint PO: %p \n", aPO));
2111 nsIPresShell* poPresShell = aPO->mPresShell;
2112 nsPresContext* poPresContext = aPO->mPresContext;
2114 NS_ASSERTION(poPresContext, "PrintObject has not been reflowed");
2115 NS_ASSERTION(poPresContext->Type() != nsPresContext::eContext_PrintPreview,
2116 "How did this context end up here?");
2118 if (mPrt->mPrintProgressParams) {
2119 SetDocAndURLIntoProgress(aPO, mPrt->mPrintProgressParams);
2123 PRInt16 printRangeType = nsIPrintSettings::kRangeAllPages;
2124 nsresult rv;
2125 if (mPrt->mPrintSettings != nsnull) {
2126 mPrt->mPrintSettings->GetPrintRange(&printRangeType);
2129 // Ask the page sequence frame to print all the pages
2130 nsIPageSequenceFrame* pageSequence;
2131 poPresShell->GetPageSequenceFrame(&pageSequence);
2132 NS_ASSERTION(nsnull != pageSequence, "no page sequence frame");
2134 // We are done preparing for printing, so we can turn this off
2135 mPrt->mPreparingForPrint = PR_FALSE;
2137 // mPrt->mDebugFilePtr this is onlu non-null when compiled for debugging
2138 if (nsnull != mPrt->mDebugFilePtr) {
2139 #ifdef NS_DEBUG
2140 // output the regression test
2141 nsIFrameDebug* fdbg;
2142 nsIFrame* root = poPresShell->FrameManager()->GetRootFrame();
2144 if (NS_SUCCEEDED(CallQueryInterface(root, &fdbg))) {
2145 fdbg->DumpRegressionData(poPresContext, mPrt->mDebugFilePtr, 0, PR_TRUE);
2147 fclose(mPrt->mDebugFilePtr);
2148 SetIsPrinting(PR_FALSE);
2149 #endif
2150 } else {
2151 #ifdef EXTENDED_DEBUG_PRINTING
2152 nsIFrame* rootFrame = poPresShell->FrameManager()->GetRootFrame();
2153 if (aPO->IsPrintable()) {
2154 char * docStr;
2155 char * urlStr;
2156 GetDocTitleAndURL(aPO, docStr, urlStr);
2157 DumpLayoutData(docStr, urlStr, poPresContext, mPrt->mPrintDocDC, rootFrame, docShell, nsnull);
2158 if (docStr) nsMemory::Free(docStr);
2159 if (urlStr) nsMemory::Free(urlStr);
2161 #endif
2163 if (mPrt->mPrintSettings) {
2164 PRUnichar * docTitleStr = nsnull;
2165 PRUnichar * docURLStr = nsnull;
2167 GetDisplayTitleAndURL(aPO, &docTitleStr, &docURLStr, eDocTitleDefBlank);
2169 if (nsIPrintSettings::kRangeSelection == printRangeType) {
2170 poPresContext->SetIsRenderingOnlySelection(PR_TRUE);
2171 // temporarily creating rendering context
2172 // which is needed to dinf the selection frames
2173 nsCOMPtr<nsIRenderingContext> rc;
2174 mPrt->mPrintDC->CreateRenderingContext(*getter_AddRefs(rc));
2176 // find the starting and ending page numbers
2177 // via the selection
2178 nsIFrame* startFrame;
2179 nsIFrame* endFrame;
2180 PRInt32 startPageNum;
2181 PRInt32 endPageNum;
2182 nsRect startRect;
2183 nsRect endRect;
2185 nsCOMPtr<nsISelection> selectionPS;
2186 selectionPS = poPresShell->GetCurrentSelection(nsISelectionController::SELECTION_NORMAL);
2188 rv = GetPageRangeForSelection(poPresShell, poPresContext, *rc, selectionPS, pageSequence,
2189 &startFrame, startPageNum, startRect,
2190 &endFrame, endPageNum, endRect);
2191 if (NS_SUCCEEDED(rv)) {
2192 mPrt->mPrintSettings->SetStartPageRange(startPageNum);
2193 mPrt->mPrintSettings->SetEndPageRange(endPageNum);
2194 nsMargin marginTwips(0,0,0,0);
2195 nsMargin unwrtMarginTwips(0,0,0,0);
2196 mPrt->mPrintSettings->GetMarginInTwips(marginTwips);
2197 mPrt->mPrintSettings->GetUnwriteableMarginInTwips(unwrtMarginTwips);
2198 nsMargin totalMargin = poPresContext->TwipsToAppUnits(marginTwips +
2199 unwrtMarginTwips);
2200 if (startPageNum == endPageNum) {
2202 startRect.y -= totalMargin.top;
2203 endRect.y -= totalMargin.top;
2205 // Clip out selection regions above the top of the first page
2206 if (startRect.y < 0) {
2207 // Reduce height to be the height of the positive-territory
2208 // region of original rect
2209 startRect.height = PR_MAX(0, startRect.YMost());
2210 startRect.y = 0;
2212 if (endRect.y < 0) {
2213 // Reduce height to be the height of the positive-territory
2214 // region of original rect
2215 endRect.height = PR_MAX(0, endRect.YMost());
2216 endRect.y = 0;
2218 NS_ASSERTION(endRect.y >= startRect.y,
2219 "Selection end point should be after start point");
2220 NS_ASSERTION(startRect.height >= 0,
2221 "rect should have non-negative height.");
2222 NS_ASSERTION(endRect.height >= 0,
2223 "rect should have non-negative height.");
2225 nscoord selectionHgt = endRect.y + endRect.height - startRect.y;
2226 // XXX This is temporary fix for printing more than one page of a selection
2227 pageSequence->SetSelectionHeight(startRect.y * aPO->mZoomRatio,
2228 selectionHgt * aPO->mZoomRatio);
2230 // calc total pages by getting calculating the selection's height
2231 // and then dividing it by how page content frames will fit.
2232 nscoord pageWidth, pageHeight;
2233 mPrt->mPrintDC->GetDeviceSurfaceDimensions(pageWidth, pageHeight);
2234 pageHeight -= totalMargin.top + totalMargin.bottom;
2235 PRInt32 totalPages = NSToIntCeil(float(selectionHgt) * aPO->mZoomRatio / float(pageHeight));
2236 pageSequence->SetTotalNumPages(totalPages);
2242 nsIFrame * seqFrame;
2243 if (NS_FAILED(CallQueryInterface(pageSequence, &seqFrame))) {
2244 SetIsPrinting(PR_FALSE);
2245 return NS_ERROR_FAILURE;
2248 mPageSeqFrame = pageSequence;
2249 mPageSeqFrame->StartPrint(poPresContext, mPrt->mPrintSettings, docTitleStr, docURLStr);
2251 // Schedule Page to Print
2252 PR_PL(("Scheduling Print of PO: %p (%s) \n", aPO, gFrameTypesStr[aPO->mFrameType]));
2253 StartPagePrintTimer(aPO);
2254 } else {
2255 // not sure what to do here!
2256 SetIsPrinting(PR_FALSE);
2257 return NS_ERROR_FAILURE;
2262 return NS_OK;
2265 //---------------------------------------------------------------------
2266 void
2267 nsPrintEngine::SetDocAndURLIntoProgress(nsPrintObject* aPO,
2268 nsIPrintProgressParams* aParams)
2270 NS_ASSERTION(aPO, "Must have vaild nsPrintObject");
2271 NS_ASSERTION(aParams, "Must have vaild nsIPrintProgressParams");
2273 if (!aPO || !aPO->mDocShell || !aParams) {
2274 return;
2276 const PRUint32 kTitleLength = 64;
2278 PRUnichar * docTitleStr;
2279 PRUnichar * docURLStr;
2280 GetDisplayTitleAndURL(aPO, &docTitleStr, &docURLStr, eDocTitleDefURLDoc);
2282 // Make sure the Titles & URLS don't get too long for the progress dialog
2283 ElipseLongString(docTitleStr, kTitleLength, PR_FALSE);
2284 ElipseLongString(docURLStr, kTitleLength, PR_TRUE);
2286 aParams->SetDocTitle(docTitleStr);
2287 aParams->SetDocURL(docURLStr);
2289 if (docTitleStr != nsnull) nsMemory::Free(docTitleStr);
2290 if (docURLStr != nsnull) nsMemory::Free(docURLStr);
2293 //---------------------------------------------------------------------
2294 void
2295 nsPrintEngine::ElipseLongString(PRUnichar *& aStr, const PRUint32 aLen, PRBool aDoFront)
2297 // Make sure the URLS don't get too long for the progress dialog
2298 if (aStr && nsCRT::strlen(aStr) > aLen) {
2299 if (aDoFront) {
2300 PRUnichar * ptr = &aStr[nsCRT::strlen(aStr)-aLen+3];
2301 nsAutoString newStr;
2302 newStr.AppendLiteral("...");
2303 newStr += ptr;
2304 nsMemory::Free(aStr);
2305 aStr = ToNewUnicode(newStr);
2306 } else {
2307 nsAutoString newStr(aStr);
2308 newStr.SetLength(aLen-3);
2309 newStr.AppendLiteral("...");
2310 nsMemory::Free(aStr);
2311 aStr = ToNewUnicode(newStr);
2316 //-------------------------------------------------------
2317 PRBool
2318 nsPrintEngine::PrintPage(nsPrintObject* aPO,
2319 PRBool& aInRange)
2321 NS_ASSERTION(aPO, "aPO is null!");
2322 NS_ASSERTION(mPageSeqFrame, "mPageSeqFrame is null!");
2323 NS_ASSERTION(mPrt, "mPrt is null!");
2325 // Although these should NEVER be NULL
2326 // This is added insurance, to make sure we don't crash in optimized builds
2327 if (!mPrt || !aPO || !mPageSeqFrame) {
2328 ShowPrintErrorDialog(NS_ERROR_FAILURE);
2329 return PR_TRUE; // means we are done printing
2332 PR_PL(("-----------------------------------\n"));
2333 PR_PL(("------ In DV::PrintPage PO: %p (%s)\n", aPO, gFrameTypesStr[aPO->mFrameType]));
2335 // Check setting to see if someone request it be cancelled
2336 PRBool isCancelled = PR_FALSE;
2337 mPrt->mPrintSettings->GetIsCancelled(&isCancelled);
2338 if (isCancelled)
2339 return PR_TRUE;
2341 PRInt32 pageNum, numPages, endPage;
2342 mPageSeqFrame->GetCurrentPageNum(&pageNum);
2343 mPageSeqFrame->GetNumPages(&numPages);
2345 PRBool donePrinting;
2346 PRBool isDoingPrintRange;
2347 mPageSeqFrame->IsDoingPrintRange(&isDoingPrintRange);
2348 if (isDoingPrintRange) {
2349 PRInt32 fromPage;
2350 PRInt32 toPage;
2351 mPageSeqFrame->GetPrintRange(&fromPage, &toPage);
2353 if (fromPage > numPages) {
2354 return PR_TRUE;
2356 if (toPage > numPages) {
2357 toPage = numPages;
2360 PR_PL(("****** Printing Page %d printing from %d to page %d\n", pageNum, fromPage, toPage));
2362 donePrinting = pageNum >= toPage;
2363 aInRange = pageNum >= fromPage && pageNum <= toPage;
2364 endPage = (toPage - fromPage)+1;
2365 } else {
2366 PR_PL(("****** Printing Page %d of %d page(s)\n", pageNum, numPages));
2368 donePrinting = pageNum >= numPages;
2369 endPage = numPages;
2370 aInRange = PR_TRUE;
2373 // XXX This is wrong, but the actual behavior in the presence of a print
2374 // range sucks.
2375 if (mPrt->mPrintFrameType == nsIPrintSettings::kEachFrameSep)
2376 endPage = mPrt->mNumPrintablePages;
2378 mPrt->DoOnProgressChange(++mPrt->mNumPagesPrinted, endPage, PR_FALSE, 0);
2380 // Print the Page
2381 // if a print job was cancelled externally, an EndPage or BeginPage may
2382 // fail and the failure is passed back here.
2383 // Returning PR_TRUE means we are done printing.
2385 // When rv == NS_ERROR_ABORT, it means we want out of the
2386 // print job without displaying any error messages
2387 nsresult rv = mPageSeqFrame->PrintNextPage();
2388 if (NS_FAILED(rv)) {
2389 if (rv != NS_ERROR_ABORT) {
2390 ShowPrintErrorDialog(rv);
2391 mPrt->mIsAborted = PR_TRUE;
2393 return PR_TRUE;
2396 mPageSeqFrame->DoPageEnd();
2398 return donePrinting;
2401 /** ---------------------------------------------------
2402 * Find by checking frames type
2404 nsresult
2405 nsPrintEngine::FindSelectionBoundsWithList(nsPresContext* aPresContext,
2406 nsIRenderingContext& aRC,
2407 nsIAtom* aList,
2408 nsIFrame * aParentFrame,
2409 nsRect& aRect,
2410 nsIFrame *& aStartFrame,
2411 nsRect& aStartRect,
2412 nsIFrame *& aEndFrame,
2413 nsRect& aEndRect)
2415 NS_ASSERTION(aPresContext, "Pointer is null!");
2416 NS_ASSERTION(aParentFrame, "Pointer is null!");
2418 nsIFrame* child = aParentFrame->GetFirstChild(aList);
2419 aRect += aParentFrame->GetPosition();
2420 while (child) {
2421 // only leaf frames have this bit flipped
2422 // then check the hard way
2423 PRBool isSelected = (child->GetStateBits() & NS_FRAME_SELECTED_CONTENT)
2424 == NS_FRAME_SELECTED_CONTENT;
2425 if (isSelected) {
2426 isSelected = child->IsVisibleForPainting();
2429 if (isSelected) {
2430 nsRect r = child->GetRect();
2431 if (aStartFrame == nsnull) {
2432 aStartFrame = child;
2433 aStartRect.SetRect(aRect.x + r.x, aRect.y + r.y, r.width, r.height);
2434 } else {
2435 aEndFrame = child;
2436 aEndRect.SetRect(aRect.x + r.x, aRect.y + r.y, r.width, r.height);
2439 FindSelectionBounds(aPresContext, aRC, child, aRect, aStartFrame, aStartRect, aEndFrame, aEndRect);
2440 child = child->GetNextSibling();
2442 aRect -= aParentFrame->GetPosition();
2443 return NS_OK;
2446 //-------------------------------------------------------
2447 // Find the Frame that is XMost
2448 nsresult
2449 nsPrintEngine::FindSelectionBounds(nsPresContext* aPresContext,
2450 nsIRenderingContext& aRC,
2451 nsIFrame * aParentFrame,
2452 nsRect& aRect,
2453 nsIFrame *& aStartFrame,
2454 nsRect& aStartRect,
2455 nsIFrame *& aEndFrame,
2456 nsRect& aEndRect)
2458 NS_ASSERTION(aPresContext, "Pointer is null!");
2459 NS_ASSERTION(aParentFrame, "Pointer is null!");
2461 // loop through named child lists
2462 nsIAtom* childListName = nsnull;
2463 PRInt32 childListIndex = 0;
2464 do {
2465 nsresult rv = FindSelectionBoundsWithList(aPresContext, aRC, childListName, aParentFrame, aRect, aStartFrame, aStartRect, aEndFrame, aEndRect);
2466 NS_ENSURE_SUCCESS(rv, rv);
2467 childListName = aParentFrame->GetAdditionalChildListName(childListIndex++);
2468 } while (childListName);
2469 return NS_OK;
2472 /** ---------------------------------------------------
2473 * This method finds the starting and ending page numbers
2474 * of the selection and also returns rect for each where
2475 * the x,y of the rect is relative to the very top of the
2476 * frame tree (absolutely positioned)
2478 nsresult
2479 nsPrintEngine::GetPageRangeForSelection(nsIPresShell * aPresShell,
2480 nsPresContext* aPresContext,
2481 nsIRenderingContext& aRC,
2482 nsISelection* aSelection,
2483 nsIPageSequenceFrame* aPageSeqFrame,
2484 nsIFrame** aStartFrame,
2485 PRInt32& aStartPageNum,
2486 nsRect& aStartRect,
2487 nsIFrame** aEndFrame,
2488 PRInt32& aEndPageNum,
2489 nsRect& aEndRect)
2491 NS_ASSERTION(aPresShell, "Pointer is null!");
2492 NS_ASSERTION(aPresContext, "Pointer is null!");
2493 NS_ASSERTION(aSelection, "Pointer is null!");
2494 NS_ASSERTION(aPageSeqFrame, "Pointer is null!");
2495 NS_ASSERTION(aStartFrame, "Pointer is null!");
2496 NS_ASSERTION(aEndFrame, "Pointer is null!");
2498 nsIFrame * seqFrame;
2499 if (NS_FAILED(CallQueryInterface(aPageSeqFrame, &seqFrame))) {
2500 return NS_ERROR_FAILURE;
2503 nsIFrame * startFrame = nsnull;
2504 nsIFrame * endFrame = nsnull;
2506 // start out with the sequence frame and search the entire frame tree
2507 // capturing the starting and ending child frames of the selection
2508 // and their rects
2509 nsRect r = seqFrame->GetRect();
2510 FindSelectionBounds(aPresContext, aRC, seqFrame, r,
2511 startFrame, aStartRect, endFrame, aEndRect);
2513 #ifdef DEBUG_rodsX
2514 printf("Start Frame: %p\n", startFrame);
2515 printf("End Frame: %p\n", endFrame);
2516 #endif
2518 // initial the page numbers here
2519 // in case we don't find and frames
2520 aStartPageNum = -1;
2521 aEndPageNum = -1;
2523 nsIFrame * startPageFrame;
2524 nsIFrame * endPageFrame;
2526 // check to make sure we found a starting frame
2527 if (startFrame != nsnull) {
2528 // Now search up the tree to find what page the
2529 // start/ending selections frames are on
2531 // Check to see if start should be same as end if
2532 // the end frame comes back null
2533 if (endFrame == nsnull) {
2534 // XXX the "GetPageFrame" step could be integrated into
2535 // the FindSelectionBounds step, but walking up to find
2536 // the parent of a child frame isn't expensive and it makes
2537 // FindSelectionBounds a little easier to understand
2538 startPageFrame = nsLayoutUtils::GetPageFrame(startFrame);
2539 endPageFrame = startPageFrame;
2540 aEndRect = aStartRect;
2541 } else {
2542 startPageFrame = nsLayoutUtils::GetPageFrame(startFrame);
2543 endPageFrame = nsLayoutUtils::GetPageFrame(endFrame);
2545 } else {
2546 return NS_ERROR_FAILURE;
2549 #ifdef DEBUG_rodsX
2550 printf("Start Page: %p\n", startPageFrame);
2551 printf("End Page: %p\n", endPageFrame);
2553 // dump all the pages and their pointers
2555 PRInt32 pageNum = 1;
2556 nsIFrame* child = seqFrame->GetFirstChild(nsnull);
2557 while (child != nsnull) {
2558 printf("Page: %d - %p\n", pageNum, child);
2559 pageNum++;
2560 child = child->GetNextSibling();
2563 #endif
2565 // Now that we have the page frames
2566 // find out what the page numbers are for each frame
2567 PRInt32 pageNum = 1;
2568 nsIFrame* page = seqFrame->GetFirstChild(nsnull);
2569 while (page != nsnull) {
2570 if (page == startPageFrame) {
2571 aStartPageNum = pageNum;
2573 if (page == endPageFrame) {
2574 aEndPageNum = pageNum;
2576 pageNum++;
2577 page = page->GetNextSibling();
2580 #ifdef DEBUG_rodsX
2581 printf("Start Page No: %d\n", aStartPageNum);
2582 printf("End Page No: %d\n", aEndPageNum);
2583 #endif
2585 *aStartFrame = startPageFrame;
2586 *aEndFrame = endPageFrame;
2588 return NS_OK;
2591 //-----------------------------------------------------------------
2592 //-- Done: Printing Methods
2593 //-----------------------------------------------------------------
2596 //-----------------------------------------------------------------
2597 //-- Section: Misc Support Methods
2598 //-----------------------------------------------------------------
2600 //---------------------------------------------------------------------
2601 void nsPrintEngine::SetIsPrinting(PRBool aIsPrinting)
2603 mIsDoingPrinting = aIsPrinting;
2604 if (mDocViewerPrint) {
2605 mDocViewerPrint->SetIsPrinting(aIsPrinting);
2607 if (mPrt && aIsPrinting) {
2608 mPrt->mPreparingForPrint = PR_TRUE;
2612 //---------------------------------------------------------------------
2613 void nsPrintEngine::SetIsPrintPreview(PRBool aIsPrintPreview)
2615 mIsDoingPrintPreview = aIsPrintPreview;
2617 if (mDocViewerPrint) {
2618 mDocViewerPrint->SetIsPrintPreview(aIsPrintPreview);
2622 //---------------------------------------------------------------------
2623 void
2624 nsPrintEngine::CleanupDocTitleArray(PRUnichar**& aArray, PRInt32& aCount)
2626 for (PRInt32 i = aCount - 1; i >= 0; i--) {
2627 nsMemory::Free(aArray[i]);
2629 nsMemory::Free(aArray);
2630 aArray = NULL;
2631 aCount = 0;
2634 //---------------------------------------------------------------------
2635 // static
2636 PRBool nsPrintEngine::HasFramesetChild(nsIContent* aContent)
2638 if (!aContent) {
2639 return PR_FALSE;
2642 PRUint32 numChildren = aContent->GetChildCount();
2644 // do a breadth search across all siblings
2645 for (PRUint32 i = 0; i < numChildren; ++i) {
2646 nsIContent *child = aContent->GetChildAt(i);
2647 if (child->Tag() == nsGkAtoms::frameset &&
2648 child->IsNodeOfType(nsINode::eHTML)) {
2649 return PR_TRUE;
2653 return PR_FALSE;
2658 /** ---------------------------------------------------
2659 * Get the Focused Frame for a documentviewer
2661 already_AddRefed<nsIDOMWindow>
2662 nsPrintEngine::FindFocusedDOMWindow()
2664 nsIDOMWindow * domWin = nsnull;
2666 nsPIDOMWindow *theDOMWindow = mDocument->GetWindow();
2667 if(theDOMWindow){
2668 nsIFocusController *focusController =
2669 theDOMWindow->GetRootFocusController();
2670 if (focusController) {
2671 nsCOMPtr<nsIDOMWindowInternal> theDOMWin;
2672 focusController->GetFocusedWindow(getter_AddRefs(theDOMWin));
2673 if(theDOMWin && IsWindowsInOurSubTree(theDOMWin)){
2674 NS_ADDREF(domWin = theDOMWin);
2679 return domWin;
2682 //---------------------------------------------------------------------
2683 PRBool
2684 nsPrintEngine::IsWindowsInOurSubTree(nsIDOMWindow * aDOMWindow)
2686 PRBool found = PR_FALSE;
2688 // now check to make sure it is in "our" tree of docshells
2689 nsCOMPtr<nsPIDOMWindow> window(do_QueryInterface(aDOMWindow));
2690 if (window) {
2691 nsCOMPtr<nsIDocShellTreeItem> docShellAsItem =
2692 do_QueryInterface(window->GetDocShell());
2694 if (docShellAsItem) {
2695 // get this DocViewer docshell
2696 nsCOMPtr<nsIDocShell> thisDVDocShell(do_QueryInterface(mContainer));
2697 while (!found) {
2698 nsCOMPtr<nsIDocShell> parentDocshell(do_QueryInterface(docShellAsItem));
2699 if (parentDocshell) {
2700 if (parentDocshell == thisDVDocShell) {
2701 found = PR_TRUE;
2702 break;
2704 } else {
2705 break; // at top of tree
2707 nsCOMPtr<nsIDocShellTreeItem> docShellParent;
2708 docShellAsItem->GetSameTypeParent(getter_AddRefs(docShellParent));
2709 docShellAsItem = docShellParent;
2710 } // while
2712 } // scriptobj
2714 return found;
2717 //-------------------------------------------------------
2718 PRBool
2719 nsPrintEngine::DonePrintingPages(nsPrintObject* aPO, nsresult aResult)
2721 //NS_ASSERTION(aPO, "Pointer is null!");
2722 PR_PL(("****** In DV::DonePrintingPages PO: %p (%s)\n", aPO, aPO?gFrameTypesStr[aPO->mFrameType]:""));
2724 if (aPO != nsnull) {
2725 aPO->mHasBeenPrinted = PR_TRUE;
2726 nsresult rv;
2727 PRBool didPrint = PrintDocContent(mPrt->mPrintObject, rv);
2728 if (NS_SUCCEEDED(rv) && didPrint) {
2729 PR_PL(("****** In DV::DonePrintingPages PO: %p (%s) didPrint:%s (Not Done Printing)\n", aPO, gFrameTypesStr[aPO->mFrameType], PRT_YESNO(didPrint)));
2730 return PR_FALSE;
2734 if (NS_SUCCEEDED(aResult)) {
2735 FirePrintCompletionEvent();
2738 SetIsPrinting(PR_FALSE);
2740 // Release reference to mPagePrintTimer; the timer object destroys itself
2741 // after this returns true
2742 NS_IF_RELEASE(mPagePrintTimer);
2744 return PR_TRUE;
2747 //-------------------------------------------------------
2748 // Recursively sets the PO items to be printed "As Is"
2749 // from the given item down into the tree
2750 void
2751 nsPrintEngine::SetPrintAsIs(nsPrintObject* aPO, PRBool aAsIs)
2753 NS_ASSERTION(aPO, "Pointer is null!");
2755 aPO->mPrintAsIs = aAsIs;
2756 for (PRInt32 i=0;i<aPO->mKids.Count();i++) {
2757 SetPrintAsIs((nsPrintObject*)aPO->mKids[i], aAsIs);
2761 //-------------------------------------------------------
2762 // Given a DOMWindow it recursively finds the PO object that matches
2763 nsPrintObject*
2764 nsPrintEngine::FindPrintObjectByDOMWin(nsPrintObject* aPO,
2765 nsIDOMWindow* aDOMWin)
2767 NS_ASSERTION(aPO, "Pointer is null!");
2769 // Often the CurFocused DOMWindow is passed in
2770 // andit is valid for it to be null, so short circut
2771 if (!aDOMWin) {
2772 return nsnull;
2775 nsCOMPtr<nsIDOMWindow> domWin(do_GetInterface(aPO->mDocShell));
2776 if (domWin && domWin == aDOMWin) {
2777 return aPO;
2780 PRInt32 cnt = aPO->mKids.Count();
2781 for (PRInt32 i = 0; i < cnt; ++i) {
2782 nsPrintObject* po = FindPrintObjectByDOMWin((nsPrintObject*)aPO->mKids[i],
2783 aDOMWin);
2784 if (po) {
2785 return po;
2789 return nsnull;
2792 //-------------------------------------------------------
2793 nsresult
2794 nsPrintEngine::EnablePOsForPrinting()
2796 // NOTE: All POs have been "turned off" for printing
2797 // this is where we decided which POs get printed.
2798 mPrt->mSelectedPO = nsnull;
2800 if (mPrt->mPrintSettings == nsnull) {
2801 return NS_ERROR_FAILURE;
2804 mPrt->mPrintFrameType = nsIPrintSettings::kNoFrames;
2805 mPrt->mPrintSettings->GetPrintFrameType(&mPrt->mPrintFrameType);
2807 PRInt16 printHowEnable = nsIPrintSettings::kFrameEnableNone;
2808 mPrt->mPrintSettings->GetHowToEnableFrameUI(&printHowEnable);
2810 PRInt16 printRangeType = nsIPrintSettings::kRangeAllPages;
2811 mPrt->mPrintSettings->GetPrintRange(&printRangeType);
2813 PR_PL(("\n"));
2814 PR_PL(("********* nsPrintEngine::EnablePOsForPrinting *********\n"));
2815 PR_PL(("PrintFrameType: %s \n", gPrintFrameTypeStr[mPrt->mPrintFrameType]));
2816 PR_PL(("HowToEnableFrameUI: %s \n", gFrameHowToEnableStr[printHowEnable]));
2817 PR_PL(("PrintRange: %s \n", gPrintRangeStr[printRangeType]));
2818 PR_PL(("----\n"));
2820 // ***** This is the ultimate override *****
2821 // if we are printing the selection (either an IFrame or selection range)
2822 // then set the mPrintFrameType as if it were the selected frame
2823 if (printRangeType == nsIPrintSettings::kRangeSelection) {
2824 mPrt->mPrintFrameType = nsIPrintSettings::kSelectedFrame;
2825 printHowEnable = nsIPrintSettings::kFrameEnableNone;
2828 // This tells us that the "Frame" UI has turned off,
2829 // so therefore there are no FrameSets/Frames/IFrames to be printed
2831 // This means there are not FrameSets,
2832 // but the document could contain an IFrame
2833 if (printHowEnable == nsIPrintSettings::kFrameEnableNone) {
2835 // Print all the pages or a sub range of pages
2836 if (printRangeType == nsIPrintSettings::kRangeAllPages ||
2837 printRangeType == nsIPrintSettings::kRangeSpecifiedPageRange) {
2838 SetPrintPO(mPrt->mPrintObject, PR_TRUE);
2840 // Set the children so they are PrinAsIs
2841 // In this case, the children are probably IFrames
2842 if (mPrt->mPrintObject->mKids.Count() > 0) {
2843 for (PRInt32 i=0;i<mPrt->mPrintObject->mKids.Count();i++) {
2844 nsPrintObject* po = (nsPrintObject*)mPrt->mPrintObject->mKids[i];
2845 NS_ASSERTION(po, "nsPrintObject can't be null!");
2846 SetPrintAsIs(po);
2849 // ***** Another override *****
2850 mPrt->mPrintFrameType = nsIPrintSettings::kFramesAsIs;
2852 PR_PL(("PrintFrameType: %s \n", gPrintFrameTypeStr[mPrt->mPrintFrameType]));
2853 PR_PL(("HowToEnableFrameUI: %s \n", gFrameHowToEnableStr[printHowEnable]));
2854 PR_PL(("PrintRange: %s \n", gPrintRangeStr[printRangeType]));
2855 return NS_OK;
2858 // This means we are either printed a selected IFrame or
2859 // we are printing the current selection
2860 if (printRangeType == nsIPrintSettings::kRangeSelection) {
2862 // If the currentFocusDOMWin can'r be null if something is selected
2863 if (mPrt->mCurrentFocusWin) {
2864 // Find the selected IFrame
2865 nsPrintObject * po = FindPrintObjectByDOMWin(mPrt->mPrintObject, mPrt->mCurrentFocusWin);
2866 if (po != nsnull) {
2867 mPrt->mSelectedPO = po;
2868 // Makes sure all of its children are be printed "AsIs"
2869 SetPrintAsIs(po);
2871 // Now, only enable this POs (the selected PO) and all of its children
2872 SetPrintPO(po, PR_TRUE);
2874 // check to see if we have a range selection,
2875 // as oppose to a insert selection
2876 // this means if the user just clicked on the IFrame then
2877 // there will not be a selection so we want the entire page to print
2879 // XXX this is sort of a hack right here to make the page
2880 // not try to reposition itself when printing selection
2881 nsCOMPtr<nsIDOMWindow> domWin = do_GetInterface(po->mDocShell);
2882 if (!IsThereARangeSelection(domWin)) {
2883 printRangeType = nsIPrintSettings::kRangeAllPages;
2884 mPrt->mPrintSettings->SetPrintRange(printRangeType);
2886 PR_PL(("PrintFrameType: %s \n", gPrintFrameTypeStr[mPrt->mPrintFrameType]));
2887 PR_PL(("HowToEnableFrameUI: %s \n", gFrameHowToEnableStr[printHowEnable]));
2888 PR_PL(("PrintRange: %s \n", gPrintRangeStr[printRangeType]));
2889 return NS_OK;
2891 } else {
2892 for (PRInt32 i=0;i<mPrt->mPrintDocList->Count();i++) {
2893 nsPrintObject* po = (nsPrintObject*)mPrt->mPrintDocList->ElementAt(i);
2894 NS_ASSERTION(po, "nsPrintObject can't be null!");
2895 nsCOMPtr<nsIDOMWindow> domWin = do_GetInterface(po->mDocShell);
2896 if (IsThereARangeSelection(domWin)) {
2897 mPrt->mCurrentFocusWin = domWin;
2898 SetPrintPO(po, PR_TRUE);
2899 break;
2902 return NS_OK;
2907 // check to see if there is a selection when a FrameSet is present
2908 if (printRangeType == nsIPrintSettings::kRangeSelection) {
2909 // If the currentFocusDOMWin can'r be null if something is selected
2910 if (mPrt->mCurrentFocusWin) {
2911 // Find the selected IFrame
2912 nsPrintObject * po = FindPrintObjectByDOMWin(mPrt->mPrintObject, mPrt->mCurrentFocusWin);
2913 if (po != nsnull) {
2914 mPrt->mSelectedPO = po;
2915 // Makes sure all of its children are be printed "AsIs"
2916 SetPrintAsIs(po);
2918 // Now, only enable this POs (the selected PO) and all of its children
2919 SetPrintPO(po, PR_TRUE);
2921 // check to see if we have a range selection,
2922 // as oppose to a insert selection
2923 // this means if the user just clicked on the IFrame then
2924 // there will not be a selection so we want the entire page to print
2926 // XXX this is sort of a hack right here to make the page
2927 // not try to reposition itself when printing selection
2928 nsCOMPtr<nsIDOMWindow> domWin = do_GetInterface(po->mDocShell);
2929 if (!IsThereARangeSelection(domWin)) {
2930 printRangeType = nsIPrintSettings::kRangeAllPages;
2931 mPrt->mPrintSettings->SetPrintRange(printRangeType);
2933 PR_PL(("PrintFrameType: %s \n", gPrintFrameTypeStr[mPrt->mPrintFrameType]));
2934 PR_PL(("HowToEnableFrameUI: %s \n", gFrameHowToEnableStr[printHowEnable]));
2935 PR_PL(("PrintRange: %s \n", gPrintRangeStr[printRangeType]));
2936 return NS_OK;
2941 // If we are printing "AsIs" then sets all the POs to be printed as is
2942 if (mPrt->mPrintFrameType == nsIPrintSettings::kFramesAsIs) {
2943 SetPrintAsIs(mPrt->mPrintObject);
2944 SetPrintPO(mPrt->mPrintObject, PR_TRUE);
2945 return NS_OK;
2948 // If we are printing the selected Frame then
2949 // find that PO for that selected DOMWin and set it all of its
2950 // children to be printed
2951 if (mPrt->mPrintFrameType == nsIPrintSettings::kSelectedFrame) {
2953 if ((mPrt->mIsParentAFrameSet && mPrt->mCurrentFocusWin) || mPrt->mIsIFrameSelected) {
2954 nsPrintObject * po = FindPrintObjectByDOMWin(mPrt->mPrintObject, mPrt->mCurrentFocusWin);
2955 if (po != nsnull) {
2956 mPrt->mSelectedPO = po;
2957 // NOTE: Calling this sets the "po" and
2958 // we don't want to do this for documents that have no children,
2959 // because then the "DoEndPage" gets called and it shouldn't
2960 if (po->mKids.Count() > 0) {
2961 // Makes sure that itself, and all of its children are printed "AsIs"
2962 SetPrintAsIs(po);
2965 // Now, only enable this POs (the selected PO) and all of its children
2966 SetPrintPO(po, PR_TRUE);
2969 return NS_OK;
2972 // If we are print each subdoc separately,
2973 // then don't print any of the FraneSet Docs
2974 if (mPrt->mPrintFrameType == nsIPrintSettings::kEachFrameSep) {
2975 SetPrintPO(mPrt->mPrintObject, PR_TRUE);
2976 PRInt32 cnt = mPrt->mPrintDocList->Count();
2977 for (PRInt32 i=0;i<cnt;i++) {
2978 nsPrintObject* po = (nsPrintObject*)mPrt->mPrintDocList->ElementAt(i);
2979 NS_ASSERTION(po, "nsPrintObject can't be null!");
2980 if (po->mFrameType == eFrameSet) {
2981 po->mDontPrint = PR_TRUE;
2986 return NS_OK;
2989 //-------------------------------------------------------
2990 // Return the nsPrintObject with that is XMost (The widest frameset frame) AND
2991 // contains the XMost (widest) layout frame
2992 nsPrintObject*
2993 nsPrintEngine::FindSmallestSTF()
2995 float smallestRatio = 1.0f;
2996 nsPrintObject* smallestPO = nsnull;
2998 for (PRInt32 i=0;i<mPrt->mPrintDocList->Count();i++) {
2999 nsPrintObject* po = (nsPrintObject*)mPrt->mPrintDocList->ElementAt(i);
3000 NS_ASSERTION(po, "nsPrintObject can't be null!");
3001 if (po->mFrameType != eFrameSet && po->mFrameType != eIFrame) {
3002 if (po->mShrinkRatio < smallestRatio) {
3003 smallestRatio = po->mShrinkRatio;
3004 smallestPO = po;
3009 #ifdef EXTENDED_DEBUG_PRINTING
3010 if (smallestPO) printf("*PO: %p Type: %d %10.3f\n", smallestPO, smallestPO->mFrameType, smallestPO->mShrinkRatio);
3011 #endif
3012 return smallestPO;
3015 //-------------------------------------------------------
3016 void
3017 nsPrintEngine::TurnScriptingOn(PRBool aDoTurnOn)
3019 nsPrintData* prt = mPrt;
3020 #ifdef NS_PRINT_PREVIEW
3021 if (!prt) {
3022 prt = mPrtPreview;
3024 #endif
3025 if (!prt) {
3026 return;
3029 NS_ASSERTION(mDocument, "We MUST have a document.");
3030 // First, get the script global object from the document...
3032 for (PRInt32 i=0;i<prt->mPrintDocList->Count();i++) {
3033 nsPrintObject* po = (nsPrintObject*)prt->mPrintDocList->ElementAt(i);
3034 NS_ASSERTION(po, "nsPrintObject can't be null!");
3036 nsIDocument* doc = po->mDocument;
3038 // get the script global object
3039 nsIScriptGlobalObject *scriptGlobalObj = doc->GetScriptGlobalObject();
3041 if (scriptGlobalObj) {
3042 nsIScriptContext *scx = scriptGlobalObj->GetContext();
3043 NS_ASSERTION(scx, "Can't get nsIScriptContext");
3044 if (aDoTurnOn) {
3045 doc->DeleteProperty(nsGkAtoms::scriptEnabledBeforePrintPreview);
3046 } else {
3047 // Have to be careful, because people call us over and over again with
3048 // aDoTurnOn == PR_FALSE. So don't set the property if it's already
3049 // set, since in that case we'd set it to the wrong value.
3050 nsresult propThere;
3051 doc->GetProperty(nsGkAtoms::scriptEnabledBeforePrintPreview,
3052 &propThere);
3053 if (propThere == NS_PROPTABLE_PROP_NOT_THERE) {
3054 // Stash the current value of IsScriptEnabled on the document, so
3055 // that layout code running in print preview doesn't get confused.
3056 doc->SetProperty(nsGkAtoms::scriptEnabledBeforePrintPreview,
3057 NS_INT32_TO_PTR(doc->IsScriptEnabled()));
3060 scx->SetScriptsEnabled(aDoTurnOn, PR_TRUE);
3065 //-----------------------------------------------------------------
3066 //-- Done: Misc Support Methods
3067 //-----------------------------------------------------------------
3070 //-----------------------------------------------------------------
3071 //-- Section: Finishing up or Cleaning up
3072 //-----------------------------------------------------------------
3074 //-----------------------------------------------------------------
3075 void
3076 nsPrintEngine::CloseProgressDialog(nsIWebProgressListener* aWebProgressListener)
3078 if (aWebProgressListener) {
3079 aWebProgressListener->OnStateChange(nsnull, nsnull, nsIWebProgressListener::STATE_STOP|nsIWebProgressListener::STATE_IS_DOCUMENT, nsnull);
3083 //-----------------------------------------------------------------
3084 nsresult
3085 nsPrintEngine::FinishPrintPreview()
3087 nsresult rv = NS_OK;
3089 #ifdef NS_PRINT_PREVIEW
3091 if (!mPrt) {
3092 /* we're already finished with print preview */
3093 return rv;
3096 rv = DocumentReadyForPrinting();
3098 SetIsCreatingPrintPreview(PR_FALSE);
3100 /* cleaup on failure + notify user */
3101 if (NS_FAILED(rv)) {
3102 /* cleanup done, let's fire-up an error dialog to notify the user
3103 * what went wrong...
3105 mPrt->OnEndPrinting();
3106 TurnScriptingOn(PR_TRUE);
3108 return rv;
3111 // At this point we are done preparing everything
3112 // before it is to be created
3115 if (mIsDoingPrintPreview && mOldPrtPreview) {
3116 delete mOldPrtPreview;
3117 mOldPrtPreview = nsnull;
3120 InstallPrintPreviewListener();
3122 mPrt->OnEndPrinting();
3124 // PrintPreview was built using the mPrt (code reuse)
3125 // then we assign it over
3126 mPrtPreview = mPrt;
3127 mPrt = nsnull;
3129 #endif // NS_PRINT_PREVIEW
3131 return NS_OK;
3134 //-----------------------------------------------------------------
3135 //-- Done: Finishing up or Cleaning up
3136 //-----------------------------------------------------------------
3139 /*=============== Timer Related Code ======================*/
3140 nsresult
3141 nsPrintEngine::StartPagePrintTimer(nsPrintObject* aPO)
3143 if (!mPagePrintTimer) {
3144 nsresult rv = NS_NewPagePrintTimer(&mPagePrintTimer);
3145 NS_ENSURE_SUCCESS(rv, rv);
3147 // Get the delay time in between the printing of each page
3148 // this gives the user more time to press cancel
3149 PRInt32 printPageDelay = 500;
3150 mPrt->mPrintSettings->GetPrintPageDelay(&printPageDelay);
3152 mPagePrintTimer->Init(this, mDocViewerPrint, printPageDelay);
3155 return mPagePrintTimer->Start(aPO);
3158 /*=============== nsIObserver Interface ======================*/
3159 NS_IMETHODIMP
3160 nsPrintEngine::Observe(nsISupports *aSubject, const char *aTopic, const PRUnichar *aData)
3162 nsresult rv = NS_ERROR_FAILURE;
3164 if (mIsDoingPrinting) {
3165 rv = DocumentReadyForPrinting();
3167 /* cleaup on failure + notify user */
3168 if (NS_FAILED(rv)) {
3169 CleanupOnFailure(rv, PR_TRUE);
3171 } else {
3172 rv = FinishPrintPreview();
3173 if (NS_FAILED(rv)) {
3174 CleanupOnFailure(rv, PR_FALSE);
3176 if (mPrtPreview) {
3177 mPrtPreview->OnEndPrinting();
3179 rv = NS_OK;
3182 return rv;
3186 //---------------------------------------------------------------
3187 //-- PLEvent Notification
3188 //---------------------------------------------------------------
3189 class nsPrintCompletionEvent : public nsRunnable {
3190 public:
3191 nsPrintCompletionEvent(nsIDocumentViewerPrint *docViewerPrint)
3192 : mDocViewerPrint(docViewerPrint) {
3193 NS_ASSERTION(mDocViewerPrint, "mDocViewerPrint is null.");
3196 NS_IMETHOD Run() {
3197 if (mDocViewerPrint)
3198 mDocViewerPrint->OnDonePrinting();
3199 return NS_OK;
3202 private:
3203 nsCOMPtr<nsIDocumentViewerPrint> mDocViewerPrint;
3206 //-----------------------------------------------------------
3207 void
3208 nsPrintEngine::FirePrintCompletionEvent()
3210 nsCOMPtr<nsIRunnable> event = new nsPrintCompletionEvent(mDocViewerPrint);
3211 if (NS_FAILED(NS_DispatchToCurrentThread(event)))
3212 NS_WARNING("failed to dispatch print completion event");
3215 //---------------------------------------------------------------
3216 //---------------------------------------------------------------
3217 //-- Debug helper routines
3218 //---------------------------------------------------------------
3219 //---------------------------------------------------------------
3220 #if (defined(XP_WIN) || defined(XP_OS2)) && defined(EXTENDED_DEBUG_PRINTING)
3221 #include "windows.h"
3222 #include "process.h"
3223 #include "direct.h"
3225 #define MY_FINDFIRST(a,b) FindFirstFile(a,b)
3226 #define MY_FINDNEXT(a,b) FindNextFile(a,b)
3227 #define ISDIR(a) (a.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
3228 #define MY_FINDCLOSE(a) FindClose(a)
3229 #define MY_FILENAME(a) a.cFileName
3230 #define MY_FILESIZE(a) (a.nFileSizeHigh * MAXDWORD) + a.nFileSizeLow
3232 int RemoveFilesInDir(const char * aDir)
3234 WIN32_FIND_DATA data_ptr;
3235 HANDLE find_handle;
3237 char path[MAX_PATH];
3239 strcpy(path, aDir);
3241 // Append slash to the end of the directory names if not there
3242 if (path[strlen(path)-1] != '\\')
3243 strcat(path, "\\");
3245 char findPath[MAX_PATH];
3246 strcpy(findPath, path);
3247 strcat(findPath, "*.*");
3249 find_handle = MY_FINDFIRST(findPath, &data_ptr);
3251 if (find_handle != INVALID_HANDLE_VALUE) {
3252 do {
3253 if (ISDIR(data_ptr)
3254 && (stricmp(MY_FILENAME(data_ptr),"."))
3255 && (stricmp(MY_FILENAME(data_ptr),".."))) {
3256 // skip
3258 else if (!ISDIR(data_ptr)) {
3259 if (!strncmp(MY_FILENAME(data_ptr), "print_dump", 10)) {
3260 char fileName[MAX_PATH];
3261 strcpy(fileName, aDir);
3262 strcat(fileName, "\\");
3263 strcat(fileName, MY_FILENAME(data_ptr));
3264 printf("Removing %s\n", fileName);
3265 remove(fileName);
3268 } while(MY_FINDNEXT(find_handle,&data_ptr));
3269 MY_FINDCLOSE(find_handle);
3271 return TRUE;
3273 #endif
3275 #ifdef EXTENDED_DEBUG_PRINTING
3277 /** ---------------------------------------------------
3278 * Dumps Frames for Printing
3280 static void RootFrameList(nsPresContext* aPresContext, FILE* out, PRInt32 aIndent)
3282 if (!aPresContext || !out)
3283 return;
3285 nsIPresShell *shell = aPresContext->GetPresShell();
3286 if (shell) {
3287 nsIFrame* frame = shell->FrameManager()->GetRootFrame();
3288 if (frame) {
3289 nsIFrameDebug* debugFrame;
3290 nsresult rv = CallQueryInterface(frame, &debugFrame);
3291 if (NS_SUCCEEDED(rv))
3292 debugFrame->List(aPresContext, out, aIndent);
3297 /** ---------------------------------------------------
3298 * Dumps Frames for Printing
3300 static void DumpFrames(FILE* out,
3301 nsPresContext* aPresContext,
3302 nsIRenderingContext * aRendContext,
3303 nsIFrame * aFrame,
3304 PRInt32 aLevel)
3306 NS_ASSERTION(out, "Pointer is null!");
3307 NS_ASSERTION(aPresContext, "Pointer is null!");
3308 NS_ASSERTION(aRendContext, "Pointer is null!");
3309 NS_ASSERTION(aFrame, "Pointer is null!");
3311 nsIFrame* child = aFrame->GetFirstChild(nsnull);
3312 while (child != nsnull) {
3313 for (PRInt32 i=0;i<aLevel;i++) {
3314 fprintf(out, " ");
3316 nsAutoString tmp;
3317 nsIFrameDebug* frameDebug;
3319 if (NS_SUCCEEDED(CallQueryInterface(child, &frameDebug))) {
3320 frameDebug->GetFrameName(tmp);
3322 fputs(NS_LossyConvertUTF16toASCII(tmp).get(), out);
3323 PRBool isSelected;
3324 if (NS_SUCCEEDED(child->IsVisibleForPainting(aPresContext, *aRendContext, PR_TRUE, &isSelected))) {
3325 fprintf(out, " %p %s", child, isSelected?"VIS":"UVS");
3326 nsRect rect = child->GetRect();
3327 fprintf(out, "[%d,%d,%d,%d] ", rect.x, rect.y, rect.width, rect.height);
3328 fprintf(out, "v: %p ", (void*)child->GetView());
3329 fprintf(out, "\n");
3330 DumpFrames(out, aPresContext, aRendContext, child, aLevel+1);
3331 child = child->GetNextSibling();
3337 /** ---------------------------------------------------
3338 * Dumps the Views from the DocShell
3340 static void
3341 DumpViews(nsIDocShell* aDocShell, FILE* out)
3343 NS_ASSERTION(aDocShell, "Pointer is null!");
3344 NS_ASSERTION(out, "Pointer is null!");
3346 if (nsnull != aDocShell) {
3347 fprintf(out, "docshell=%p \n", aDocShell);
3348 nsIPresShell* shell = nsPrintEngine::GetPresShellFor(aDocShell);
3349 if (shell) {
3350 nsIViewManager* vm = shell->GetViewManager();
3351 if (vm) {
3352 nsIView* root;
3353 vm->GetRootView(root);
3354 if (nsnull != root) {
3355 root->List(out);
3359 else {
3360 fputs("null pres shell\n", out);
3363 // dump the views of the sub documents
3364 PRInt32 i, n;
3365 nsCOMPtr<nsIDocShellTreeNode> docShellAsNode(do_QueryInterface(aDocShell));
3366 docShellAsNode->GetChildCount(&n);
3367 for (i = 0; i < n; i++) {
3368 nsCOMPtr<nsIDocShellTreeItem> child;
3369 docShellAsNode->GetChildAt(i, getter_AddRefs(child));
3370 nsCOMPtr<nsIDocShell> childAsShell(do_QueryInterface(child));
3371 if (childAsShell) {
3372 DumpViews(childAsShell, out);
3378 /** ---------------------------------------------------
3379 * Dumps the Views and Frames
3381 void DumpLayoutData(char* aTitleStr,
3382 char* aURLStr,
3383 nsPresContext* aPresContext,
3384 nsIDeviceContext * aDC,
3385 nsIFrame * aRootFrame,
3386 nsIDocShekk * aDocShell,
3387 FILE* aFD = nsnull)
3389 if (!kPrintingLogMod || kPrintingLogMod->level != DUMP_LAYOUT_LEVEL) return;
3391 if (aPresContext == nsnull || aDC == nsnull) {
3392 return;
3395 #ifdef NS_PRINT_PREVIEW
3396 if (aPresContext->Type() == nsPresContext::eContext_PrintPreview) {
3397 return;
3399 #endif
3401 NS_ASSERTION(aRootFrame, "Pointer is null!");
3402 NS_ASSERTION(aDocShell, "Pointer is null!");
3404 // Dump all the frames and view to a a file
3405 char filename[256];
3406 sprintf(filename, "print_dump_layout_%d.txt", gDumpLOFileNameCnt++);
3407 FILE * fd = aFD?aFD:fopen(filename, "w");
3408 if (fd) {
3409 fprintf(fd, "Title: %s\n", aTitleStr?aTitleStr:"");
3410 fprintf(fd, "URL: %s\n", aURLStr?aURLStr:"");
3411 fprintf(fd, "--------------- Frames ----------------\n");
3412 fprintf(fd, "--------------- Frames ----------------\n");
3413 nsCOMPtr<nsIRenderingContext> renderingContext;
3414 aDC->CreateRenderingContext(*getter_AddRefs(renderingContext));
3415 RootFrameList(aPresContext, fd, 0);
3416 //DumpFrames(fd, aPresContext, renderingContext, aRootFrame, 0);
3417 fprintf(fd, "---------------------------------------\n\n");
3418 fprintf(fd, "--------------- Views From Root Frame----------------\n");
3419 nsIView* v = aRootFrame->GetView();
3420 if (v) {
3421 v->List(fd);
3422 } else {
3423 printf("View is null!\n");
3425 if (aDocShell) {
3426 fprintf(fd, "--------------- All Views ----------------\n");
3427 DumpViews(aDocShell, fd);
3428 fprintf(fd, "---------------------------------------\n\n");
3430 if (aFD == nsnull) {
3431 fclose(fd);
3436 //-------------------------------------------------------------
3437 static void DumpPrintObjectsList(nsVoidArray * aDocList)
3439 if (!kPrintingLogMod || kPrintingLogMod->level != DUMP_LAYOUT_LEVEL) return;
3441 NS_ASSERTION(aDocList, "Pointer is null!");
3443 const char types[][3] = {"DC", "FR", "IF", "FS"};
3444 PR_PL(("Doc List\n***************************************************\n"));
3445 PR_PL(("T P A H PO DocShell Seq Page Root Page# Rect\n"));
3446 PRInt32 cnt = aDocList->Count();
3447 for (PRInt32 i=0;i<cnt;i++) {
3448 nsPrintObject* po = (nsPrintObject*)aDocList->ElementAt(i);
3449 NS_ASSERTION(po, "nsPrintObject can't be null!");
3450 nsIFrame* rootFrame = nsnull;
3451 if (po->mPresShell) {
3452 rootFrame = po->mPresShell->FrameManager()->GetRootFrame();
3453 while (rootFrame != nsnull) {
3454 nsIPageSequenceFrame * sqf = nsnull;
3455 if (NS_SUCCEEDED(CallQueryInterface(rootFrame, &sqf))) {
3456 break;
3458 rootFrame = rootFrame->GetFirstChild(nsnull);
3462 PR_PL(("%s %d %d %d %p %p %p %p %p %d %d,%d,%d,%d\n", types[po->mFrameType],
3463 po->IsPrintable(), po->mPrintAsIs, po->mHasBeenPrinted, po, po->mDocShell.get(), po->mSeqFrame,
3464 po->mPageFrame, rootFrame, po->mPageNum, po->mRect.x, po->mRect.y, po->mRect.width, po->mRect.height));
3468 //-------------------------------------------------------------
3469 static void DumpPrintObjectsTree(nsPrintObject * aPO, int aLevel, FILE* aFD)
3471 if (!kPrintingLogMod || kPrintingLogMod->level != DUMP_LAYOUT_LEVEL) return;
3473 NS_ASSERTION(aPO, "Pointer is null!");
3475 FILE * fd = aFD?aFD:stdout;
3476 const char types[][3] = {"DC", "FR", "IF", "FS"};
3477 if (aLevel == 0) {
3478 fprintf(fd, "DocTree\n***************************************************\n");
3479 fprintf(fd, "T PO DocShell Seq Page Page# Rect\n");
3481 PRInt32 cnt = aPO->mKids.Count();
3482 for (PRInt32 i=0;i<cnt;i++) {
3483 nsPrintObject* po = (nsPrintObject*)aPO->mKids.ElementAt(i);
3484 NS_ASSERTION(po, "nsPrintObject can't be null!");
3485 for (PRInt32 k=0;k<aLevel;k++) fprintf(fd, " ");
3486 fprintf(fd, "%s %p %p %p %p %d %d,%d,%d,%d\n", types[po->mFrameType], po, po->mDocShell.get(), po->mSeqFrame,
3487 po->mPageFrame, po->mPageNum, po->mRect.x, po->mRect.y, po->mRect.width, po->mRect.height);
3491 //-------------------------------------------------------------
3492 static void GetDocTitleAndURL(nsPrintObject* aPO, char *& aDocStr, char *& aURLStr)
3494 aDocStr = nsnull;
3495 aURLStr = nsnull;
3497 PRUnichar * docTitleStr;
3498 PRUnichar * docURLStr;
3499 nsPrintEngine::GetDisplayTitleAndURL(aPO,
3500 &docTitleStr, &docURLStr,
3501 nsPrintEngine::eDocTitleDefURLDoc);
3503 if (docTitleStr) {
3504 nsAutoString strDocTitle(docTitleStr);
3505 aDocStr = ToNewCString(strDocTitle);
3506 nsMemory::Free(docTitleStr);
3509 if (docURLStr) {
3510 nsAutoString strURL(docURLStr);
3511 aURLStr = ToNewCString(strURL);
3512 nsMemory::Free(docURLStr);
3516 //-------------------------------------------------------------
3517 static void DumpPrintObjectsTreeLayout(nsPrintObject * aPO,
3518 nsIDeviceContext * aDC,
3519 int aLevel, FILE * aFD)
3521 if (!kPrintingLogMod || kPrintingLogMod->level != DUMP_LAYOUT_LEVEL) return;
3523 NS_ASSERTION(aPO, "Pointer is null!");
3524 NS_ASSERTION(aDC, "Pointer is null!");
3526 const char types[][3] = {"DC", "FR", "IF", "FS"};
3527 FILE * fd = nsnull;
3528 if (aLevel == 0) {
3529 fd = fopen("tree_layout.txt", "w");
3530 fprintf(fd, "DocTree\n***************************************************\n");
3531 fprintf(fd, "***************************************************\n");
3532 fprintf(fd, "T PO DocShell Seq Page Page# Rect\n");
3533 } else {
3534 fd = aFD;
3536 if (fd) {
3537 nsIFrame* rootFrame = nsnull;
3538 if (aPO->mPresShell) {
3539 rootFrame = aPO->mPresShell->FrameManager()->GetRootFrame();
3541 for (PRInt32 k=0;k<aLevel;k++) fprintf(fd, " ");
3542 fprintf(fd, "%s %p %p %p %p %d %d,%d,%d,%d\n", types[aPO->mFrameType], aPO, aPO->mDocShell.get(), aPO->mSeqFrame,
3543 aPO->mPageFrame, aPO->mPageNum, aPO->mRect.x, aPO->mRect.y, aPO->mRect.width, aPO->mRect.height);
3544 if (aPO->IsPrintable()) {
3545 char * docStr;
3546 char * urlStr;
3547 GetDocTitleAndURL(aPO, docStr, urlStr);
3548 DumpLayoutData(docStr, urlStr, aPO->mPresContext, aDC, rootFrame, aPO->mDocShell, fd);
3549 if (docStr) nsMemory::Free(docStr);
3550 if (urlStr) nsMemory::Free(urlStr);
3552 fprintf(fd, "<***************************************************>\n");
3554 PRInt32 cnt = aPO->mKids.Count();
3555 for (PRInt32 i=0;i<cnt;i++) {
3556 nsPrintObject* po = (nsPrintObject*)aPO->mKids.ElementAt(i);
3557 NS_ASSERTION(po, "nsPrintObject can't be null!");
3558 DumpPrintObjectsTreeLayout(po, aDC, aLevel+1, fd);
3561 if (aLevel == 0 && fd) {
3562 fclose(fd);
3566 //-------------------------------------------------------------
3567 static void DumpPrintObjectsListStart(const char * aStr, nsVoidArray * aDocList)
3569 if (!kPrintingLogMod || kPrintingLogMod->level != DUMP_LAYOUT_LEVEL) return;
3571 NS_ASSERTION(aStr, "Pointer is null!");
3572 NS_ASSERTION(aDocList, "Pointer is null!");
3574 PR_PL(("%s\n", aStr));
3575 DumpPrintObjectsList(aDocList);
3578 #define DUMP_DOC_LIST(_title) DumpPrintObjectsListStart((_title), mPrt->mPrintDocList);
3579 #define DUMP_DOC_TREE DumpPrintObjectsTree(mPrt->mPrintObject);
3580 #define DUMP_DOC_TREELAYOUT DumpPrintObjectsTreeLayout(mPrt->mPrintObject, mPrt->mPrintDC);
3582 #else
3583 #define DUMP_DOC_LIST(_title)
3584 #define DUMP_DOC_TREE
3585 #define DUMP_DOC_TREELAYOUT
3586 #endif
3588 //---------------------------------------------------------------
3589 //---------------------------------------------------------------
3590 //-- End of debug helper routines
3591 //---------------------------------------------------------------