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