Backed out changeset b88172246b66 due to Win32 debug failures.
[mozilla-central.git] / layout / printing / nsPrintEngine.cpp
blobe65d92a4a0cf14efcae9d5934e98aaccc4e2e103
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 "nsITextToSubURI.h"
51 #include "nsContentErrors.h"
53 // Print Options
54 #include "nsIPrintSettings.h"
55 #include "nsIPrintSettingsService.h"
56 #include "nsIPrintOptions.h"
57 #include "nsIPrintSession.h"
58 #include "nsGfxCIID.h"
59 #include "nsIServiceManager.h"
60 #include "nsGkAtoms.h"
61 #include "nsXPCOM.h"
62 #include "nsISupportsPrimitives.h"
64 static const char sPrintSettingsServiceContractID[] = "@mozilla.org/gfx/printsettings-service;1";
66 // Printing Events
67 #include "nsPrintPreviewListener.h"
68 #include "nsThreadUtils.h"
70 // Printing
71 #include "nsIWebBrowserPrint.h"
72 #include "nsIDOMHTMLFrameElement.h"
73 #include "nsIDOMHTMLFrameSetElement.h"
74 #include "nsIDOMHTMLIFrameElement.h"
75 #include "nsIDOMHTMLObjectElement.h"
76 #include "nsIDOMHTMLEmbedElement.h"
78 // Print Preview
79 #include "imgIContainer.h" // image animation mode constants
80 #include "nsIWebBrowserPrint.h" // needed for PrintPreview Navigation constants
82 // Print Progress
83 #include "nsIPrintProgress.h"
84 #include "nsIPrintProgressParams.h"
85 #include "nsIObserver.h"
87 // Print error dialog
88 #include "nsIPrompt.h"
89 #include "nsIWindowWatcher.h"
90 #include "nsIStringBundle.h"
92 // Printing Prompts
93 #include "nsIPrintingPromptService.h"
94 static const char kPrintingPromptService[] = "@mozilla.org/embedcomp/printingprompt-service;1";
96 // Printing Timer
97 #include "nsPagePrintTimer.h"
99 // FrameSet
100 #include "nsIDocument.h"
102 // Focus
103 #include "nsIDOMEventTarget.h"
104 #include "nsIDOMFocusListener.h"
105 #include "nsISelectionController.h"
107 // Misc
108 #include "nsISupportsUtils.h"
109 #include "nsIFrame.h"
110 #include "nsIScriptContext.h"
111 #include "nsILinkHandler.h"
112 #include "nsIDOMDocument.h"
113 #include "nsISelectionListener.h"
114 #include "nsISelectionPrivate.h"
115 #include "nsIDOMHTMLDocument.h"
116 #include "nsIDOMNSDocument.h"
117 #include "nsIDOMNSHTMLDocument.h"
118 #include "nsIDOMHTMLCollection.h"
119 #include "nsIDOMHTMLElement.h"
120 #include "nsIDOMRange.h"
121 #include "nsContentCID.h"
122 #include "nsLayoutCID.h"
123 #include "nsContentUtils.h"
124 #include "nsIPresShell.h"
125 #include "nsLayoutUtils.h"
127 #include "nsViewsCID.h"
128 #include "nsWidgetsCID.h"
129 #include "nsIDeviceContext.h"
130 #include "nsIDeviceContextSpec.h"
131 #include "nsIViewManager.h"
132 #include "nsIView.h"
134 #include "nsIPageSequenceFrame.h"
135 #include "nsIURL.h"
136 #include "nsIContentViewerEdit.h"
137 #include "nsIContentViewerFile.h"
138 #include "nsIMarkupDocumentViewer.h"
139 #include "nsIInterfaceRequestor.h"
140 #include "nsIInterfaceRequestorUtils.h"
141 #include "nsIDocShellTreeItem.h"
142 #include "nsIDocShellTreeNode.h"
143 #include "nsIDocShellTreeOwner.h"
144 #include "nsIWebBrowserChrome.h"
145 #include "nsIDocShell.h"
146 #include "nsIBaseWindow.h"
147 #include "nsILayoutHistoryState.h"
148 #include "nsFrameManager.h"
149 #include "nsIParser.h"
150 #include "nsGUIEvent.h"
151 #include "nsHTMLReflowState.h"
152 #include "nsIDOMHTMLAnchorElement.h"
153 #include "nsIDOMHTMLAreaElement.h"
154 #include "nsIDOMHTMLLinkElement.h"
155 #include "nsIDOMHTMLImageElement.h"
156 #include "nsIContentViewerContainer.h"
157 #include "nsIContentViewer.h"
158 #include "nsIDocumentViewer.h"
159 #include "nsIDocumentViewerPrint.h"
161 #include "nsPIDOMWindow.h"
162 #include "nsFocusManager.h"
163 #include "nsRange.h"
164 #include "nsCDefaultURIFixup.h"
165 #include "nsIURIFixup.h"
166 #include "mozilla/dom/Element.h"
168 using namespace mozilla::dom;
170 //-----------------------------------------------------
171 // PR LOGGING
172 #ifdef MOZ_LOGGING
173 #define FORCE_PR_LOG /* Allow logging in the release build */
174 #endif
176 #include "prlog.h"
178 #ifdef PR_LOGGING
180 #ifdef NS_DEBUG
181 // PR_LOGGING is force to always be on (even in release builds)
182 // but we only want some of it on,
183 //#define EXTENDED_DEBUG_PRINTING
184 #endif
186 #define DUMP_LAYOUT_LEVEL 9 // this turns on the dumping of each doucment's layout info
188 static PRLogModuleInfo * kPrintingLogMod = PR_NewLogModule("printing");
189 #define PR_PL(_p1) PR_LOG(kPrintingLogMod, PR_LOG_DEBUG, _p1);
191 #ifdef EXTENDED_DEBUG_PRINTING
192 static PRUint32 gDumpFileNameCnt = 0;
193 static PRUint32 gDumpLOFileNameCnt = 0;
194 #endif
196 #define PRT_YESNO(_p) ((_p)?"YES":"NO")
197 static const char * gFrameTypesStr[] = {"eDoc", "eFrame", "eIFrame", "eFrameSet"};
198 static const char * gPrintFrameTypeStr[] = {"kNoFrames", "kFramesAsIs", "kSelectedFrame", "kEachFrameSep"};
199 static const char * gFrameHowToEnableStr[] = {"kFrameEnableNone", "kFrameEnableAll", "kFrameEnableAsIsAndEach"};
200 static const char * gPrintRangeStr[] = {"kRangeAllPages", "kRangeSpecifiedPageRange", "kRangeSelection", "kRangeFocusFrame"};
201 #else
202 #define PRT_YESNO(_p)
203 #define PR_PL(_p1)
204 #endif
206 #ifdef EXTENDED_DEBUG_PRINTING
207 // Forward Declarations
208 static void DumpPrintObjectsListStart(const char * aStr, nsTArray<nsPrintObject*> * aDocList);
209 static void DumpPrintObjectsTree(nsPrintObject * aPO, int aLevel= 0, FILE* aFD = nsnull);
210 static void DumpPrintObjectsTreeLayout(nsPrintObject * aPO,nsIDeviceContext * aDC, int aLevel= 0, FILE * aFD = nsnull);
212 #define DUMP_DOC_LIST(_title) DumpPrintObjectsListStart((_title), mPrt->mPrintDocList);
213 #define DUMP_DOC_TREE DumpPrintObjectsTree(mPrt->mPrintObject);
214 #define DUMP_DOC_TREELAYOUT DumpPrintObjectsTreeLayout(mPrt->mPrintObject, mPrt->mPrintDC);
215 #else
216 #define DUMP_DOC_LIST(_title)
217 #define DUMP_DOC_TREE
218 #define DUMP_DOC_TREELAYOUT
219 #endif
221 class nsScriptSuppressor
223 public:
224 nsScriptSuppressor(nsPrintEngine* aPrintEngine)
225 : mPrintEngine(aPrintEngine), mSuppressed(PR_FALSE) {}
227 ~nsScriptSuppressor() { Unsuppress(); }
229 void Suppress()
231 if (mPrintEngine) {
232 mSuppressed = PR_TRUE;
233 mPrintEngine->TurnScriptingOn(PR_FALSE);
237 void Unsuppress()
239 if (mPrintEngine && mSuppressed) {
240 mPrintEngine->TurnScriptingOn(PR_TRUE);
242 mSuppressed = PR_FALSE;
245 void Disconnect() { mPrintEngine = nsnull; }
246 protected:
247 nsRefPtr<nsPrintEngine> mPrintEngine;
248 PRBool mSuppressed;
251 // Class IDs
252 static NS_DEFINE_CID(kViewManagerCID, NS_VIEW_MANAGER_CID);
254 NS_IMPL_ISUPPORTS1(nsPrintEngine, nsIObserver)
256 //---------------------------------------------------
257 //-- nsPrintEngine Class Impl
258 //---------------------------------------------------
259 nsPrintEngine::nsPrintEngine() :
260 mIsCreatingPrintPreview(PR_FALSE),
261 mIsDoingPrinting(PR_FALSE),
262 mIsDoingPrintPreview(PR_FALSE),
263 mProgressDialogIsShown(PR_FALSE),
264 mContainer(nsnull),
265 mScreenDPI(115.0f),
266 mPrt(nsnull),
267 mPagePrintTimer(nsnull),
268 mPageSeqFrame(nsnull),
269 mPrtPreview(nsnull),
270 mOldPrtPreview(nsnull),
271 mDebugFile(nsnull)
275 //-------------------------------------------------------
276 nsPrintEngine::~nsPrintEngine()
278 Destroy(); // for insurance
281 //-------------------------------------------------------
282 void nsPrintEngine::Destroy()
284 if (mPrt) {
285 delete mPrt;
286 mPrt = nsnull;
289 #ifdef NS_PRINT_PREVIEW
290 if (mPrtPreview) {
291 delete mPrtPreview;
292 mPrtPreview = nsnull;
295 // This is insruance
296 if (mOldPrtPreview) {
297 delete mOldPrtPreview;
298 mOldPrtPreview = nsnull;
301 #endif
302 mDocViewerPrint = nsnull;
305 //-------------------------------------------------------
306 void nsPrintEngine::DestroyPrintingData()
308 if (mPrt) {
309 delete mPrt;
310 mPrt = nsnull;
314 //---------------------------------------------------------------------------------
315 //-- Section: Methods needed by the DocViewer
316 //---------------------------------------------------------------------------------
318 //--------------------------------------------------------
319 nsresult nsPrintEngine::Initialize(nsIDocumentViewerPrint* aDocViewerPrint,
320 nsISupports* aContainer,
321 nsIDocument* aDocument,
322 float aScreenDPI,
323 FILE* aDebugFile)
325 NS_ENSURE_ARG_POINTER(aDocViewerPrint);
326 NS_ENSURE_ARG_POINTER(aContainer);
327 NS_ENSURE_ARG_POINTER(aDocument);
329 mDocViewerPrint = aDocViewerPrint;
330 mContainer = aContainer; // weak reference
331 mDocument = aDocument;
332 mScreenDPI = aScreenDPI;
334 mDebugFile = aDebugFile; // ok to be NULL
336 return NS_OK;
339 //-------------------------------------------------------
340 PRBool
341 nsPrintEngine::CheckBeforeDestroy()
343 if (mPrt && mPrt->mPreparingForPrint) {
344 mPrt->mDocWasToBeDestroyed = PR_TRUE;
345 return PR_TRUE;
347 return PR_FALSE;
350 //-------------------------------------------------------
351 nsresult
352 nsPrintEngine::Cancelled()
354 if (mPrt && mPrt->mPrintSettings) {
355 return mPrt->mPrintSettings->SetIsCancelled(PR_TRUE);
357 return NS_ERROR_FAILURE;
360 //-------------------------------------------------------
361 // Install our event listeners on the document to prevent
362 // some events from being processed while in PrintPreview
364 // No return code - if this fails, there isn't much we can do
365 void
366 nsPrintEngine::InstallPrintPreviewListener()
368 if (!mPrt->mPPEventListeners) {
369 nsCOMPtr<nsPIDOMWindow> win(do_GetInterface(mContainer));
370 nsCOMPtr<nsIDOMEventTarget> target(do_QueryInterface(win->GetFrameElementInternal()));
371 mPrt->mPPEventListeners = new nsPrintPreviewListener(target);
373 if (mPrt->mPPEventListeners) {
374 mPrt->mPPEventListeners->AddListeners();
379 //----------------------------------------------------------------------
380 nsresult
381 nsPrintEngine::GetSeqFrameAndCountPagesInternal(nsPrintObject* aPO,
382 nsIFrame*& aSeqFrame,
383 PRInt32& aCount)
385 NS_ENSURE_ARG_POINTER(aPO);
387 // Finds the SimplePageSequencer frame
388 nsIPageSequenceFrame* seqFrame = aPO->mPresShell->GetPageSequenceFrame();
389 if (seqFrame) {
390 aSeqFrame = do_QueryFrame(seqFrame);
391 } else {
392 aSeqFrame = nsnull;
394 if (aSeqFrame == nsnull) return NS_ERROR_FAILURE;
396 // first count the total number of pages
397 aCount = 0;
398 nsIFrame* pageFrame = aSeqFrame->GetFirstChild(nsnull);
399 while (pageFrame != nsnull) {
400 aCount++;
401 pageFrame = pageFrame->GetNextSibling();
404 return NS_OK;
408 //-----------------------------------------------------------------
409 nsresult nsPrintEngine::GetSeqFrameAndCountPages(nsIFrame*& aSeqFrame, PRInt32& aCount)
411 NS_ASSERTION(mPrtPreview, "mPrtPreview can't be null!");
412 return GetSeqFrameAndCountPagesInternal(mPrtPreview->mPrintObject, aSeqFrame, aCount);
414 //---------------------------------------------------------------------------------
415 //-- Done: Methods needed by the DocViewer
416 //---------------------------------------------------------------------------------
419 //---------------------------------------------------------------------------------
420 //-- Section: nsIWebBrowserPrint
421 //---------------------------------------------------------------------------------
423 // Foward decl for Debug Helper Functions
424 #ifdef EXTENDED_DEBUG_PRINTING
425 static int RemoveFilesInDir(const char * aDir);
426 static void GetDocTitleAndURL(nsPrintObject* aPO, char *& aDocStr, char *& aURLStr);
427 static void DumpPrintObjectsTree(nsPrintObject * aPO, int aLevel, FILE* aFD);
428 static void DumpPrintObjectsList(nsTArray<nsPrintObject*> * aDocList);
429 static void RootFrameList(nsPresContext* aPresContext, FILE* out, PRInt32 aIndent);
430 static void DumpViews(nsIDocShell* aDocShell, FILE* out);
431 static void DumpLayoutData(char* aTitleStr, char* aURLStr,
432 nsPresContext* aPresContext,
433 nsIDeviceContext * aDC, nsIFrame * aRootFrame,
434 nsIDocShell * aDocShell, FILE* aFD);
435 #endif
437 //--------------------------------------------------------------------------------
439 nsresult
440 nsPrintEngine::CommonPrint(PRBool aIsPrintPreview,
441 nsIPrintSettings* aPrintSettings,
442 nsIWebProgressListener* aWebProgressListener,
443 nsIDOMDocument* aDoc) {
444 nsresult rv = DoCommonPrint(aIsPrintPreview, aPrintSettings,
445 aWebProgressListener, aDoc);
446 if (NS_FAILED(rv)) {
447 if (aIsPrintPreview) {
448 SetIsCreatingPrintPreview(PR_FALSE);
449 SetIsPrintPreview(PR_FALSE);
450 } else {
451 SetIsPrinting(PR_FALSE);
453 if (mProgressDialogIsShown)
454 CloseProgressDialog(aWebProgressListener);
455 if (rv != NS_ERROR_ABORT && rv != NS_ERROR_OUT_OF_MEMORY)
456 ShowPrintErrorDialog(rv, !aIsPrintPreview);
457 delete mPrt;
458 mPrt = nsnull;
461 return rv;
464 nsresult
465 nsPrintEngine::DoCommonPrint(PRBool aIsPrintPreview,
466 nsIPrintSettings* aPrintSettings,
467 nsIWebProgressListener* aWebProgressListener,
468 nsIDOMDocument* aDoc)
470 nsresult rv;
472 if (aIsPrintPreview) {
473 // The WebProgressListener can be QI'ed to nsIPrintingPromptService
474 // then that means the progress dialog is already being shown.
475 nsCOMPtr<nsIPrintingPromptService> pps(do_QueryInterface(aWebProgressListener));
476 mProgressDialogIsShown = pps != nsnull;
478 if (mIsDoingPrintPreview) {
479 mOldPrtPreview = mPrtPreview;
480 mPrtPreview = nsnull;
482 } else {
483 mProgressDialogIsShown = PR_FALSE;
486 mPrt = new nsPrintData(aIsPrintPreview ? nsPrintData::eIsPrintPreview :
487 nsPrintData::eIsPrinting);
488 NS_ENSURE_TRUE(mPrt, NS_ERROR_OUT_OF_MEMORY);
490 // if they don't pass in a PrintSettings, then get the Global PS
491 mPrt->mPrintSettings = aPrintSettings;
492 if (!mPrt->mPrintSettings) {
493 rv = GetGlobalPrintSettings(getter_AddRefs(mPrt->mPrintSettings));
494 NS_ENSURE_SUCCESS(rv, rv);
497 rv = CheckForPrinters(mPrt->mPrintSettings);
498 NS_ENSURE_SUCCESS(rv, rv);
500 mPrt->mPrintSettings->SetIsCancelled(PR_FALSE);
501 mPrt->mPrintSettings->GetShrinkToFit(&mPrt->mShrinkToFit);
503 if (aIsPrintPreview) {
504 SetIsCreatingPrintPreview(PR_TRUE);
505 SetIsPrintPreview(PR_TRUE);
506 nsCOMPtr<nsIMarkupDocumentViewer> viewer =
507 do_QueryInterface(mDocViewerPrint);
508 if (viewer) {
509 viewer->SetTextZoom(1.0f);
510 viewer->SetFullZoom(1.0f);
512 } else {
513 SetIsPrinting(PR_TRUE);
516 // Create a print session and let the print settings know about it.
517 // The print settings hold an nsWeakPtr to the session so it does not
518 // need to be cleared from the settings at the end of the job.
519 // XXX What lifetime does the printSession need to have?
520 nsCOMPtr<nsIPrintSession> printSession;
521 if (!aIsPrintPreview) {
522 printSession = do_CreateInstance("@mozilla.org/gfx/printsession;1", &rv);
523 NS_ENSURE_SUCCESS(rv, rv);
524 mPrt->mPrintSettings->SetPrintSession(printSession);
527 if (aWebProgressListener != nsnull) {
528 mPrt->mPrintProgressListeners.AppendObject(aWebProgressListener);
531 // Get the currently focused window and cache it
532 // because the Print Dialog will "steal" focus and later when you try
533 // to get the currently focused windows it will be NULL
534 mPrt->mCurrentFocusWin = FindFocusedDOMWindow();
536 // Check to see if there is a "regular" selection
537 PRBool isSelection = IsThereARangeSelection(mPrt->mCurrentFocusWin);
539 // Get the docshell for this documentviewer
540 nsCOMPtr<nsIDocShell> webContainer(do_QueryInterface(mContainer, &rv));
541 NS_ENSURE_SUCCESS(rv, rv);
543 mPrt->mPrintObject = new nsPrintObject();
544 NS_ENSURE_TRUE(mPrt->mPrintObject, NS_ERROR_OUT_OF_MEMORY);
545 rv = mPrt->mPrintObject->Init(webContainer, aDoc, aIsPrintPreview);
546 NS_ENSURE_SUCCESS(rv, rv);
548 NS_ENSURE_TRUE(mPrt->mPrintDocList.AppendElement(mPrt->mPrintObject),
549 NS_ERROR_OUT_OF_MEMORY);
551 mPrt->mIsParentAFrameSet = IsParentAFrameSet(webContainer);
552 mPrt->mPrintObject->mFrameType = mPrt->mIsParentAFrameSet ? eFrameSet : eDoc;
554 // Build the "tree" of PrintObjects
555 nsCOMPtr<nsIDocShellTreeNode> parentAsNode =
556 do_QueryInterface(mPrt->mPrintObject->mDocShell);
557 BuildDocTree(parentAsNode, &mPrt->mPrintDocList, mPrt->mPrintObject);
559 // XXX This isn't really correct...
560 if (!mPrt->mPrintObject->mDocument ||
561 !mPrt->mPrintObject->mDocument->GetRootElement())
562 return NS_ERROR_GFX_PRINTER_STARTDOC;
564 // Create the linkage from the sub-docs back to the content element
565 // in the parent document
566 MapContentToWebShells(mPrt->mPrintObject, mPrt->mPrintObject);
568 mPrt->mIsIFrameSelected = IsThereAnIFrameSelected(webContainer, mPrt->mCurrentFocusWin, mPrt->mIsParentAFrameSet);
570 // Setup print options for UI
571 if (mPrt->mIsParentAFrameSet) {
572 if (mPrt->mCurrentFocusWin) {
573 mPrt->mPrintSettings->SetHowToEnableFrameUI(nsIPrintSettings::kFrameEnableAll);
574 } else {
575 mPrt->mPrintSettings->SetHowToEnableFrameUI(nsIPrintSettings::kFrameEnableAsIsAndEach);
577 } else {
578 mPrt->mPrintSettings->SetHowToEnableFrameUI(nsIPrintSettings::kFrameEnableNone);
580 // Now determine how to set up the Frame print UI
581 mPrt->mPrintSettings->SetPrintOptions(nsIPrintSettings::kEnableSelectionRB, isSelection || mPrt->mIsIFrameSelected);
583 nsCOMPtr<nsIDeviceContextSpec> devspec
584 (do_CreateInstance("@mozilla.org/gfx/devicecontextspec;1", &rv));
585 NS_ENSURE_SUCCESS(rv, rv);
587 nsScriptSuppressor scriptSuppressor(this);
588 if (!aIsPrintPreview) {
589 #ifdef NS_DEBUG
590 mPrt->mDebugFilePtr = mDebugFile;
591 #endif
593 scriptSuppressor.Suppress();
594 PRBool printSilently;
595 mPrt->mPrintSettings->GetPrintSilent(&printSilently);
597 // Check prefs for a default setting as to whether we should print silently
598 printSilently = nsContentUtils::GetBoolPref("print.always_print_silent",
599 printSilently);
601 // Ask dialog to be Print Shown via the Plugable Printing Dialog Service
602 // This service is for the Print Dialog and the Print Progress Dialog
603 // If printing silently or you can't get the service continue on
604 if (!printSilently) {
605 nsCOMPtr<nsIPrintingPromptService> printPromptService(do_GetService(kPrintingPromptService));
606 if (printPromptService) {
607 nsIDOMWindow *domWin = mDocument->GetWindow();
608 NS_ENSURE_TRUE(domWin, NS_ERROR_FAILURE);
610 // Platforms not implementing a given dialog for the service may
611 // return NS_ERROR_NOT_IMPLEMENTED or an error code.
613 // NS_ERROR_NOT_IMPLEMENTED indicates they want default behavior
614 // Any other error code means we must bail out
616 nsCOMPtr<nsIWebBrowserPrint> wbp(do_QueryInterface(mDocViewerPrint));
617 rv = printPromptService->ShowPrintDialog(domWin, wbp,
618 mPrt->mPrintSettings);
620 // ShowPrintDialog triggers an event loop which means we can't assume
621 // that the state of this->{anything} matches the state we've checked
622 // above. Including that a given {thing} is non null.
624 if (NS_SUCCEEDED(rv)) {
625 // since we got the dialog and it worked then make sure we
626 // are telling GFX we want to print silent
627 printSilently = PR_TRUE;
629 if (mPrt && mPrt->mPrintSettings) {
630 // The user might have changed shrink-to-fit in the print dialog, so update our copy of its state
631 mPrt->mPrintSettings->GetShrinkToFit(&mPrt->mShrinkToFit);
633 } else if (rv == NS_ERROR_NOT_IMPLEMENTED) {
634 // This means the Dialog service was there,
635 // but they choose not to implement this dialog and
636 // are looking for default behavior from the toolkit
637 rv = NS_OK;
639 } else {
640 rv = NS_ERROR_GFX_NO_PRINTROMPTSERVICE;
642 } else {
643 // Call any code that requires a run of the event loop.
644 rv = mPrt->mPrintSettings->SetupSilentPrinting();
646 // Check explicitly for abort because it's expected
647 if (rv == NS_ERROR_ABORT)
648 return rv;
649 NS_ENSURE_SUCCESS(rv, rv);
652 rv = devspec->Init(nsnull, mPrt->mPrintSettings, aIsPrintPreview);
653 NS_ENSURE_SUCCESS(rv, rv);
655 mPrt->mPrintDC = do_CreateInstance("@mozilla.org/gfx/devicecontext;1", &rv);
656 NS_ENSURE_SUCCESS(rv, rv);
657 rv = mPrt->mPrintDC->InitForPrinting(devspec);
658 NS_ENSURE_SUCCESS(rv, rv);
660 if (aIsPrintPreview) {
661 mPrt->mPrintSettings->SetPrintFrameType(nsIPrintSettings::kFramesAsIs);
663 // override any UI that wants to PrintPreview any selection or page range
664 // we want to view every page in PrintPreview each time
665 mPrt->mPrintSettings->SetPrintRange(nsIPrintSettings::kRangeAllPages);
666 } else {
667 // Always check and set the print settings first and then fall back
668 // onto the PrintService if there isn't a PrintSettings
670 // Posiible Usage values:
671 // nsIPrintSettings::kUseInternalDefault
672 // nsIPrintSettings::kUseSettingWhenPossible
674 // NOTE: The consts are the same for PrintSettings and PrintSettings
675 PRInt16 printFrameTypeUsage = nsIPrintSettings::kUseSettingWhenPossible;
676 mPrt->mPrintSettings->GetPrintFrameTypeUsage(&printFrameTypeUsage);
678 // Ok, see if we are going to use our value and override the default
679 if (printFrameTypeUsage == nsIPrintSettings::kUseSettingWhenPossible) {
680 // Get the Print Options/Settings PrintFrameType to see what is preferred
681 PRInt16 printFrameType = nsIPrintSettings::kEachFrameSep;
682 mPrt->mPrintSettings->GetPrintFrameType(&printFrameType);
684 // Don't let anybody do something stupid like try to set it to
685 // kNoFrames when we are printing a FrameSet
686 if (printFrameType == nsIPrintSettings::kNoFrames) {
687 mPrt->mPrintFrameType = nsIPrintSettings::kEachFrameSep;
688 mPrt->mPrintSettings->SetPrintFrameType(mPrt->mPrintFrameType);
689 } else {
690 // First find out from the PrinService what options are available
691 // to us for Printing FrameSets
692 PRInt16 howToEnableFrameUI;
693 mPrt->mPrintSettings->GetHowToEnableFrameUI(&howToEnableFrameUI);
694 if (howToEnableFrameUI != nsIPrintSettings::kFrameEnableNone) {
695 switch (howToEnableFrameUI) {
696 case nsIPrintSettings::kFrameEnableAll:
697 mPrt->mPrintFrameType = printFrameType;
698 break;
700 case nsIPrintSettings::kFrameEnableAsIsAndEach:
701 if (printFrameType != nsIPrintSettings::kSelectedFrame) {
702 mPrt->mPrintFrameType = printFrameType;
703 } else { // revert back to a good value
704 mPrt->mPrintFrameType = nsIPrintSettings::kEachFrameSep;
706 break;
707 } // switch
708 mPrt->mPrintSettings->SetPrintFrameType(mPrt->mPrintFrameType);
711 } else {
712 mPrt->mPrintSettings->GetPrintFrameType(&mPrt->mPrintFrameType);
716 if (aIsPrintPreview) {
717 PRBool notifyOnInit = PR_FALSE;
718 ShowPrintProgress(PR_FALSE, notifyOnInit);
720 // Very important! Turn Off scripting
721 TurnScriptingOn(PR_FALSE);
723 if (!notifyOnInit) {
724 rv = FinishPrintPreview();
725 } else {
726 rv = NS_OK;
728 NS_ENSURE_SUCCESS(rv, rv);
729 } else {
730 PRUnichar * docTitleStr;
731 PRUnichar * docURLStr;
733 GetDisplayTitleAndURL(mPrt->mPrintObject, &docTitleStr, &docURLStr, eDocTitleDefURLDoc);
735 // Nobody ever cared about the file name passed in, as far as I can tell
736 rv = mPrt->mPrintDC->PrepareDocument(docTitleStr, nsnull);
738 if (docTitleStr) nsMemory::Free(docTitleStr);
739 if (docURLStr) nsMemory::Free(docURLStr);
741 NS_ENSURE_SUCCESS(rv, rv);
743 PRBool doNotify;
744 ShowPrintProgress(PR_TRUE, doNotify);
745 if (!doNotify) {
746 // Print listener setup...
747 mPrt->OnStartPrinting();
748 rv = DocumentReadyForPrinting();
749 NS_ENSURE_SUCCESS(rv, rv);
753 // We will enable scripting later after printing has finished.
754 scriptSuppressor.Disconnect();
756 return NS_OK;
759 //---------------------------------------------------------------------------------
760 NS_IMETHODIMP
761 nsPrintEngine::Print(nsIPrintSettings* aPrintSettings,
762 nsIWebProgressListener* aWebProgressListener)
764 // If we have a print preview document, use that instead of the original
765 // mDocument. That way animated images etc. get printed using the same state
766 // as in print preview.
767 nsCOMPtr<nsIDOMDocument> doc =
768 do_QueryInterface(mPrtPreview && mPrtPreview->mPrintObject ?
769 mPrtPreview->mPrintObject->mDocument : mDocument);
771 return CommonPrint(PR_FALSE, aPrintSettings, aWebProgressListener, doc);
774 NS_IMETHODIMP
775 nsPrintEngine::PrintPreview(nsIPrintSettings* aPrintSettings,
776 nsIDOMWindow *aChildDOMWin,
777 nsIWebProgressListener* aWebProgressListener)
779 // Get the DocShell and see if it is busy
780 // (We can't Print Preview this document if it is still busy)
781 nsCOMPtr<nsIDocShell> docShell(do_QueryInterface(mContainer));
782 NS_ASSERTION(docShell, "This has to be a docshell");
784 PRUint32 busyFlags = nsIDocShell::BUSY_FLAGS_NONE;
785 if (NS_FAILED(docShell->GetBusyFlags(&busyFlags)) ||
786 busyFlags != nsIDocShell::BUSY_FLAGS_NONE) {
787 CloseProgressDialog(aWebProgressListener);
788 ShowPrintErrorDialog(NS_ERROR_GFX_PRINTER_DOC_IS_BUSY_PP, PR_FALSE);
789 return NS_ERROR_FAILURE;
792 NS_ENSURE_STATE(aChildDOMWin);
793 nsCOMPtr<nsIDOMDocument> doc;
794 aChildDOMWin->GetDocument(getter_AddRefs(doc));
795 NS_ENSURE_STATE(doc);
797 // Document is not busy -- go ahead with the Print Preview
798 return CommonPrint(PR_TRUE, aPrintSettings, aWebProgressListener, doc);
801 //----------------------------------------------------------------------------------
802 /* readonly attribute boolean isFramesetDocument; */
803 NS_IMETHODIMP
804 nsPrintEngine::GetIsFramesetDocument(PRBool *aIsFramesetDocument)
806 nsCOMPtr<nsIDocShell> webContainer(do_QueryInterface(mContainer));
807 *aIsFramesetDocument = IsParentAFrameSet(webContainer);
808 return NS_OK;
811 //----------------------------------------------------------------------------------
812 /* readonly attribute boolean isIFrameSelected; */
813 NS_IMETHODIMP
814 nsPrintEngine::GetIsIFrameSelected(PRBool *aIsIFrameSelected)
816 *aIsIFrameSelected = PR_FALSE;
818 // Get the docshell for this documentviewer
819 nsCOMPtr<nsIDocShell> webContainer(do_QueryInterface(mContainer));
820 // Get the currently focused window
821 nsCOMPtr<nsIDOMWindow> currentFocusWin = FindFocusedDOMWindow();
822 if (currentFocusWin && webContainer) {
823 // Get whether the doc contains a frameset
824 // Also, check to see if the currently focus docshell
825 // is a child of this docshell
826 PRPackedBool isParentFrameSet;
827 *aIsIFrameSelected = IsThereAnIFrameSelected(webContainer, currentFocusWin, isParentFrameSet);
829 return NS_OK;
832 //----------------------------------------------------------------------------------
833 /* readonly attribute boolean isRangeSelection; */
834 NS_IMETHODIMP
835 nsPrintEngine::GetIsRangeSelection(PRBool *aIsRangeSelection)
837 // Get the currently focused window
838 nsCOMPtr<nsIDOMWindow> currentFocusWin = FindFocusedDOMWindow();
839 *aIsRangeSelection = IsThereARangeSelection(currentFocusWin);
840 return NS_OK;
843 //----------------------------------------------------------------------------------
844 /* readonly attribute boolean isFramesetFrameSelected; */
845 NS_IMETHODIMP
846 nsPrintEngine::GetIsFramesetFrameSelected(PRBool *aIsFramesetFrameSelected)
848 // Get the currently focused window
849 nsCOMPtr<nsIDOMWindow> currentFocusWin = FindFocusedDOMWindow();
850 *aIsFramesetFrameSelected = currentFocusWin != nsnull;
851 return NS_OK;
854 //----------------------------------------------------------------------------------
855 /* readonly attribute long printPreviewNumPages; */
856 NS_IMETHODIMP
857 nsPrintEngine::GetPrintPreviewNumPages(PRInt32 *aPrintPreviewNumPages)
859 NS_ENSURE_ARG_POINTER(aPrintPreviewNumPages);
861 nsIFrame* seqFrame = nsnull;
862 *aPrintPreviewNumPages = 0;
863 if (!mPrtPreview ||
864 NS_FAILED(GetSeqFrameAndCountPagesInternal(mPrtPreview->mPrintObject, seqFrame, *aPrintPreviewNumPages))) {
865 return NS_ERROR_FAILURE;
867 return NS_OK;
870 //----------------------------------------------------------------------------------
871 // Enumerate all the documents for their titles
872 NS_IMETHODIMP
873 nsPrintEngine::EnumerateDocumentNames(PRUint32* aCount,
874 PRUnichar*** aResult)
876 NS_ENSURE_ARG(aCount);
877 NS_ENSURE_ARG_POINTER(aResult);
879 *aCount = 0;
880 *aResult = nsnull;
882 PRInt32 numDocs = mPrt->mPrintDocList.Length();
883 PRUnichar** array = (PRUnichar**) nsMemory::Alloc(numDocs * sizeof(PRUnichar*));
884 if (!array)
885 return NS_ERROR_OUT_OF_MEMORY;
887 for (PRInt32 i=0;i<numDocs;i++) {
888 nsPrintObject* po = mPrt->mPrintDocList.ElementAt(i);
889 NS_ASSERTION(po, "nsPrintObject can't be null!");
890 PRUnichar * docTitleStr;
891 PRUnichar * docURLStr;
892 GetDocumentTitleAndURL(po->mDocument, &docTitleStr, &docURLStr);
894 // Use the URL if the doc is empty
895 if (!docTitleStr || !*docTitleStr) {
896 if (docURLStr && *docURLStr) {
897 nsMemory::Free(docTitleStr);
898 docTitleStr = docURLStr;
899 } else {
900 nsMemory::Free(docURLStr);
902 docURLStr = nsnull;
903 if (!docTitleStr || !*docTitleStr) {
904 CleanupDocTitleArray(array, i);
905 return NS_ERROR_OUT_OF_MEMORY;
908 array[i] = docTitleStr;
909 if (docURLStr) nsMemory::Free(docURLStr);
911 *aCount = numDocs;
912 *aResult = array;
914 return NS_OK;
918 //----------------------------------------------------------------------------------
919 /* readonly attribute nsIPrintSettings globalPrintSettings; */
920 nsresult
921 nsPrintEngine::GetGlobalPrintSettings(nsIPrintSettings **aGlobalPrintSettings)
923 NS_ENSURE_ARG_POINTER(aGlobalPrintSettings);
925 nsresult rv = NS_ERROR_FAILURE;
926 nsCOMPtr<nsIPrintSettingsService> printSettingsService =
927 do_GetService(sPrintSettingsServiceContractID, &rv);
928 if (NS_SUCCEEDED(rv)) {
929 rv = printSettingsService->GetGlobalPrintSettings(aGlobalPrintSettings);
931 return rv;
934 //----------------------------------------------------------------------------------
935 /* readonly attribute boolean doingPrint; */
936 NS_IMETHODIMP
937 nsPrintEngine::GetDoingPrint(PRBool *aDoingPrint)
939 NS_ENSURE_ARG_POINTER(aDoingPrint);
940 *aDoingPrint = mIsDoingPrinting;
941 return NS_OK;
944 //----------------------------------------------------------------------------------
945 /* readonly attribute boolean doingPrintPreview; */
946 NS_IMETHODIMP
947 nsPrintEngine::GetDoingPrintPreview(PRBool *aDoingPrintPreview)
949 NS_ENSURE_ARG_POINTER(aDoingPrintPreview);
950 *aDoingPrintPreview = mIsDoingPrintPreview;
951 return NS_OK;
954 //----------------------------------------------------------------------------------
955 /* readonly attribute nsIPrintSettings currentPrintSettings; */
956 NS_IMETHODIMP
957 nsPrintEngine::GetCurrentPrintSettings(nsIPrintSettings * *aCurrentPrintSettings)
959 NS_ENSURE_ARG_POINTER(aCurrentPrintSettings);
961 if (mPrt) {
962 *aCurrentPrintSettings = mPrt->mPrintSettings;
964 } else if (mPrtPreview) {
965 *aCurrentPrintSettings = mPrtPreview->mPrintSettings;
967 } else {
968 *aCurrentPrintSettings = nsnull;
970 NS_IF_ADDREF(*aCurrentPrintSettings);
971 return NS_OK;
974 //-----------------------------------------------------------------
975 //-- Section: Pre-Reflow Methods
976 //-----------------------------------------------------------------
978 //---------------------------------------------------------------------
979 // This method checks to see if there is at least one printer defined
980 // and if so, it sets the first printer in the list as the default name
981 // in the PrintSettings which is then used for Printer Preview
982 nsresult
983 nsPrintEngine::CheckForPrinters(nsIPrintSettings* aPrintSettings)
985 #if defined(XP_MACOSX) || defined(ANDROID)
986 // Mac doesn't support retrieving a printer list.
987 return NS_OK;
988 #else
989 NS_ENSURE_ARG_POINTER(aPrintSettings);
991 // See if aPrintSettings already has a printer
992 nsXPIDLString printerName;
993 nsresult rv = aPrintSettings->GetPrinterName(getter_Copies(printerName));
994 if (NS_SUCCEEDED(rv) && !printerName.IsEmpty()) {
995 return NS_OK;
998 // aPrintSettings doesn't have a printer set. Try to fetch the default.
999 nsCOMPtr<nsIPrintSettingsService> printSettingsService =
1000 do_GetService(sPrintSettingsServiceContractID, &rv);
1001 NS_ENSURE_SUCCESS(rv, rv);
1003 rv = printSettingsService->GetDefaultPrinterName(getter_Copies(printerName));
1004 if (NS_SUCCEEDED(rv) && !printerName.IsEmpty()) {
1005 rv = aPrintSettings->SetPrinterName(printerName.get());
1007 return rv;
1008 #endif
1011 //----------------------------------------------------------------------
1012 // Set up to use the "pluggable" Print Progress Dialog
1013 void
1014 nsPrintEngine::ShowPrintProgress(PRBool aIsForPrinting, PRBool& aDoNotify)
1016 // default to not notifying, that if something here goes wrong
1017 // or we aren't going to show the progress dialog we can straight into
1018 // reflowing the doc for printing.
1019 aDoNotify = PR_FALSE;
1021 // Assume we can't do progress and then see if we can
1022 PRBool showProgresssDialog = PR_FALSE;
1024 // if it is already being shown then don't bother to find out if it should be
1025 // so skip this and leave mShowProgressDialog set to FALSE
1026 if (!mProgressDialogIsShown) {
1027 showProgresssDialog =
1028 nsContentUtils::GetBoolPref("print.show_print_progress");
1031 // Turning off the showing of Print Progress in Prefs overrides
1032 // whether the calling PS desire to have it on or off, so only check PS if
1033 // prefs says it's ok to be on.
1034 if (showProgresssDialog) {
1035 mPrt->mPrintSettings->GetShowPrintProgress(&showProgresssDialog);
1038 // Now open the service to get the progress dialog
1039 // If we don't get a service, that's ok, then just don't show progress
1040 if (showProgresssDialog) {
1041 nsCOMPtr<nsIPrintingPromptService> printPromptService(do_GetService(kPrintingPromptService));
1042 if (printPromptService) {
1043 nsPIDOMWindow *domWin = mDocument->GetWindow();
1044 if (!domWin) return;
1046 nsCOMPtr<nsIDocShellTreeItem> docShellItem =
1047 do_QueryInterface(domWin->GetDocShell());
1048 if (!docShellItem) return;
1049 nsCOMPtr<nsIDocShellTreeOwner> owner;
1050 docShellItem->GetTreeOwner(getter_AddRefs(owner));
1051 nsCOMPtr<nsIWebBrowserChrome> browserChrome = do_GetInterface(owner);
1052 if (!browserChrome) return;
1053 PRBool isModal = PR_TRUE;
1054 browserChrome->IsWindowModal(&isModal);
1055 if (isModal) {
1056 // Showing a print progress dialog when printing a modal window
1057 // isn't supported. See bug 301560.
1058 return;
1061 nsCOMPtr<nsIWebProgressListener> printProgressListener;
1063 nsCOMPtr<nsIWebBrowserPrint> wbp(do_QueryInterface(mDocViewerPrint));
1064 nsresult rv = printPromptService->ShowProgress(domWin, wbp, mPrt->mPrintSettings, this, aIsForPrinting,
1065 getter_AddRefs(printProgressListener),
1066 getter_AddRefs(mPrt->mPrintProgressParams),
1067 &aDoNotify);
1068 if (NS_SUCCEEDED(rv)) {
1069 if (printProgressListener && mPrt->mPrintProgressParams) {
1070 mPrt->mPrintProgressListeners.AppendObject(printProgressListener);
1071 SetDocAndURLIntoProgress(mPrt->mPrintObject, mPrt->mPrintProgressParams);
1078 //---------------------------------------------------------------------
1079 PRBool
1080 nsPrintEngine::IsThereARangeSelection(nsIDOMWindow* aDOMWin)
1082 nsCOMPtr<nsIPresShell> presShell;
1083 if (aDOMWin) {
1084 nsCOMPtr<nsPIDOMWindow> window(do_QueryInterface(aDOMWin));
1085 window->GetDocShell()->GetPresShell(getter_AddRefs(presShell));
1088 if (!presShell)
1089 return PR_FALSE;
1091 // check here to see if there is a range selection
1092 // so we know whether to turn on the "Selection" radio button
1093 nsCOMPtr<nsISelection> selection;
1094 selection = presShell->GetCurrentSelection(nsISelectionController::SELECTION_NORMAL);
1095 if (selection) {
1096 PRInt32 count;
1097 selection->GetRangeCount(&count);
1098 if (count == 1) {
1099 nsCOMPtr<nsIDOMRange> range;
1100 if (NS_SUCCEEDED(selection->GetRangeAt(0, getter_AddRefs(range)))) {
1101 // check to make sure it isn't an insertion selection
1102 PRBool isCollapsed;
1103 selection->GetIsCollapsed(&isCollapsed);
1104 return !isCollapsed;
1107 if (count > 1) return PR_TRUE;
1109 return PR_FALSE;
1112 //---------------------------------------------------------------------
1113 PRBool
1114 nsPrintEngine::IsParentAFrameSet(nsIDocShell * aParent)
1116 // See if the incoming doc is the root document
1117 nsCOMPtr<nsIDocShellTreeItem> parentAsItem(do_QueryInterface(aParent));
1118 if (!parentAsItem) return PR_FALSE;
1120 // When it is the top level document we need to check
1121 // to see if it contains a frameset. If it does, then
1122 // we only want to print the doc's children and not the document itself
1123 // For anything else we always print all the children and the document
1124 // for example, if the doc contains an IFRAME we eant to print the child
1125 // document (the IFRAME) and then the rest of the document.
1127 // XXX we really need to search the frame tree, and not the content
1128 // but there is no way to distinguish between IFRAMEs and FRAMEs
1129 // with the GetFrameType call.
1130 // Bug 53459 has been files so we can eventually distinguish
1131 // between IFRAME frames and FRAME frames
1132 PRBool isFrameSet = PR_FALSE;
1133 // only check to see if there is a frameset if there is
1134 // NO parent doc for this doc. meaning this parent is the root doc
1135 nsCOMPtr<nsIDOMDocument> domDoc = do_GetInterface(aParent);
1136 nsCOMPtr<nsIDocument> doc = do_QueryInterface(domDoc);
1137 if (doc) {
1138 nsIContent *rootElement = doc->GetRootElement();
1139 if (rootElement) {
1140 isFrameSet = HasFramesetChild(rootElement);
1143 return isFrameSet;
1147 //---------------------------------------------------------------------
1148 // Recursively build a list of sub documents to be printed
1149 // that mirrors the document tree
1150 void
1151 nsPrintEngine::BuildDocTree(nsIDocShellTreeNode * aParentNode,
1152 nsTArray<nsPrintObject*> * aDocList,
1153 nsPrintObject * aPO)
1155 NS_ASSERTION(aParentNode, "Pointer is null!");
1156 NS_ASSERTION(aDocList, "Pointer is null!");
1157 NS_ASSERTION(aPO, "Pointer is null!");
1159 PRInt32 childWebshellCount;
1160 aParentNode->GetChildCount(&childWebshellCount);
1161 if (childWebshellCount > 0) {
1162 for (PRInt32 i=0;i<childWebshellCount;i++) {
1163 nsCOMPtr<nsIDocShellTreeItem> child;
1164 aParentNode->GetChildAt(i, getter_AddRefs(child));
1165 nsCOMPtr<nsIDocShell> childAsShell(do_QueryInterface(child));
1167 nsCOMPtr<nsIContentViewer> viewer;
1168 childAsShell->GetContentViewer(getter_AddRefs(viewer));
1169 if (viewer) {
1170 nsCOMPtr<nsIContentViewerFile> viewerFile(do_QueryInterface(viewer));
1171 if (viewerFile) {
1172 nsCOMPtr<nsIDocShell> childDocShell(do_QueryInterface(child));
1173 nsCOMPtr<nsIDocShellTreeNode> childNode(do_QueryInterface(child));
1174 nsCOMPtr<nsIDOMDocument> doc = do_GetInterface(childDocShell);
1175 nsPrintObject * po = new nsPrintObject();
1176 po->mParent = aPO;
1177 nsresult rv = po->Init(childDocShell, doc, aPO->mPrintPreview);
1178 if (NS_FAILED(rv))
1179 NS_NOTREACHED("Init failed?");
1180 aPO->mKids.AppendElement(po);
1181 aDocList->AppendElement(po);
1182 BuildDocTree(childNode, aDocList, po);
1189 //---------------------------------------------------------------------
1190 void
1191 nsPrintEngine::GetDocumentTitleAndURL(nsIDocument* aDoc,
1192 PRUnichar** aTitle,
1193 PRUnichar** aURLStr)
1195 NS_ASSERTION(aDoc, "Pointer is null!");
1196 NS_ASSERTION(aTitle, "Pointer is null!");
1197 NS_ASSERTION(aURLStr, "Pointer is null!");
1199 *aTitle = nsnull;
1200 *aURLStr = nsnull;
1202 nsAutoString docTitle;
1203 nsCOMPtr<nsIDOMNSDocument> doc = do_QueryInterface(aDoc);
1204 doc->GetTitle(docTitle);
1205 if (!docTitle.IsEmpty()) {
1206 *aTitle = ToNewUnicode(docTitle);
1209 nsIURI* url = aDoc->GetDocumentURI();
1210 if (!url) return;
1212 nsCOMPtr<nsIURIFixup> urifixup(do_GetService(NS_URIFIXUP_CONTRACTID));
1213 if (!urifixup) return;
1215 nsCOMPtr<nsIURI> exposableURI;
1216 urifixup->CreateExposableURI(url, getter_AddRefs(exposableURI));
1218 if (!exposableURI) return;
1220 nsCAutoString urlCStr;
1221 exposableURI->GetSpec(urlCStr);
1223 nsresult rv;
1224 nsCOMPtr<nsITextToSubURI> textToSubURI =
1225 do_GetService(NS_ITEXTTOSUBURI_CONTRACTID, &rv);
1226 if (NS_FAILED(rv)) return;
1228 nsAutoString unescapedURI;
1229 rv = textToSubURI->UnEscapeURIForUI(NS_LITERAL_CSTRING("UTF-8"),
1230 urlCStr, unescapedURI);
1231 if (NS_FAILED(rv)) return;
1233 *aURLStr = ToNewUnicode(unescapedURI);
1236 //---------------------------------------------------------------------
1237 // The walks the PO tree and for each document it walks the content
1238 // tree looking for any content that are sub-shells
1240 // It then sets the mContent pointer in the "found" PO object back to the
1241 // the document that contained it.
1242 void
1243 nsPrintEngine::MapContentToWebShells(nsPrintObject* aRootPO,
1244 nsPrintObject* aPO)
1246 NS_ASSERTION(aRootPO, "Pointer is null!");
1247 NS_ASSERTION(aPO, "Pointer is null!");
1249 // Recursively walk the content from the root item
1250 // XXX Would be faster to enumerate the subdocuments, although right now
1251 // nsIDocument doesn't expose quite what would be needed.
1252 nsCOMPtr<nsIContentViewer> viewer;
1253 aPO->mDocShell->GetContentViewer(getter_AddRefs(viewer));
1254 if (!viewer) return;
1256 nsCOMPtr<nsIDOMDocument> domDoc;
1257 viewer->GetDOMDocument(getter_AddRefs(domDoc));
1258 nsCOMPtr<nsIDocument> doc = do_QueryInterface(domDoc);
1259 if (!doc) return;
1261 Element* rootElement = doc->GetRootElement();
1262 if (rootElement) {
1263 MapContentForPO(aPO, rootElement);
1264 } else {
1265 NS_WARNING("Null root content on (sub)document.");
1268 // Continue recursively walking the chilren of this PO
1269 for (PRUint32 i=0;i<aPO->mKids.Length();i++) {
1270 MapContentToWebShells(aRootPO, aPO->mKids[i]);
1275 //-------------------------------------------------------
1276 // A Frame's sub-doc may contain content or a FrameSet
1277 // When it contains a FrameSet the mFrameType for the PrintObject
1278 // is always set to an eFrame. Which is fine when printing "AsIs"
1279 // but is incorrect when when printing "Each Frame Separately".
1280 // When printing "Each Frame Separately" the Frame really acts like
1281 // a frameset.
1283 // This method walks the PO tree and checks to see if the PrintObject is
1284 // an eFrame and has children that are eFrames (meaning it's a Frame containing a FrameSet)
1285 // If so, then the mFrameType need to be changed to eFrameSet
1287 // Also note: We only want to call this we are printing "Each Frame Separately"
1288 // when printing "As Is" leave it as an eFrame
1289 void
1290 nsPrintEngine::CheckForChildFrameSets(nsPrintObject* aPO)
1292 NS_ASSERTION(aPO, "Pointer is null!");
1294 // Continue recursively walking the chilren of this PO
1295 PRBool hasChildFrames = PR_FALSE;
1296 for (PRUint32 i=0;i<aPO->mKids.Length();i++) {
1297 nsPrintObject* po = aPO->mKids[i];
1298 if (po->mFrameType == eFrame) {
1299 hasChildFrames = PR_TRUE;
1300 CheckForChildFrameSets(po);
1304 if (hasChildFrames && aPO->mFrameType == eFrame) {
1305 aPO->mFrameType = eFrameSet;
1309 //---------------------------------------------------------------------
1310 // This method is key to the entire print mechanism.
1312 // This "maps" or figures out which sub-doc represents a
1313 // given Frame or IFrame in its parent sub-doc.
1315 // So the Mcontent pointer in the child sub-doc points to the
1316 // content in the its parent document, that caused it to be printed.
1317 // This is used later to (after reflow) to find the absolute location
1318 // of the sub-doc on its parent's page frame so it can be
1319 // printed in the correct location.
1321 // This method recursvely "walks" the content for a document finding
1322 // all the Frames and IFrames, then sets the "mFrameType" data member
1323 // which tells us what type of PO we have
1324 void
1325 nsPrintEngine::MapContentForPO(nsPrintObject* aPO,
1326 nsIContent* aContent)
1328 NS_PRECONDITION(aPO && aContent, "Null argument");
1330 nsIDocument* doc = aContent->GetDocument();
1332 NS_ASSERTION(doc, "Content without a document from a document tree?");
1334 nsIDocument* subDoc = doc->GetSubDocumentFor(aContent);
1336 if (subDoc) {
1337 nsCOMPtr<nsISupports> container = subDoc->GetContainer();
1338 nsCOMPtr<nsIDocShell> docShell(do_QueryInterface(container));
1340 if (docShell) {
1341 nsPrintObject * po = nsnull;
1342 PRInt32 cnt = aPO->mKids.Length();
1343 for (PRInt32 i=0;i<cnt;i++) {
1344 nsPrintObject* kid = aPO->mKids.ElementAt(i);
1345 if (kid->mDocument == subDoc) {
1346 po = kid;
1347 break;
1351 // XXX If a subdocument has no onscreen presentation, there will be no PO
1352 // This is even if there should be a print presentation
1353 if (po) {
1355 nsCOMPtr<nsIDOMHTMLFrameElement> frame(do_QueryInterface(aContent));
1356 // "frame" elements not in a frameset context should be treated
1357 // as iframes
1358 if (frame && po->mParent->mFrameType == eFrameSet) {
1359 po->mFrameType = eFrame;
1360 } else {
1361 // Assume something iframe-like, i.e. iframe, object, or embed
1362 po->mFrameType = eIFrame;
1363 SetPrintAsIs(po, PR_TRUE);
1364 NS_ASSERTION(po->mParent, "The root must be a parent");
1365 po->mParent->mPrintAsIs = PR_TRUE;
1371 // walk children content
1372 PRUint32 count = aContent->GetChildCount();
1373 for (PRUint32 i = 0; i < count; ++i) {
1374 nsIContent *child = aContent->GetChildAt(i);
1375 MapContentForPO(aPO, child);
1379 //---------------------------------------------------------------------
1380 PRBool
1381 nsPrintEngine::IsThereAnIFrameSelected(nsIDocShell* aDocShell,
1382 nsIDOMWindow* aDOMWin,
1383 PRPackedBool& aIsParentFrameSet)
1385 aIsParentFrameSet = IsParentAFrameSet(aDocShell);
1386 PRBool iFrameIsSelected = PR_FALSE;
1387 if (mPrt && mPrt->mPrintObject) {
1388 nsPrintObject* po = FindPrintObjectByDOMWin(mPrt->mPrintObject, aDOMWin);
1389 iFrameIsSelected = po && po->mFrameType == eIFrame;
1390 } else {
1391 // First, check to see if we are a frameset
1392 if (!aIsParentFrameSet) {
1393 // Check to see if there is a currenlt focused frame
1394 // if so, it means the selected frame is either the main docshell
1395 // or an IFRAME
1396 if (aDOMWin) {
1397 // Get the main docshell's DOMWin to see if it matches
1398 // the frame that is selected
1399 nsCOMPtr<nsIDOMWindow> domWin = do_GetInterface(aDocShell);
1400 if (domWin != aDOMWin) {
1401 iFrameIsSelected = PR_TRUE; // we have a selected IFRAME
1407 return iFrameIsSelected;
1410 //---------------------------------------------------------------------
1411 // Recursively sets all the PO items to be printed
1412 // from the given item down into the tree
1413 void
1414 nsPrintEngine::SetPrintPO(nsPrintObject* aPO, PRBool aPrint)
1416 NS_ASSERTION(aPO, "Pointer is null!");
1418 // Set whether to print flag
1419 aPO->mDontPrint = !aPrint;
1421 for (PRUint32 i=0;i<aPO->mKids.Length();i++) {
1422 SetPrintPO(aPO->mKids[i], aPrint);
1426 //---------------------------------------------------------------------
1427 // This will first use a Title and/or URL from the PrintSettings
1428 // if one isn't set then it uses the one from the document
1429 // then if not title is there we will make sure we send something back
1430 // depending on the situation.
1431 void
1432 nsPrintEngine::GetDisplayTitleAndURL(nsPrintObject* aPO,
1433 PRUnichar** aTitle,
1434 PRUnichar** aURLStr,
1435 eDocTitleDefault aDefType)
1437 NS_ASSERTION(aPO, "Pointer is null!");
1438 NS_ASSERTION(aTitle, "Pointer is null!");
1439 NS_ASSERTION(aURLStr, "Pointer is null!");
1441 *aTitle = nsnull;
1442 *aURLStr = nsnull;
1444 if (!mPrt)
1445 return;
1447 // First check to see if the PrintSettings has defined an alternate title
1448 // and use that if it did
1449 PRUnichar * docTitleStrPS = nsnull;
1450 PRUnichar * docURLStrPS = nsnull;
1451 if (mPrt->mPrintSettings) {
1452 mPrt->mPrintSettings->GetTitle(&docTitleStrPS);
1453 mPrt->mPrintSettings->GetDocURL(&docURLStrPS);
1455 if (docTitleStrPS && *docTitleStrPS) {
1456 *aTitle = docTitleStrPS;
1459 if (docURLStrPS && *docURLStrPS) {
1460 *aURLStr = docURLStrPS;
1463 // short circut
1464 if (docTitleStrPS && docURLStrPS) {
1465 return;
1469 PRUnichar* docTitle;
1470 PRUnichar* docUrl;
1471 GetDocumentTitleAndURL(aPO->mDocument, &docTitle, &docUrl);
1473 if (docUrl) {
1474 if (!docURLStrPS)
1475 *aURLStr = docUrl;
1476 else
1477 nsMemory::Free(docUrl);
1480 if (docTitle) {
1481 if (!docTitleStrPS)
1482 *aTitle = docTitle;
1483 else
1484 nsMemory::Free(docTitle);
1485 } else if (!docTitleStrPS) {
1486 switch (aDefType) {
1487 case eDocTitleDefBlank: *aTitle = ToNewUnicode(EmptyString());
1488 break;
1490 case eDocTitleDefURLDoc:
1491 if (*aURLStr) {
1492 *aTitle = NS_strdup(*aURLStr);
1493 } else if (mPrt->mBrandName) {
1494 *aTitle = NS_strdup(mPrt->mBrandName);
1496 break;
1497 case eDocTitleDefNone:
1498 // *aTitle defaults to nsnull
1499 break;
1504 //---------------------------------------------------------------------
1505 nsresult nsPrintEngine::DocumentReadyForPrinting()
1507 if (mPrt->mPrintFrameType == nsIPrintSettings::kEachFrameSep) {
1508 CheckForChildFrameSets(mPrt->mPrintObject);
1512 // Send the document to the printer...
1514 nsresult rv = SetupToPrintContent();
1515 if (NS_FAILED(rv)) {
1516 // The print job was canceled or there was a problem
1517 // So remove all other documents from the print list
1518 DonePrintingPages(nsnull, rv);
1520 return rv;
1523 /** ---------------------------------------------------
1524 * Cleans up when an error occurred
1526 nsresult nsPrintEngine::CleanupOnFailure(nsresult aResult, PRBool aIsPrinting)
1528 PR_PL(("**** Failed %s - rv 0x%X", aIsPrinting?"Printing":"Print Preview", aResult));
1530 /* cleanup... */
1531 if (mPagePrintTimer) {
1532 mPagePrintTimer->Stop();
1533 NS_RELEASE(mPagePrintTimer);
1536 if (aIsPrinting) {
1537 SetIsPrinting(PR_FALSE);
1538 } else {
1539 SetIsPrintPreview(PR_FALSE);
1540 SetIsCreatingPrintPreview(PR_FALSE);
1543 /* cleanup done, let's fire-up an error dialog to notify the user
1544 * what went wrong...
1546 * When rv == NS_ERROR_ABORT, it means we want out of the
1547 * print job without displaying any error messages
1549 if (aResult != NS_ERROR_ABORT) {
1550 ShowPrintErrorDialog(aResult, aIsPrinting);
1553 FirePrintCompletionEvent();
1555 return aResult;
1559 //---------------------------------------------------------------------
1560 void
1561 nsPrintEngine::ShowPrintErrorDialog(nsresult aPrintError, PRBool aIsPrinting)
1564 PR_PL(("nsPrintEngine::ShowPrintErrorDialog(nsresult aPrintError=%lx, PRBool aIsPrinting=%d)\n", (long)aPrintError, (int)aIsPrinting));
1566 nsCAutoString stringName;
1568 switch(aPrintError)
1570 #define NS_ERROR_TO_LOCALIZED_PRINT_ERROR_MSG(nserr) case nserr: stringName.AssignLiteral(#nserr); break;
1571 NS_ERROR_TO_LOCALIZED_PRINT_ERROR_MSG(NS_ERROR_GFX_PRINTER_CMD_NOT_FOUND)
1572 NS_ERROR_TO_LOCALIZED_PRINT_ERROR_MSG(NS_ERROR_GFX_PRINTER_CMD_FAILURE)
1573 NS_ERROR_TO_LOCALIZED_PRINT_ERROR_MSG(NS_ERROR_GFX_PRINTER_NO_PRINTER_AVAILABLE)
1574 NS_ERROR_TO_LOCALIZED_PRINT_ERROR_MSG(NS_ERROR_GFX_PRINTER_NAME_NOT_FOUND)
1575 NS_ERROR_TO_LOCALIZED_PRINT_ERROR_MSG(NS_ERROR_GFX_PRINTER_ACCESS_DENIED)
1576 NS_ERROR_TO_LOCALIZED_PRINT_ERROR_MSG(NS_ERROR_GFX_PRINTER_INVALID_ATTRIBUTE)
1577 NS_ERROR_TO_LOCALIZED_PRINT_ERROR_MSG(NS_ERROR_GFX_PRINTER_PRINTER_NOT_READY)
1578 NS_ERROR_TO_LOCALIZED_PRINT_ERROR_MSG(NS_ERROR_GFX_PRINTER_OUT_OF_PAPER)
1579 NS_ERROR_TO_LOCALIZED_PRINT_ERROR_MSG(NS_ERROR_GFX_PRINTER_PRINTER_IO_ERROR)
1580 NS_ERROR_TO_LOCALIZED_PRINT_ERROR_MSG(NS_ERROR_GFX_PRINTER_COULD_NOT_OPEN_FILE)
1581 NS_ERROR_TO_LOCALIZED_PRINT_ERROR_MSG(NS_ERROR_GFX_PRINTER_FILE_IO_ERROR)
1582 NS_ERROR_TO_LOCALIZED_PRINT_ERROR_MSG(NS_ERROR_GFX_PRINTER_PRINTPREVIEW)
1583 NS_ERROR_TO_LOCALIZED_PRINT_ERROR_MSG(NS_ERROR_UNEXPECTED)
1584 NS_ERROR_TO_LOCALIZED_PRINT_ERROR_MSG(NS_ERROR_OUT_OF_MEMORY)
1585 NS_ERROR_TO_LOCALIZED_PRINT_ERROR_MSG(NS_ERROR_NOT_IMPLEMENTED)
1586 NS_ERROR_TO_LOCALIZED_PRINT_ERROR_MSG(NS_ERROR_NOT_AVAILABLE)
1587 NS_ERROR_TO_LOCALIZED_PRINT_ERROR_MSG(NS_ERROR_ABORT)
1588 NS_ERROR_TO_LOCALIZED_PRINT_ERROR_MSG(NS_ERROR_GFX_PRINTER_STARTDOC)
1589 NS_ERROR_TO_LOCALIZED_PRINT_ERROR_MSG(NS_ERROR_GFX_PRINTER_ENDDOC)
1590 NS_ERROR_TO_LOCALIZED_PRINT_ERROR_MSG(NS_ERROR_GFX_PRINTER_STARTPAGE)
1591 NS_ERROR_TO_LOCALIZED_PRINT_ERROR_MSG(NS_ERROR_GFX_PRINTER_ENDPAGE)
1592 NS_ERROR_TO_LOCALIZED_PRINT_ERROR_MSG(NS_ERROR_GFX_PRINTER_PRINT_WHILE_PREVIEW)
1593 NS_ERROR_TO_LOCALIZED_PRINT_ERROR_MSG(NS_ERROR_GFX_PRINTER_PAPER_SIZE_NOT_SUPPORTED)
1594 NS_ERROR_TO_LOCALIZED_PRINT_ERROR_MSG(NS_ERROR_GFX_PRINTER_ORIENTATION_NOT_SUPPORTED)
1595 NS_ERROR_TO_LOCALIZED_PRINT_ERROR_MSG(NS_ERROR_GFX_PRINTER_COLORSPACE_NOT_SUPPORTED)
1596 NS_ERROR_TO_LOCALIZED_PRINT_ERROR_MSG(NS_ERROR_GFX_PRINTER_TOO_MANY_COPIES)
1597 NS_ERROR_TO_LOCALIZED_PRINT_ERROR_MSG(NS_ERROR_GFX_PRINTER_DRIVER_CONFIGURATION_ERROR)
1598 NS_ERROR_TO_LOCALIZED_PRINT_ERROR_MSG(NS_ERROR_GFX_PRINTER_DOC_IS_BUSY_PP)
1599 NS_ERROR_TO_LOCALIZED_PRINT_ERROR_MSG(NS_ERROR_GFX_PRINTER_DOC_WAS_DESTORYED)
1600 NS_ERROR_TO_LOCALIZED_PRINT_ERROR_MSG(NS_ERROR_GFX_NO_PRINTDIALOG_IN_TOOLKIT)
1601 NS_ERROR_TO_LOCALIZED_PRINT_ERROR_MSG(NS_ERROR_GFX_NO_PRINTROMPTSERVICE)
1602 NS_ERROR_TO_LOCALIZED_PRINT_ERROR_MSG(NS_ERROR_GFX_PRINTER_NO_XUL) // Temporary code for Bug 136185 / bug 240490
1603 NS_ERROR_TO_LOCALIZED_PRINT_ERROR_MSG(NS_ERROR_GFX_PRINTER_PLEX_NOT_SUPPORTED)
1604 NS_ERROR_TO_LOCALIZED_PRINT_ERROR_MSG(NS_ERROR_GFX_PRINTER_DOC_IS_BUSY)
1605 NS_ERROR_TO_LOCALIZED_PRINT_ERROR_MSG(NS_ERROR_GFX_PRINTING_NOT_IMPLEMENTED)
1606 NS_ERROR_TO_LOCALIZED_PRINT_ERROR_MSG(NS_ERROR_GFX_COULD_NOT_LOAD_PRINT_MODULE)
1607 NS_ERROR_TO_LOCALIZED_PRINT_ERROR_MSG(NS_ERROR_GFX_PRINTER_RESOLUTION_NOT_SUPPORTED)
1609 default:
1610 NS_ERROR_TO_LOCALIZED_PRINT_ERROR_MSG(NS_ERROR_FAILURE)
1611 #undef NS_ERROR_TO_LOCALIZED_PRINT_ERROR_MSG
1614 PR_PL(("ShowPrintErrorDialog: stringName='%s'\n", stringName.get()));
1616 nsXPIDLString msg, title;
1617 nsresult rv =
1618 nsContentUtils::GetLocalizedString(nsContentUtils::ePRINTING_PROPERTIES,
1619 stringName.get(), msg);
1620 if (NS_FAILED(rv)) {
1621 PR_PL(("GetLocalizedString failed\n"));
1622 return;
1625 rv = nsContentUtils::GetLocalizedString(nsContentUtils::ePRINTING_PROPERTIES,
1626 aIsPrinting ? "print_error_dialog_title"
1627 : "printpreview_error_dialog_title",
1628 title);
1630 nsCOMPtr<nsIWindowWatcher> wwatch = do_GetService(NS_WINDOWWATCHER_CONTRACTID, &rv);
1631 if (NS_FAILED(rv)) {
1632 PR_PL(("ShowPrintErrorDialog(): wwatch==nsnull\n"));
1633 return;
1636 nsCOMPtr<nsIDOMWindow> active;
1637 wwatch->GetActiveWindow(getter_AddRefs(active));
1639 nsCOMPtr<nsIPrompt> dialog;
1640 /* |GetNewPrompter| allows that |active| is |nsnull|
1641 * (see bug 234982 ("nsPrintEngine::ShowPrintErrorDialog() fails in many cases")) */
1642 wwatch->GetNewPrompter(active, getter_AddRefs(dialog));
1643 if (!dialog) {
1644 PR_PL(("ShowPrintErrorDialog(): dialog==nsnull\n"));
1645 return;
1648 dialog->Alert(title.get(), msg.get());
1649 PR_PL(("ShowPrintErrorDialog(): alert displayed successfully.\n"));
1652 //-----------------------------------------------------------------
1653 //-- Section: Reflow Methods
1654 //-----------------------------------------------------------------
1656 //-------------------------------------------------------
1657 nsresult
1658 nsPrintEngine::SetupToPrintContent()
1660 // In this step we figure out which documents should be printed
1661 // i.e. if we are printing the selection then only enable that nsPrintObject
1662 // for printing
1663 if (NS_FAILED(EnablePOsForPrinting())) {
1664 return NS_ERROR_FAILURE;
1666 DUMP_DOC_LIST("\nAfter Enable------------------------------------------");
1668 // This is an Optimization
1669 // If we are in PP then we already know all the shrinkage information
1670 // so just transfer it to the PrintData and we will skip the extra shrinkage reflow
1672 // doSetPixelScale tells Reflow whether to set the shrinkage value into the DC
1673 // The first time we do not want to do this, the second time through we do
1674 PRBool doSetPixelScale = PR_FALSE;
1675 PRBool ppIsShrinkToFit = mPrtPreview && mPrtPreview->mShrinkToFit;
1676 if (ppIsShrinkToFit) {
1677 mPrt->mShrinkRatio = mPrtPreview->mShrinkRatio;
1678 doSetPixelScale = PR_TRUE;
1681 // Here we reflow all the PrintObjects
1682 nsresult rv = ReflowDocList(mPrt->mPrintObject, doSetPixelScale);
1683 if (NS_FAILED(rv)) {
1684 return NS_ERROR_FAILURE;
1687 // Here is where we do the extra reflow for shrinking the content
1688 // But skip this step if we are in PrintPreview
1689 if (mPrt->mShrinkToFit && !ppIsShrinkToFit) {
1690 // Now look for the PO that has the smallest percent for shrink to fit
1691 if (mPrt->mPrintDocList.Length() > 1 && mPrt->mPrintObject->mFrameType == eFrameSet) {
1692 nsPrintObject* smallestPO = FindSmallestSTF();
1693 NS_ASSERTION(smallestPO, "There must always be an XMost PO!");
1694 if (smallestPO) {
1695 // Calc the shrinkage based on the entire content area
1696 mPrt->mShrinkRatio = smallestPO->mShrinkRatio;
1698 } else {
1699 // Single document so use the Shrink as calculated for the PO
1700 mPrt->mShrinkRatio = mPrt->mPrintObject->mShrinkRatio;
1703 // Only Shrink if we are smaller
1704 if (mPrt->mShrinkRatio < 0.998f) {
1705 // Clamp Shrink to Fit to 60%
1706 mPrt->mShrinkRatio = NS_MAX(mPrt->mShrinkRatio, 0.60f);
1708 for (PRUint32 i=0;i<mPrt->mPrintDocList.Length();i++) {
1709 nsPrintObject* po = mPrt->mPrintDocList.ElementAt(i);
1710 NS_ASSERTION(po, "nsPrintObject can't be null!");
1711 // Wipe out the presentation before we reflow
1712 po->DestroyPresentation();
1715 #if (defined(XP_WIN) || defined(XP_OS2)) && defined(EXTENDED_DEBUG_PRINTING)
1716 // We need to clear all the output files here
1717 // because they will be re-created with second reflow of the docs
1718 if (kPrintingLogMod && kPrintingLogMod->level == DUMP_LAYOUT_LEVEL) {
1719 RemoveFilesInDir(".\\");
1720 gDumpFileNameCnt = 0;
1721 gDumpLOFileNameCnt = 0;
1723 #endif
1725 // Here we reflow all the PrintObjects a second time
1726 // this time using the shrinkage values
1727 // The last param here tells reflow to NOT calc the shrinkage values
1728 if (NS_FAILED(ReflowDocList(mPrt->mPrintObject, PR_TRUE))) {
1729 return NS_ERROR_FAILURE;
1733 #ifdef PR_LOGGING
1735 float calcRatio = 0.0f;
1736 if (mPrt->mPrintDocList.Length() > 1 && mPrt->mPrintObject->mFrameType == eFrameSet) {
1737 nsPrintObject* smallestPO = FindSmallestSTF();
1738 NS_ASSERTION(smallestPO, "There must always be an XMost PO!");
1739 if (smallestPO) {
1740 // Calc the shrinkage based on the entire content area
1741 calcRatio = smallestPO->mShrinkRatio;
1743 } else {
1744 // Single document so use the Shrink as calculated for the PO
1745 calcRatio = mPrt->mPrintObject->mShrinkRatio;
1747 PR_PL(("**************************************************************************\n"));
1748 PR_PL(("STF Ratio is: %8.5f Effective Ratio: %8.5f Diff: %8.5f\n", mPrt->mShrinkRatio, calcRatio, mPrt->mShrinkRatio-calcRatio));
1749 PR_PL(("**************************************************************************\n"));
1751 #endif
1754 DUMP_DOC_LIST(("\nAfter Reflow------------------------------------------"));
1755 PR_PL(("\n"));
1756 PR_PL(("-------------------------------------------------------\n"));
1757 PR_PL(("\n"));
1759 CalcNumPrintablePages(mPrt->mNumPrintablePages);
1761 PR_PL(("--- Printing %d pages\n", mPrt->mNumPrintablePages));
1762 DUMP_DOC_TREELAYOUT;
1764 // Print listener setup...
1765 if (mPrt != nsnull) {
1766 mPrt->OnStartPrinting();
1769 PRUnichar* fileName = nsnull;
1770 // check to see if we are printing to a file
1771 PRBool isPrintToFile = PR_FALSE;
1772 mPrt->mPrintSettings->GetPrintToFile(&isPrintToFile);
1773 if (isPrintToFile) {
1774 // On some platforms The BeginDocument needs to know the name of the file
1775 // and it uses the PrintService to get it, so we need to set it into the PrintService here
1776 mPrt->mPrintSettings->GetToFileName(&fileName);
1779 PRUnichar * docTitleStr;
1780 PRUnichar * docURLStr;
1781 GetDisplayTitleAndURL(mPrt->mPrintObject, &docTitleStr, &docURLStr, eDocTitleDefURLDoc);
1783 PRInt32 startPage = 1;
1784 PRInt32 endPage = mPrt->mNumPrintablePages;
1786 PRInt16 printRangeType = nsIPrintSettings::kRangeAllPages;
1787 mPrt->mPrintSettings->GetPrintRange(&printRangeType);
1788 if (printRangeType == nsIPrintSettings::kRangeSpecifiedPageRange) {
1789 mPrt->mPrintSettings->GetStartPageRange(&startPage);
1790 mPrt->mPrintSettings->GetEndPageRange(&endPage);
1791 if (endPage > mPrt->mNumPrintablePages) {
1792 endPage = mPrt->mNumPrintablePages;
1796 rv = NS_OK;
1797 // BeginDocument may pass back a FAILURE code
1798 // i.e. On Windows, if you are printing to a file and hit "Cancel"
1799 // to the "File Name" dialog, this comes back as an error
1800 // Don't start printing when regression test are executed
1801 if (!mPrt->mDebugFilePtr && mIsDoingPrinting) {
1802 rv = mPrt->mPrintDC->BeginDocument(docTitleStr, fileName, startPage, endPage);
1805 if (mIsCreatingPrintPreview) {
1806 // Print Preview -- Pass ownership of docTitleStr and docURLStr
1807 // to the pageSequenceFrame, to be displayed in the header
1808 nsIPageSequenceFrame *seqFrame = mPrt->mPrintObject->mPresShell->GetPageSequenceFrame();
1809 if (seqFrame) {
1810 seqFrame->StartPrint(mPrt->mPrintObject->mPresContext,
1811 mPrt->mPrintSettings, docTitleStr, docURLStr);
1812 docTitleStr = nsnull;
1813 docURLStr = nsnull;
1816 if (docTitleStr) nsMemory::Free(docTitleStr);
1817 if (docURLStr) nsMemory::Free(docURLStr);
1819 PR_PL(("****************** Begin Document ************************\n"));
1821 NS_ENSURE_SUCCESS(rv, rv);
1823 // This will print the docshell document
1824 // when it completes asynchronously in the DonePrintingPages method
1825 // it will check to see if there are more docshells to be printed and
1826 // then PrintDocContent will be called again.
1828 if (mIsDoingPrinting) {
1829 PrintDocContent(mPrt->mPrintObject, rv); // ignore return value
1832 return rv;
1835 //-------------------------------------------------------
1836 // Recursively reflow each sub-doc and then calc
1837 // all the frame locations of the sub-docs
1838 nsresult
1839 nsPrintEngine::ReflowDocList(nsPrintObject* aPO, PRBool aSetPixelScale)
1841 NS_ENSURE_ARG_POINTER(aPO);
1843 // Check to see if the subdocument's element has been hidden by the parent document
1844 if (aPO->mParent && aPO->mParent->mPresShell) {
1845 nsIFrame * frame = aPO->mContent->GetPrimaryFrame();
1846 if (frame) {
1847 if (!frame->GetStyleVisibility()->IsVisible()) {
1848 aPO->mDontPrint = PR_TRUE;
1849 aPO->mInvisible = PR_TRUE;
1850 return NS_OK;
1855 // Here is where we set the shrinkage value into the DC
1856 // and this is what actually makes it shrink
1857 if (aSetPixelScale && aPO->mFrameType != eIFrame) {
1858 float ratio;
1859 if (mPrt->mPrintFrameType == nsIPrintSettings::kFramesAsIs || mPrt->mPrintFrameType == nsIPrintSettings::kNoFrames) {
1860 ratio = mPrt->mShrinkRatio - 0.005f; // round down
1861 } else {
1862 ratio = aPO->mShrinkRatio - 0.005f; // round down
1864 aPO->mZoomRatio = ratio;
1865 } else if (!mPrt->mShrinkToFit) {
1866 double scaling;
1867 mPrt->mPrintSettings->GetScaling(&scaling);
1868 aPO->mZoomRatio = float(scaling);
1871 nsresult rv;
1872 // Reflow the PO
1873 rv = ReflowPrintObject(aPO);
1874 NS_ENSURE_SUCCESS(rv, rv);
1876 PRInt32 cnt = aPO->mKids.Length();
1877 for (PRInt32 i=0;i<cnt;i++) {
1878 rv = ReflowDocList(aPO->mKids[i], aSetPixelScale);
1879 NS_ENSURE_SUCCESS(rv, rv);
1881 return NS_OK;
1884 //-------------------------------------------------------
1885 // Reflow a nsPrintObject
1886 nsresult
1887 nsPrintEngine::ReflowPrintObject(nsPrintObject * aPO)
1889 NS_ASSERTION(aPO, "Pointer is null!");
1890 if (!aPO) return NS_ERROR_FAILURE;
1892 nsSize adjSize;
1893 PRBool documentIsTopLevel;
1894 if (!aPO->IsPrintable())
1895 return NS_OK;
1897 PRBool canCreateScrollbars = PR_TRUE;
1898 nsIView* parentView = nsnull;
1900 if (aPO->mParent && aPO->mParent->IsPrintable()) {
1901 nsIFrame* frame = aPO->mContent->GetPrimaryFrame();
1902 // Without a frame, this document can't be displayed; therefore, there is no
1903 // point to reflowing it
1904 if (!frame) {
1905 SetPrintPO(aPO, PR_FALSE);
1906 return NS_OK;
1909 //XXX If printing supported printing document hierarchies with non-constant
1910 // zoom this would be wrong as we use the same mPrt->mPrintDC for all
1911 // subdocuments.
1912 adjSize = frame->GetContentRect().Size();
1913 documentIsTopLevel = PR_FALSE;
1914 // presshell exists because parent is printable
1916 // the top nsPrintObject's widget will always have scrollbars
1917 if (frame && frame->GetType() == nsGkAtoms::subDocumentFrame) {
1918 nsIView* view = frame->GetView();
1919 NS_ENSURE_TRUE(view, NS_ERROR_FAILURE);
1920 view = view->GetFirstChild();
1921 NS_ENSURE_TRUE(view, NS_ERROR_FAILURE);
1922 parentView = view;
1923 canCreateScrollbars = PR_FALSE;
1925 } else {
1926 nscoord pageWidth, pageHeight;
1927 mPrt->mPrintDC->GetDeviceSurfaceDimensions(pageWidth, pageHeight);
1928 #if defined(XP_UNIX) && !defined(XP_MACOSX)
1929 // If we're in landscape mode on Linux, the device surface will have
1930 // been rotated, so for the purposes of reflowing content, we'll
1931 // treat device's height as our width and its width as our height,
1932 PRInt32 orientation;
1933 mPrt->mPrintSettings->GetOrientation(&orientation);
1934 if (nsIPrintSettings::kLandscapeOrientation == orientation) {
1935 adjSize = nsSize(pageHeight, pageWidth);
1936 } else {
1937 adjSize = nsSize(pageWidth, pageHeight);
1939 #else
1940 adjSize = nsSize(pageWidth, pageHeight);
1941 #endif // XP_UNIX && !XP_MACOSX
1942 documentIsTopLevel = PR_TRUE;
1944 if (mIsCreatingPrintPreview) {
1945 nsCOMPtr<nsIDocumentViewer> dv = do_QueryInterface(mDocViewerPrint);
1946 if (dv) {
1947 parentView = dv->FindContainerView();
1952 NS_ASSERTION(!aPO->mPresContext, "Recreating prescontext");
1954 // create the PresContext
1955 aPO->mPresContext = new nsPresContext(aPO->mDocument,
1956 mIsCreatingPrintPreview ? nsPresContext::eContext_PrintPreview:
1957 nsPresContext::eContext_Print);
1958 NS_ENSURE_TRUE(aPO->mPresContext, NS_ERROR_OUT_OF_MEMORY);
1959 aPO->mPresContext->SetPrintSettings(mPrt->mPrintSettings);
1961 // set the presentation context to the value in the print settings
1962 PRBool printBGColors;
1963 mPrt->mPrintSettings->GetPrintBGColors(&printBGColors);
1964 aPO->mPresContext->SetBackgroundColorDraw(printBGColors);
1965 mPrt->mPrintSettings->GetPrintBGImages(&printBGColors);
1966 aPO->mPresContext->SetBackgroundImageDraw(printBGColors);
1968 // init it with the DC
1969 nsresult rv = aPO->mPresContext->Init(mPrt->mPrintDC);
1970 NS_ENSURE_SUCCESS(rv, rv);
1972 aPO->mViewManager = do_CreateInstance(kViewManagerCID, &rv);
1973 NS_ENSURE_SUCCESS(rv,rv);
1975 rv = aPO->mViewManager->Init(mPrt->mPrintDC);
1976 NS_ENSURE_SUCCESS(rv,rv);
1978 nsStyleSet* styleSet;
1979 rv = mDocViewerPrint->CreateStyleSet(aPO->mDocument, &styleSet);
1980 NS_ENSURE_SUCCESS(rv, rv);
1982 rv = aPO->mDocument->CreateShell(aPO->mPresContext, aPO->mViewManager,
1983 styleSet, getter_AddRefs(aPO->mPresShell));
1984 if (NS_FAILED(rv)) {
1985 delete styleSet;
1986 return rv;
1989 styleSet->EndUpdate();
1991 // The pres shell now owns the style set object.
1993 PR_PL(("In DV::ReflowPrintObject PO: %p (%9s) Setting w,h to %d,%d\n", aPO,
1994 gFrameTypesStr[aPO->mFrameType], adjSize.width, adjSize.height));
1996 // Create a child window of the parent that is our "root view/window"
1997 nsRect tbounds = nsRect(nsPoint(0, 0), adjSize);
1998 nsIView* rootView = aPO->mViewManager->CreateView(tbounds, parentView);
1999 NS_ENSURE_TRUE(rootView, NS_ERROR_OUT_OF_MEMORY);
2001 if (mIsCreatingPrintPreview && documentIsTopLevel) {
2002 aPO->mPresContext->SetPaginatedScrolling(canCreateScrollbars);
2005 // Setup hierarchical relationship in view manager
2006 aPO->mViewManager->SetRootView(rootView);
2008 // This docshell stuff is weird; will go away when we stop having multiple
2009 // presentations per document
2010 nsCOMPtr<nsISupports> supps(do_QueryInterface(aPO->mDocShell));
2011 aPO->mPresContext->SetContainer(supps);
2013 aPO->mPresShell->BeginObservingDocument();
2015 aPO->mPresContext->SetPageSize(adjSize);
2016 aPO->mPresContext->SetIsRootPaginatedDocument(documentIsTopLevel);
2017 aPO->mPresContext->SetPageScale(aPO->mZoomRatio);
2018 // Calculate scale factor from printer to screen
2019 float printDPI = float(mPrt->mPrintDC->AppUnitsPerCSSInch()) /
2020 float(mPrt->mPrintDC->AppUnitsPerDevPixel());
2021 aPO->mPresContext->SetPrintPreviewScale(mScreenDPI / printDPI);
2023 if (mIsCreatingPrintPreview && documentIsTopLevel) {
2024 mDocViewerPrint->SetPrintPreviewPresentation(aPO->mViewManager,
2025 aPO->mPresContext,
2026 aPO->mPresShell);
2029 rv = aPO->mPresShell->InitialReflow(adjSize.width, adjSize.height);
2031 NS_ENSURE_SUCCESS(rv, rv);
2032 NS_ASSERTION(aPO->mPresShell, "Presshell should still be here");
2034 // Process the reflow event InitialReflow posted
2035 aPO->mPresShell->FlushPendingNotifications(Flush_Layout);
2037 nsCOMPtr<nsIPresShell> displayShell;
2038 aPO->mDocShell->GetPresShell(getter_AddRefs(displayShell));
2039 // Transfer Selection Ranges to the new Print PresShell
2040 nsCOMPtr<nsISelection> selection, selectionPS;
2041 // It's okay if there is no display shell, just skip copying the selection
2042 if (displayShell) {
2043 selection = displayShell->GetCurrentSelection(nsISelectionController::SELECTION_NORMAL);
2045 selectionPS = aPO->mPresShell->GetCurrentSelection(nsISelectionController::SELECTION_NORMAL);
2046 if (selection && selectionPS) {
2047 PRInt32 cnt;
2048 selection->GetRangeCount(&cnt);
2049 PRInt32 inx;
2050 for (inx=0;inx<cnt;inx++) {
2051 nsCOMPtr<nsIDOMRange> range;
2052 if (NS_SUCCEEDED(selection->GetRangeAt(inx, getter_AddRefs(range))))
2053 selectionPS->AddRange(range);
2057 // If we are trying to shrink the contents to fit on the page
2058 // we must first locate the "pageContent" frame
2059 // Then we walk the frame tree and look for the "xmost" frame
2060 // this is the frame where the right-hand side of the frame extends
2061 // the furthest
2062 if (mPrt->mShrinkToFit && documentIsTopLevel) {
2063 nsIPageSequenceFrame* pageSequence = aPO->mPresShell->GetPageSequenceFrame();
2064 NS_ENSURE_STATE(pageSequence);
2065 pageSequence->GetSTFPercent(aPO->mShrinkRatio);
2068 #ifdef EXTENDED_DEBUG_PRINTING
2069 if (kPrintingLogMod && kPrintingLogMod->level == DUMP_LAYOUT_LEVEL) {
2070 char * docStr;
2071 char * urlStr;
2072 GetDocTitleAndURL(aPO, docStr, urlStr);
2073 char filename[256];
2074 sprintf(filename, "print_dump_%d.txt", gDumpFileNameCnt++);
2075 // Dump all the frames and view to a a file
2076 FILE * fd = fopen(filename, "w");
2077 if (fd) {
2078 nsIFrame *theRootFrame =
2079 aPO->mPresShell->FrameManager()->GetRootFrame();
2080 fprintf(fd, "Title: %s\n", docStr?docStr:"");
2081 fprintf(fd, "URL: %s\n", urlStr?urlStr:"");
2082 fprintf(fd, "--------------- Frames ----------------\n");
2083 nsCOMPtr<nsIRenderingContext> renderingContext;
2084 mPrt->mPrintDocDC->CreateRenderingContext(*getter_AddRefs(renderingContext));
2085 RootFrameList(aPO->mPresContext, fd, 0);
2086 //DumpFrames(fd, aPO->mPresContext, renderingContext, theRootFrame, 0);
2087 fprintf(fd, "---------------------------------------\n\n");
2088 fprintf(fd, "--------------- Views From Root Frame----------------\n");
2089 nsIView* v = theRootFrame->GetView();
2090 if (v) {
2091 v->List(fd);
2092 } else {
2093 printf("View is null!\n");
2095 if (docShell) {
2096 fprintf(fd, "--------------- All Views ----------------\n");
2097 DumpViews(docShell, fd);
2098 fprintf(fd, "---------------------------------------\n\n");
2100 fclose(fd);
2102 if (docStr) nsMemory::Free(docStr);
2103 if (urlStr) nsMemory::Free(urlStr);
2105 #endif
2107 return NS_OK;
2110 //-------------------------------------------------------
2111 // Figure out how many documents and how many total pages we are printing
2112 void
2113 nsPrintEngine::CalcNumPrintablePages(PRInt32& aNumPages)
2115 aNumPages = 0;
2116 // Count the number of printable documents
2117 // and printable pages
2118 for (PRUint32 i=0; i<mPrt->mPrintDocList.Length(); i++) {
2119 nsPrintObject* po = mPrt->mPrintDocList.ElementAt(i);
2120 NS_ASSERTION(po, "nsPrintObject can't be null!");
2121 if (po->mPresContext && po->mPresContext->IsRootPaginatedDocument()) {
2122 nsIPageSequenceFrame* pageSequence = po->mPresShell->GetPageSequenceFrame();
2123 nsIFrame * seqFrame = do_QueryFrame(pageSequence);
2124 if (seqFrame) {
2125 nsIFrame* frame = seqFrame->GetFirstChild(nsnull);
2126 while (frame) {
2127 aNumPages++;
2128 frame = frame->GetNextSibling();
2134 //-----------------------------------------------------------------
2135 //-- Done: Reflow Methods
2136 //-----------------------------------------------------------------
2138 //-----------------------------------------------------------------
2139 //-- Section: Printing Methods
2140 //-----------------------------------------------------------------
2142 //-------------------------------------------------------
2143 // Called for each DocShell that needs to be printed
2144 PRBool
2145 nsPrintEngine::PrintDocContent(nsPrintObject* aPO, nsresult& aStatus)
2147 NS_ASSERTION(aPO, "Pointer is null!");
2148 aStatus = NS_OK;
2150 if (!aPO->mHasBeenPrinted && aPO->IsPrintable()) {
2151 aStatus = DoPrint(aPO);
2152 return PR_TRUE;
2155 // If |aPO->mPrintAsIs| and |aPO->mHasBeenPrinted| are true,
2156 // the kids frames are already processed in |PrintPage|.
2157 if (!aPO->mInvisible && !(aPO->mPrintAsIs && aPO->mHasBeenPrinted)) {
2158 for (PRUint32 i=0;i<aPO->mKids.Length();i++) {
2159 nsPrintObject* po = aPO->mKids[i];
2160 PRBool printed = PrintDocContent(po, aStatus);
2161 if (printed || NS_FAILED(aStatus)) {
2162 return PR_TRUE;
2166 return PR_FALSE;
2169 static already_AddRefed<nsIDOMNode>
2170 GetEqualNodeInCloneTree(nsIDOMNode* aNode, nsIDocument* aDoc)
2172 nsCOMPtr<nsIContent> content = do_QueryInterface(aNode);
2173 // Selections in anonymous subtrees aren't supported.
2174 if (content && content->IsInAnonymousSubtree()) {
2175 return nsnull;
2178 nsCOMPtr<nsINode> node = do_QueryInterface(aNode);
2179 NS_ENSURE_TRUE(node, nsnull);
2181 nsTArray<PRInt32> indexArray;
2182 nsINode* current = node;
2183 NS_ENSURE_TRUE(current, nsnull);
2184 while (current) {
2185 nsINode* parent = current->GetNodeParent();
2186 if (!parent) {
2187 break;
2189 PRInt32 index = parent->IndexOf(current);
2190 NS_ENSURE_TRUE(index >= 0, nsnull);
2191 indexArray.AppendElement(index);
2192 current = parent;
2194 NS_ENSURE_TRUE(current->IsNodeOfType(nsINode::eDOCUMENT), nsnull);
2196 current = aDoc;
2197 for (PRInt32 i = indexArray.Length() - 1; i >= 0; --i) {
2198 current = current->GetChildAt(indexArray[i]);
2199 NS_ENSURE_TRUE(current, nsnull);
2201 nsCOMPtr<nsIDOMNode> result = do_QueryInterface(current);
2202 return result.forget();
2205 static nsresult CloneRangeToSelection(nsIDOMRange* aRange,
2206 nsIDocument* aDoc,
2207 nsISelection* aSelection)
2209 PRBool collapsed = PR_FALSE;
2210 aRange->GetCollapsed(&collapsed);
2211 if (collapsed) {
2212 return NS_OK;
2215 nsCOMPtr<nsIDOMNode> startContainer, endContainer;
2216 PRInt32 startOffset = -1, endOffset = -1;
2217 aRange->GetStartContainer(getter_AddRefs(startContainer));
2218 aRange->GetStartOffset(&startOffset);
2219 aRange->GetEndContainer(getter_AddRefs(endContainer));
2220 aRange->GetEndOffset(&endOffset);
2221 NS_ENSURE_STATE(startContainer && endContainer);
2223 nsCOMPtr<nsIDOMNode> newStart = GetEqualNodeInCloneTree(startContainer, aDoc);
2224 nsCOMPtr<nsIDOMNode> newEnd = GetEqualNodeInCloneTree(endContainer, aDoc);
2225 NS_ENSURE_STATE(newStart && newEnd);
2227 nsCOMPtr<nsIDOMRange> range;
2228 NS_NewRange(getter_AddRefs(range));
2229 NS_ENSURE_TRUE(range, NS_ERROR_OUT_OF_MEMORY);
2231 nsresult rv = range->SetStart(newStart, startOffset);
2232 NS_ENSURE_SUCCESS(rv, rv);
2233 rv = range->SetEnd(newEnd, endOffset);
2234 NS_ENSURE_SUCCESS(rv, rv);
2236 return aSelection->AddRange(range);
2239 static nsresult CloneSelection(nsIDocument* aOrigDoc, nsIDocument* aDoc)
2241 nsIPresShell* origShell = aOrigDoc->GetShell();
2242 nsIPresShell* shell = aDoc->GetShell();
2243 NS_ENSURE_STATE(origShell && shell);
2245 nsCOMPtr<nsISelection> origSelection =
2246 origShell->GetCurrentSelection(nsISelectionController::SELECTION_NORMAL);
2247 nsCOMPtr<nsISelection> selection =
2248 shell->GetCurrentSelection(nsISelectionController::SELECTION_NORMAL);
2249 NS_ENSURE_STATE(origSelection && selection);
2251 PRInt32 rangeCount = 0;
2252 origSelection->GetRangeCount(&rangeCount);
2253 for (PRInt32 i = 0; i < rangeCount; ++i) {
2254 nsCOMPtr<nsIDOMRange> range;
2255 origSelection->GetRangeAt(i, getter_AddRefs(range));
2256 if (range) {
2257 CloneRangeToSelection(range, aDoc, selection);
2260 return NS_OK;
2263 //-------------------------------------------------------
2264 nsresult
2265 nsPrintEngine::DoPrint(nsPrintObject * aPO)
2267 PR_PL(("\n"));
2268 PR_PL(("**************************** %s ****************************\n", gFrameTypesStr[aPO->mFrameType]));
2269 PR_PL(("****** In DV::DoPrint PO: %p \n", aPO));
2271 nsIPresShell* poPresShell = aPO->mPresShell;
2272 nsPresContext* poPresContext = aPO->mPresContext;
2274 NS_ASSERTION(poPresContext, "PrintObject has not been reflowed");
2275 NS_ASSERTION(poPresContext->Type() != nsPresContext::eContext_PrintPreview,
2276 "How did this context end up here?");
2278 if (mPrt->mPrintProgressParams) {
2279 SetDocAndURLIntoProgress(aPO, mPrt->mPrintProgressParams);
2283 PRInt16 printRangeType = nsIPrintSettings::kRangeAllPages;
2284 nsresult rv;
2285 if (mPrt->mPrintSettings != nsnull) {
2286 mPrt->mPrintSettings->GetPrintRange(&printRangeType);
2289 // Ask the page sequence frame to print all the pages
2290 nsIPageSequenceFrame* pageSequence = poPresShell->GetPageSequenceFrame();
2291 NS_ASSERTION(nsnull != pageSequence, "no page sequence frame");
2293 // We are done preparing for printing, so we can turn this off
2294 mPrt->mPreparingForPrint = PR_FALSE;
2296 // mPrt->mDebugFilePtr this is onlu non-null when compiled for debugging
2297 if (nsnull != mPrt->mDebugFilePtr) {
2298 #ifdef NS_DEBUG
2299 // output the regression test
2300 nsIFrame* root = poPresShell->FrameManager()->GetRootFrame();
2301 root->DumpRegressionData(poPresContext, mPrt->mDebugFilePtr, 0);
2302 fclose(mPrt->mDebugFilePtr);
2303 SetIsPrinting(PR_FALSE);
2304 #endif
2305 } else {
2306 #ifdef EXTENDED_DEBUG_PRINTING
2307 nsIFrame* rootFrame = poPresShell->FrameManager()->GetRootFrame();
2308 if (aPO->IsPrintable()) {
2309 char * docStr;
2310 char * urlStr;
2311 GetDocTitleAndURL(aPO, docStr, urlStr);
2312 DumpLayoutData(docStr, urlStr, poPresContext, mPrt->mPrintDocDC, rootFrame, docShell, nsnull);
2313 if (docStr) nsMemory::Free(docStr);
2314 if (urlStr) nsMemory::Free(urlStr);
2316 #endif
2318 if (!mPrt->mPrintSettings) {
2319 // not sure what to do here!
2320 SetIsPrinting(PR_FALSE);
2321 return NS_ERROR_FAILURE;
2324 PRUnichar * docTitleStr = nsnull;
2325 PRUnichar * docURLStr = nsnull;
2327 GetDisplayTitleAndURL(aPO, &docTitleStr, &docURLStr, eDocTitleDefBlank);
2329 if (nsIPrintSettings::kRangeSelection == printRangeType) {
2330 CloneSelection(aPO->mDocument->GetOriginalDocument(), aPO->mDocument);
2332 poPresContext->SetIsRenderingOnlySelection(PR_TRUE);
2333 // temporarily creating rendering context
2334 // which is needed to dinf the selection frames
2335 nsCOMPtr<nsIRenderingContext> rc;
2336 mPrt->mPrintDC->CreateRenderingContext(*getter_AddRefs(rc));
2338 // find the starting and ending page numbers
2339 // via the selection
2340 nsIFrame* startFrame;
2341 nsIFrame* endFrame;
2342 PRInt32 startPageNum;
2343 PRInt32 endPageNum;
2344 nsRect startRect;
2345 nsRect endRect;
2347 nsCOMPtr<nsISelection> selectionPS;
2348 selectionPS = poPresShell->GetCurrentSelection(nsISelectionController::SELECTION_NORMAL);
2350 rv = GetPageRangeForSelection(poPresShell, poPresContext, *rc, selectionPS, pageSequence,
2351 &startFrame, startPageNum, startRect,
2352 &endFrame, endPageNum, endRect);
2353 if (NS_SUCCEEDED(rv)) {
2354 mPrt->mPrintSettings->SetStartPageRange(startPageNum);
2355 mPrt->mPrintSettings->SetEndPageRange(endPageNum);
2356 nsIntMargin marginTwips(0,0,0,0);
2357 nsIntMargin unwrtMarginTwips(0,0,0,0);
2358 mPrt->mPrintSettings->GetMarginInTwips(marginTwips);
2359 mPrt->mPrintSettings->GetUnwriteableMarginInTwips(unwrtMarginTwips);
2360 nsMargin totalMargin = poPresContext->CSSTwipsToAppUnits(marginTwips +
2361 unwrtMarginTwips);
2362 if (startPageNum == endPageNum) {
2363 startRect.y -= totalMargin.top;
2364 endRect.y -= totalMargin.top;
2366 // Clip out selection regions above the top of the first page
2367 if (startRect.y < 0) {
2368 // Reduce height to be the height of the positive-territory
2369 // region of original rect
2370 startRect.height = NS_MAX(0, startRect.YMost());
2371 startRect.y = 0;
2373 if (endRect.y < 0) {
2374 // Reduce height to be the height of the positive-territory
2375 // region of original rect
2376 endRect.height = NS_MAX(0, endRect.YMost());
2377 endRect.y = 0;
2379 NS_ASSERTION(endRect.y >= startRect.y,
2380 "Selection end point should be after start point");
2381 NS_ASSERTION(startRect.height >= 0,
2382 "rect should have non-negative height.");
2383 NS_ASSERTION(endRect.height >= 0,
2384 "rect should have non-negative height.");
2386 nscoord selectionHgt = endRect.y + endRect.height - startRect.y;
2387 // XXX This is temporary fix for printing more than one page of a selection
2388 pageSequence->SetSelectionHeight(startRect.y * aPO->mZoomRatio,
2389 selectionHgt * aPO->mZoomRatio);
2391 // calc total pages by getting calculating the selection's height
2392 // and then dividing it by how page content frames will fit.
2393 nscoord pageWidth, pageHeight;
2394 mPrt->mPrintDC->GetDeviceSurfaceDimensions(pageWidth, pageHeight);
2395 pageHeight -= totalMargin.top + totalMargin.bottom;
2396 PRInt32 totalPages = NSToIntCeil(float(selectionHgt) * aPO->mZoomRatio / float(pageHeight));
2397 pageSequence->SetTotalNumPages(totalPages);
2402 nsIFrame * seqFrame = do_QueryFrame(pageSequence);
2403 if (!seqFrame) {
2404 SetIsPrinting(PR_FALSE);
2405 if (docTitleStr) nsMemory::Free(docTitleStr);
2406 if (docURLStr) nsMemory::Free(docURLStr);
2407 return NS_ERROR_FAILURE;
2410 mPageSeqFrame = pageSequence;
2411 mPageSeqFrame->StartPrint(poPresContext, mPrt->mPrintSettings, docTitleStr, docURLStr);
2413 // Schedule Page to Print
2414 PR_PL(("Scheduling Print of PO: %p (%s) \n", aPO, gFrameTypesStr[aPO->mFrameType]));
2415 StartPagePrintTimer(aPO);
2419 return NS_OK;
2422 //---------------------------------------------------------------------
2423 void
2424 nsPrintEngine::SetDocAndURLIntoProgress(nsPrintObject* aPO,
2425 nsIPrintProgressParams* aParams)
2427 NS_ASSERTION(aPO, "Must have vaild nsPrintObject");
2428 NS_ASSERTION(aParams, "Must have vaild nsIPrintProgressParams");
2430 if (!aPO || !aPO->mDocShell || !aParams) {
2431 return;
2433 const PRUint32 kTitleLength = 64;
2435 PRUnichar * docTitleStr;
2436 PRUnichar * docURLStr;
2437 GetDisplayTitleAndURL(aPO, &docTitleStr, &docURLStr, eDocTitleDefURLDoc);
2439 // Make sure the Titles & URLS don't get too long for the progress dialog
2440 ElipseLongString(docTitleStr, kTitleLength, PR_FALSE);
2441 ElipseLongString(docURLStr, kTitleLength, PR_TRUE);
2443 aParams->SetDocTitle(docTitleStr);
2444 aParams->SetDocURL(docURLStr);
2446 if (docTitleStr != nsnull) nsMemory::Free(docTitleStr);
2447 if (docURLStr != nsnull) nsMemory::Free(docURLStr);
2450 //---------------------------------------------------------------------
2451 void
2452 nsPrintEngine::ElipseLongString(PRUnichar *& aStr, const PRUint32 aLen, PRBool aDoFront)
2454 // Make sure the URLS don't get too long for the progress dialog
2455 if (aStr && nsCRT::strlen(aStr) > aLen) {
2456 if (aDoFront) {
2457 PRUnichar * ptr = &aStr[nsCRT::strlen(aStr)-aLen+3];
2458 nsAutoString newStr;
2459 newStr.AppendLiteral("...");
2460 newStr += ptr;
2461 nsMemory::Free(aStr);
2462 aStr = ToNewUnicode(newStr);
2463 } else {
2464 nsAutoString newStr(aStr);
2465 newStr.SetLength(aLen-3);
2466 newStr.AppendLiteral("...");
2467 nsMemory::Free(aStr);
2468 aStr = ToNewUnicode(newStr);
2473 //-------------------------------------------------------
2474 PRBool
2475 nsPrintEngine::PrintPage(nsPrintObject* aPO,
2476 PRBool& aInRange)
2478 NS_ASSERTION(aPO, "aPO is null!");
2479 NS_ASSERTION(mPageSeqFrame, "mPageSeqFrame is null!");
2480 NS_ASSERTION(mPrt, "mPrt is null!");
2482 // Although these should NEVER be NULL
2483 // This is added insurance, to make sure we don't crash in optimized builds
2484 if (!mPrt || !aPO || !mPageSeqFrame) {
2485 ShowPrintErrorDialog(NS_ERROR_FAILURE);
2486 return PR_TRUE; // means we are done printing
2489 PR_PL(("-----------------------------------\n"));
2490 PR_PL(("------ In DV::PrintPage PO: %p (%s)\n", aPO, gFrameTypesStr[aPO->mFrameType]));
2492 // Check setting to see if someone request it be cancelled
2493 PRBool isCancelled = PR_FALSE;
2494 mPrt->mPrintSettings->GetIsCancelled(&isCancelled);
2495 if (isCancelled)
2496 return PR_TRUE;
2498 PRInt32 pageNum, numPages, endPage;
2499 mPageSeqFrame->GetCurrentPageNum(&pageNum);
2500 mPageSeqFrame->GetNumPages(&numPages);
2502 PRBool donePrinting;
2503 PRBool isDoingPrintRange;
2504 mPageSeqFrame->IsDoingPrintRange(&isDoingPrintRange);
2505 if (isDoingPrintRange) {
2506 PRInt32 fromPage;
2507 PRInt32 toPage;
2508 mPageSeqFrame->GetPrintRange(&fromPage, &toPage);
2510 if (fromPage > numPages) {
2511 return PR_TRUE;
2513 if (toPage > numPages) {
2514 toPage = numPages;
2517 PR_PL(("****** Printing Page %d printing from %d to page %d\n", pageNum, fromPage, toPage));
2519 donePrinting = pageNum >= toPage;
2520 aInRange = pageNum >= fromPage && pageNum <= toPage;
2521 endPage = (toPage - fromPage)+1;
2522 } else {
2523 PR_PL(("****** Printing Page %d of %d page(s)\n", pageNum, numPages));
2525 donePrinting = pageNum >= numPages;
2526 endPage = numPages;
2527 aInRange = PR_TRUE;
2530 // XXX This is wrong, but the actual behavior in the presence of a print
2531 // range sucks.
2532 if (mPrt->mPrintFrameType == nsIPrintSettings::kEachFrameSep)
2533 endPage = mPrt->mNumPrintablePages;
2535 mPrt->DoOnProgressChange(++mPrt->mNumPagesPrinted, endPage, PR_FALSE, 0);
2537 // Print the Page
2538 // if a print job was cancelled externally, an EndPage or BeginPage may
2539 // fail and the failure is passed back here.
2540 // Returning PR_TRUE means we are done printing.
2542 // When rv == NS_ERROR_ABORT, it means we want out of the
2543 // print job without displaying any error messages
2544 nsresult rv = mPageSeqFrame->PrintNextPage();
2545 if (NS_FAILED(rv)) {
2546 if (rv != NS_ERROR_ABORT) {
2547 ShowPrintErrorDialog(rv);
2548 mPrt->mIsAborted = PR_TRUE;
2550 return PR_TRUE;
2553 mPageSeqFrame->DoPageEnd();
2555 return donePrinting;
2558 /** ---------------------------------------------------
2559 * Find by checking frames type
2561 nsresult
2562 nsPrintEngine::FindSelectionBoundsWithList(nsPresContext* aPresContext,
2563 nsIRenderingContext& aRC,
2564 nsIAtom* aList,
2565 nsIFrame * aParentFrame,
2566 nsRect& aRect,
2567 nsIFrame *& aStartFrame,
2568 nsRect& aStartRect,
2569 nsIFrame *& aEndFrame,
2570 nsRect& aEndRect)
2572 NS_ASSERTION(aPresContext, "Pointer is null!");
2573 NS_ASSERTION(aParentFrame, "Pointer is null!");
2575 nsIFrame* child = aParentFrame->GetFirstChild(aList);
2576 aRect += aParentFrame->GetPosition();
2577 while (child) {
2578 // only leaf frames have this bit flipped
2579 // then check the hard way
2580 PRBool isSelected = (child->GetStateBits() & NS_FRAME_SELECTED_CONTENT)
2581 == NS_FRAME_SELECTED_CONTENT;
2582 if (isSelected) {
2583 isSelected = child->IsVisibleForPainting();
2586 if (isSelected) {
2587 nsRect r = child->GetRect();
2588 if (aStartFrame == nsnull) {
2589 aStartFrame = child;
2590 aStartRect.SetRect(aRect.x + r.x, aRect.y + r.y, r.width, r.height);
2591 } else {
2592 aEndFrame = child;
2593 aEndRect.SetRect(aRect.x + r.x, aRect.y + r.y, r.width, r.height);
2596 FindSelectionBounds(aPresContext, aRC, child, aRect, aStartFrame, aStartRect, aEndFrame, aEndRect);
2597 child = child->GetNextSibling();
2599 aRect -= aParentFrame->GetPosition();
2600 return NS_OK;
2603 //-------------------------------------------------------
2604 // Find the Frame that is XMost
2605 nsresult
2606 nsPrintEngine::FindSelectionBounds(nsPresContext* aPresContext,
2607 nsIRenderingContext& aRC,
2608 nsIFrame * aParentFrame,
2609 nsRect& aRect,
2610 nsIFrame *& aStartFrame,
2611 nsRect& aStartRect,
2612 nsIFrame *& aEndFrame,
2613 nsRect& aEndRect)
2615 NS_ASSERTION(aPresContext, "Pointer is null!");
2616 NS_ASSERTION(aParentFrame, "Pointer is null!");
2618 // loop through named child lists
2619 nsIAtom* childListName = nsnull;
2620 PRInt32 childListIndex = 0;
2621 do {
2622 nsresult rv = FindSelectionBoundsWithList(aPresContext, aRC, childListName, aParentFrame, aRect, aStartFrame, aStartRect, aEndFrame, aEndRect);
2623 NS_ENSURE_SUCCESS(rv, rv);
2624 childListName = aParentFrame->GetAdditionalChildListName(childListIndex++);
2625 } while (childListName);
2626 return NS_OK;
2629 /** ---------------------------------------------------
2630 * This method finds the starting and ending page numbers
2631 * of the selection and also returns rect for each where
2632 * the x,y of the rect is relative to the very top of the
2633 * frame tree (absolutely positioned)
2635 nsresult
2636 nsPrintEngine::GetPageRangeForSelection(nsIPresShell * aPresShell,
2637 nsPresContext* aPresContext,
2638 nsIRenderingContext& aRC,
2639 nsISelection* aSelection,
2640 nsIPageSequenceFrame* aPageSeqFrame,
2641 nsIFrame** aStartFrame,
2642 PRInt32& aStartPageNum,
2643 nsRect& aStartRect,
2644 nsIFrame** aEndFrame,
2645 PRInt32& aEndPageNum,
2646 nsRect& aEndRect)
2648 NS_ASSERTION(aPresShell, "Pointer is null!");
2649 NS_ASSERTION(aPresContext, "Pointer is null!");
2650 NS_ASSERTION(aSelection, "Pointer is null!");
2651 NS_ASSERTION(aPageSeqFrame, "Pointer is null!");
2652 NS_ASSERTION(aStartFrame, "Pointer is null!");
2653 NS_ASSERTION(aEndFrame, "Pointer is null!");
2655 nsIFrame * seqFrame = do_QueryFrame(aPageSeqFrame);
2656 if (!seqFrame) {
2657 return NS_ERROR_FAILURE;
2660 nsIFrame * startFrame = nsnull;
2661 nsIFrame * endFrame = nsnull;
2663 // start out with the sequence frame and search the entire frame tree
2664 // capturing the starting and ending child frames of the selection
2665 // and their rects
2666 nsRect r = seqFrame->GetRect();
2667 FindSelectionBounds(aPresContext, aRC, seqFrame, r,
2668 startFrame, aStartRect, endFrame, aEndRect);
2670 #ifdef DEBUG_rodsX
2671 printf("Start Frame: %p\n", startFrame);
2672 printf("End Frame: %p\n", endFrame);
2673 #endif
2675 // initial the page numbers here
2676 // in case we don't find and frames
2677 aStartPageNum = -1;
2678 aEndPageNum = -1;
2680 nsIFrame * startPageFrame;
2681 nsIFrame * endPageFrame;
2683 // check to make sure we found a starting frame
2684 if (startFrame != nsnull) {
2685 // Now search up the tree to find what page the
2686 // start/ending selections frames are on
2688 // Check to see if start should be same as end if
2689 // the end frame comes back null
2690 if (endFrame == nsnull) {
2691 // XXX the "GetPageFrame" step could be integrated into
2692 // the FindSelectionBounds step, but walking up to find
2693 // the parent of a child frame isn't expensive and it makes
2694 // FindSelectionBounds a little easier to understand
2695 startPageFrame = nsLayoutUtils::GetPageFrame(startFrame);
2696 endPageFrame = startPageFrame;
2697 aEndRect = aStartRect;
2698 } else {
2699 startPageFrame = nsLayoutUtils::GetPageFrame(startFrame);
2700 endPageFrame = nsLayoutUtils::GetPageFrame(endFrame);
2702 } else {
2703 return NS_ERROR_FAILURE;
2706 #ifdef DEBUG_rodsX
2707 printf("Start Page: %p\n", startPageFrame);
2708 printf("End Page: %p\n", endPageFrame);
2710 // dump all the pages and their pointers
2712 PRInt32 pageNum = 1;
2713 nsIFrame* child = seqFrame->GetFirstChild(nsnull);
2714 while (child != nsnull) {
2715 printf("Page: %d - %p\n", pageNum, child);
2716 pageNum++;
2717 child = child->GetNextSibling();
2720 #endif
2722 // Now that we have the page frames
2723 // find out what the page numbers are for each frame
2724 PRInt32 pageNum = 1;
2725 nsIFrame* page = seqFrame->GetFirstChild(nsnull);
2726 while (page != nsnull) {
2727 if (page == startPageFrame) {
2728 aStartPageNum = pageNum;
2730 if (page == endPageFrame) {
2731 aEndPageNum = pageNum;
2733 pageNum++;
2734 page = page->GetNextSibling();
2737 #ifdef DEBUG_rodsX
2738 printf("Start Page No: %d\n", aStartPageNum);
2739 printf("End Page No: %d\n", aEndPageNum);
2740 #endif
2742 *aStartFrame = startPageFrame;
2743 *aEndFrame = endPageFrame;
2745 return NS_OK;
2748 //-----------------------------------------------------------------
2749 //-- Done: Printing Methods
2750 //-----------------------------------------------------------------
2753 //-----------------------------------------------------------------
2754 //-- Section: Misc Support Methods
2755 //-----------------------------------------------------------------
2757 //---------------------------------------------------------------------
2758 void nsPrintEngine::SetIsPrinting(PRBool aIsPrinting)
2760 mIsDoingPrinting = aIsPrinting;
2761 // Calling SetIsPrinting while in print preview confuses the document viewer
2762 // This is safe because we prevent exiting print preview while printing
2763 if (mDocViewerPrint && !mIsDoingPrintPreview) {
2764 mDocViewerPrint->SetIsPrinting(aIsPrinting);
2766 if (mPrt && aIsPrinting) {
2767 mPrt->mPreparingForPrint = PR_TRUE;
2771 //---------------------------------------------------------------------
2772 void nsPrintEngine::SetIsPrintPreview(PRBool aIsPrintPreview)
2774 mIsDoingPrintPreview = aIsPrintPreview;
2776 if (mDocViewerPrint) {
2777 mDocViewerPrint->SetIsPrintPreview(aIsPrintPreview);
2781 //---------------------------------------------------------------------
2782 void
2783 nsPrintEngine::CleanupDocTitleArray(PRUnichar**& aArray, PRInt32& aCount)
2785 for (PRInt32 i = aCount - 1; i >= 0; i--) {
2786 nsMemory::Free(aArray[i]);
2788 nsMemory::Free(aArray);
2789 aArray = NULL;
2790 aCount = 0;
2793 //---------------------------------------------------------------------
2794 // static
2795 PRBool nsPrintEngine::HasFramesetChild(nsIContent* aContent)
2797 if (!aContent) {
2798 return PR_FALSE;
2801 PRUint32 numChildren = aContent->GetChildCount();
2803 // do a breadth search across all siblings
2804 for (PRUint32 i = 0; i < numChildren; ++i) {
2805 nsIContent *child = aContent->GetChildAt(i);
2806 if (child->Tag() == nsGkAtoms::frameset &&
2807 child->IsHTML()) {
2808 return PR_TRUE;
2812 return PR_FALSE;
2817 /** ---------------------------------------------------
2818 * Get the Focused Frame for a documentviewer
2820 already_AddRefed<nsIDOMWindow>
2821 nsPrintEngine::FindFocusedDOMWindow()
2823 nsIFocusManager* fm = nsFocusManager::GetFocusManager();
2824 NS_ENSURE_TRUE(fm, nsnull);
2826 nsCOMPtr<nsPIDOMWindow> window(mDocument->GetWindow());
2827 NS_ENSURE_TRUE(window, nsnull);
2829 nsCOMPtr<nsPIDOMWindow> rootWindow = window->GetPrivateRoot();
2830 NS_ENSURE_TRUE(rootWindow, nsnull);
2832 nsPIDOMWindow* focusedWindow;
2833 nsFocusManager::GetFocusedDescendant(rootWindow, PR_TRUE, &focusedWindow);
2834 NS_ENSURE_TRUE(focusedWindow, nsnull);
2836 if (IsWindowsInOurSubTree(focusedWindow)) {
2837 return focusedWindow;
2840 NS_IF_RELEASE(focusedWindow);
2841 return nsnull;
2844 //---------------------------------------------------------------------
2845 PRBool
2846 nsPrintEngine::IsWindowsInOurSubTree(nsPIDOMWindow * window)
2848 PRBool found = PR_FALSE;
2850 // now check to make sure it is in "our" tree of docshells
2851 if (window) {
2852 nsCOMPtr<nsIDocShellTreeItem> docShellAsItem =
2853 do_QueryInterface(window->GetDocShell());
2855 if (docShellAsItem) {
2856 // get this DocViewer docshell
2857 nsCOMPtr<nsIDocShell> thisDVDocShell(do_QueryInterface(mContainer));
2858 while (!found) {
2859 nsCOMPtr<nsIDocShell> parentDocshell(do_QueryInterface(docShellAsItem));
2860 if (parentDocshell) {
2861 if (parentDocshell == thisDVDocShell) {
2862 found = PR_TRUE;
2863 break;
2865 } else {
2866 break; // at top of tree
2868 nsCOMPtr<nsIDocShellTreeItem> docShellParent;
2869 docShellAsItem->GetSameTypeParent(getter_AddRefs(docShellParent));
2870 docShellAsItem = docShellParent;
2871 } // while
2873 } // scriptobj
2875 return found;
2878 //-------------------------------------------------------
2879 PRBool
2880 nsPrintEngine::DonePrintingPages(nsPrintObject* aPO, nsresult aResult)
2882 //NS_ASSERTION(aPO, "Pointer is null!");
2883 PR_PL(("****** In DV::DonePrintingPages PO: %p (%s)\n", aPO, aPO?gFrameTypesStr[aPO->mFrameType]:""));
2885 if (aPO != nsnull) {
2886 aPO->mHasBeenPrinted = PR_TRUE;
2887 nsresult rv;
2888 PRBool didPrint = PrintDocContent(mPrt->mPrintObject, rv);
2889 if (NS_SUCCEEDED(rv) && didPrint) {
2890 PR_PL(("****** In DV::DonePrintingPages PO: %p (%s) didPrint:%s (Not Done Printing)\n", aPO, gFrameTypesStr[aPO->mFrameType], PRT_YESNO(didPrint)));
2891 return PR_FALSE;
2895 if (NS_SUCCEEDED(aResult)) {
2896 FirePrintCompletionEvent();
2899 TurnScriptingOn(PR_TRUE);
2900 SetIsPrinting(PR_FALSE);
2902 // Release reference to mPagePrintTimer; the timer object destroys itself
2903 // after this returns true
2904 NS_IF_RELEASE(mPagePrintTimer);
2906 return PR_TRUE;
2909 //-------------------------------------------------------
2910 // Recursively sets the PO items to be printed "As Is"
2911 // from the given item down into the tree
2912 void
2913 nsPrintEngine::SetPrintAsIs(nsPrintObject* aPO, PRBool aAsIs)
2915 NS_ASSERTION(aPO, "Pointer is null!");
2917 aPO->mPrintAsIs = aAsIs;
2918 for (PRUint32 i=0;i<aPO->mKids.Length();i++) {
2919 SetPrintAsIs(aPO->mKids[i], aAsIs);
2923 //-------------------------------------------------------
2924 // Given a DOMWindow it recursively finds the PO object that matches
2925 nsPrintObject*
2926 nsPrintEngine::FindPrintObjectByDOMWin(nsPrintObject* aPO,
2927 nsIDOMWindow* aDOMWin)
2929 NS_ASSERTION(aPO, "Pointer is null!");
2931 // Often the CurFocused DOMWindow is passed in
2932 // andit is valid for it to be null, so short circut
2933 if (!aDOMWin) {
2934 return nsnull;
2937 nsCOMPtr<nsIDOMDocument> domDoc;
2938 aDOMWin->GetDocument(getter_AddRefs(domDoc));
2939 nsCOMPtr<nsIDocument> doc = do_QueryInterface(domDoc);
2940 if (aPO->mDocument && aPO->mDocument->GetOriginalDocument() == doc) {
2941 return aPO;
2944 PRInt32 cnt = aPO->mKids.Length();
2945 for (PRInt32 i = 0; i < cnt; ++i) {
2946 nsPrintObject* po = FindPrintObjectByDOMWin(aPO->mKids[i], aDOMWin);
2947 if (po) {
2948 return po;
2952 return nsnull;
2955 //-------------------------------------------------------
2956 nsresult
2957 nsPrintEngine::EnablePOsForPrinting()
2959 // NOTE: All POs have been "turned off" for printing
2960 // this is where we decided which POs get printed.
2961 mPrt->mSelectedPO = nsnull;
2963 if (mPrt->mPrintSettings == nsnull) {
2964 return NS_ERROR_FAILURE;
2967 mPrt->mPrintFrameType = nsIPrintSettings::kNoFrames;
2968 mPrt->mPrintSettings->GetPrintFrameType(&mPrt->mPrintFrameType);
2970 PRInt16 printHowEnable = nsIPrintSettings::kFrameEnableNone;
2971 mPrt->mPrintSettings->GetHowToEnableFrameUI(&printHowEnable);
2973 PRInt16 printRangeType = nsIPrintSettings::kRangeAllPages;
2974 mPrt->mPrintSettings->GetPrintRange(&printRangeType);
2976 PR_PL(("\n"));
2977 PR_PL(("********* nsPrintEngine::EnablePOsForPrinting *********\n"));
2978 PR_PL(("PrintFrameType: %s \n", gPrintFrameTypeStr[mPrt->mPrintFrameType]));
2979 PR_PL(("HowToEnableFrameUI: %s \n", gFrameHowToEnableStr[printHowEnable]));
2980 PR_PL(("PrintRange: %s \n", gPrintRangeStr[printRangeType]));
2981 PR_PL(("----\n"));
2983 // ***** This is the ultimate override *****
2984 // if we are printing the selection (either an IFrame or selection range)
2985 // then set the mPrintFrameType as if it were the selected frame
2986 if (printRangeType == nsIPrintSettings::kRangeSelection) {
2987 mPrt->mPrintFrameType = nsIPrintSettings::kSelectedFrame;
2988 printHowEnable = nsIPrintSettings::kFrameEnableNone;
2991 // This tells us that the "Frame" UI has turned off,
2992 // so therefore there are no FrameSets/Frames/IFrames to be printed
2994 // This means there are not FrameSets,
2995 // but the document could contain an IFrame
2996 if (printHowEnable == nsIPrintSettings::kFrameEnableNone) {
2998 // Print all the pages or a sub range of pages
2999 if (printRangeType == nsIPrintSettings::kRangeAllPages ||
3000 printRangeType == nsIPrintSettings::kRangeSpecifiedPageRange) {
3001 SetPrintPO(mPrt->mPrintObject, PR_TRUE);
3003 // Set the children so they are PrinAsIs
3004 // In this case, the children are probably IFrames
3005 if (mPrt->mPrintObject->mKids.Length() > 0) {
3006 for (PRUint32 i=0;i<mPrt->mPrintObject->mKids.Length();i++) {
3007 nsPrintObject* po = mPrt->mPrintObject->mKids[i];
3008 NS_ASSERTION(po, "nsPrintObject can't be null!");
3009 SetPrintAsIs(po);
3012 // ***** Another override *****
3013 mPrt->mPrintFrameType = nsIPrintSettings::kFramesAsIs;
3015 PR_PL(("PrintFrameType: %s \n", gPrintFrameTypeStr[mPrt->mPrintFrameType]));
3016 PR_PL(("HowToEnableFrameUI: %s \n", gFrameHowToEnableStr[printHowEnable]));
3017 PR_PL(("PrintRange: %s \n", gPrintRangeStr[printRangeType]));
3018 return NS_OK;
3021 // This means we are either printed a selected IFrame or
3022 // we are printing the current selection
3023 if (printRangeType == nsIPrintSettings::kRangeSelection) {
3025 // If the currentFocusDOMWin can'r be null if something is selected
3026 if (mPrt->mCurrentFocusWin) {
3027 // Find the selected IFrame
3028 nsPrintObject * po = FindPrintObjectByDOMWin(mPrt->mPrintObject, mPrt->mCurrentFocusWin);
3029 if (po != nsnull) {
3030 mPrt->mSelectedPO = po;
3031 // Makes sure all of its children are be printed "AsIs"
3032 SetPrintAsIs(po);
3034 // Now, only enable this POs (the selected PO) and all of its children
3035 SetPrintPO(po, PR_TRUE);
3037 // check to see if we have a range selection,
3038 // as oppose to a insert selection
3039 // this means if the user just clicked on the IFrame then
3040 // there will not be a selection so we want the entire page to print
3042 // XXX this is sort of a hack right here to make the page
3043 // not try to reposition itself when printing selection
3044 nsCOMPtr<nsIDOMWindow> domWin =
3045 do_QueryInterface(po->mDocument->GetOriginalDocument()->GetWindow());
3046 if (!IsThereARangeSelection(domWin)) {
3047 printRangeType = nsIPrintSettings::kRangeAllPages;
3048 mPrt->mPrintSettings->SetPrintRange(printRangeType);
3050 PR_PL(("PrintFrameType: %s \n", gPrintFrameTypeStr[mPrt->mPrintFrameType]));
3051 PR_PL(("HowToEnableFrameUI: %s \n", gFrameHowToEnableStr[printHowEnable]));
3052 PR_PL(("PrintRange: %s \n", gPrintRangeStr[printRangeType]));
3053 return NS_OK;
3055 } else {
3056 for (PRUint32 i=0;i<mPrt->mPrintDocList.Length();i++) {
3057 nsPrintObject* po = mPrt->mPrintDocList.ElementAt(i);
3058 NS_ASSERTION(po, "nsPrintObject can't be null!");
3059 nsCOMPtr<nsIDOMWindow> domWin = do_GetInterface(po->mDocShell);
3060 if (IsThereARangeSelection(domWin)) {
3061 mPrt->mCurrentFocusWin = domWin;
3062 SetPrintPO(po, PR_TRUE);
3063 break;
3066 return NS_OK;
3071 // check to see if there is a selection when a FrameSet is present
3072 if (printRangeType == nsIPrintSettings::kRangeSelection) {
3073 // If the currentFocusDOMWin can'r be null if something is selected
3074 if (mPrt->mCurrentFocusWin) {
3075 // Find the selected IFrame
3076 nsPrintObject * po = FindPrintObjectByDOMWin(mPrt->mPrintObject, mPrt->mCurrentFocusWin);
3077 if (po != nsnull) {
3078 mPrt->mSelectedPO = po;
3079 // Makes sure all of its children are be printed "AsIs"
3080 SetPrintAsIs(po);
3082 // Now, only enable this POs (the selected PO) and all of its children
3083 SetPrintPO(po, PR_TRUE);
3085 // check to see if we have a range selection,
3086 // as oppose to a insert selection
3087 // this means if the user just clicked on the IFrame then
3088 // there will not be a selection so we want the entire page to print
3090 // XXX this is sort of a hack right here to make the page
3091 // not try to reposition itself when printing selection
3092 nsCOMPtr<nsIDOMWindow> domWin =
3093 do_QueryInterface(po->mDocument->GetOriginalDocument()->GetWindow());
3094 if (!IsThereARangeSelection(domWin)) {
3095 printRangeType = nsIPrintSettings::kRangeAllPages;
3096 mPrt->mPrintSettings->SetPrintRange(printRangeType);
3098 PR_PL(("PrintFrameType: %s \n", gPrintFrameTypeStr[mPrt->mPrintFrameType]));
3099 PR_PL(("HowToEnableFrameUI: %s \n", gFrameHowToEnableStr[printHowEnable]));
3100 PR_PL(("PrintRange: %s \n", gPrintRangeStr[printRangeType]));
3101 return NS_OK;
3106 // If we are printing "AsIs" then sets all the POs to be printed as is
3107 if (mPrt->mPrintFrameType == nsIPrintSettings::kFramesAsIs) {
3108 SetPrintAsIs(mPrt->mPrintObject);
3109 SetPrintPO(mPrt->mPrintObject, PR_TRUE);
3110 return NS_OK;
3113 // If we are printing the selected Frame then
3114 // find that PO for that selected DOMWin and set it all of its
3115 // children to be printed
3116 if (mPrt->mPrintFrameType == nsIPrintSettings::kSelectedFrame) {
3118 if ((mPrt->mIsParentAFrameSet && mPrt->mCurrentFocusWin) || mPrt->mIsIFrameSelected) {
3119 nsPrintObject * po = FindPrintObjectByDOMWin(mPrt->mPrintObject, mPrt->mCurrentFocusWin);
3120 if (po != nsnull) {
3121 mPrt->mSelectedPO = po;
3122 // NOTE: Calling this sets the "po" and
3123 // we don't want to do this for documents that have no children,
3124 // because then the "DoEndPage" gets called and it shouldn't
3125 if (po->mKids.Length() > 0) {
3126 // Makes sure that itself, and all of its children are printed "AsIs"
3127 SetPrintAsIs(po);
3130 // Now, only enable this POs (the selected PO) and all of its children
3131 SetPrintPO(po, PR_TRUE);
3134 return NS_OK;
3137 // If we are print each subdoc separately,
3138 // then don't print any of the FraneSet Docs
3139 if (mPrt->mPrintFrameType == nsIPrintSettings::kEachFrameSep) {
3140 SetPrintPO(mPrt->mPrintObject, PR_TRUE);
3141 PRInt32 cnt = mPrt->mPrintDocList.Length();
3142 for (PRInt32 i=0;i<cnt;i++) {
3143 nsPrintObject* po = mPrt->mPrintDocList.ElementAt(i);
3144 NS_ASSERTION(po, "nsPrintObject can't be null!");
3145 if (po->mFrameType == eFrameSet) {
3146 po->mDontPrint = PR_TRUE;
3151 return NS_OK;
3154 //-------------------------------------------------------
3155 // Return the nsPrintObject with that is XMost (The widest frameset frame) AND
3156 // contains the XMost (widest) layout frame
3157 nsPrintObject*
3158 nsPrintEngine::FindSmallestSTF()
3160 float smallestRatio = 1.0f;
3161 nsPrintObject* smallestPO = nsnull;
3163 for (PRUint32 i=0;i<mPrt->mPrintDocList.Length();i++) {
3164 nsPrintObject* po = mPrt->mPrintDocList.ElementAt(i);
3165 NS_ASSERTION(po, "nsPrintObject can't be null!");
3166 if (po->mFrameType != eFrameSet && po->mFrameType != eIFrame) {
3167 if (po->mShrinkRatio < smallestRatio) {
3168 smallestRatio = po->mShrinkRatio;
3169 smallestPO = po;
3174 #ifdef EXTENDED_DEBUG_PRINTING
3175 if (smallestPO) printf("*PO: %p Type: %d %10.3f\n", smallestPO, smallestPO->mFrameType, smallestPO->mShrinkRatio);
3176 #endif
3177 return smallestPO;
3180 //-------------------------------------------------------
3181 void
3182 nsPrintEngine::TurnScriptingOn(PRBool aDoTurnOn)
3184 if (mIsDoingPrinting && aDoTurnOn && mDocViewerPrint &&
3185 mDocViewerPrint->GetIsPrintPreview()) {
3186 // We don't want to turn scripting on if print preview is shown still after
3187 // printing.
3188 return;
3191 nsPrintData* prt = mPrt;
3192 #ifdef NS_PRINT_PREVIEW
3193 if (!prt) {
3194 prt = mPrtPreview;
3196 #endif
3197 if (!prt) {
3198 return;
3201 NS_ASSERTION(mDocument, "We MUST have a document.");
3202 // First, get the script global object from the document...
3204 for (PRUint32 i=0;i<prt->mPrintDocList.Length();i++) {
3205 nsPrintObject* po = prt->mPrintDocList.ElementAt(i);
3206 NS_ASSERTION(po, "nsPrintObject can't be null!");
3208 nsIDocument* doc = po->mDocument;
3209 if (!doc) {
3210 continue;
3213 // get the script global object
3214 nsIScriptGlobalObject *scriptGlobalObj = doc->GetScriptGlobalObject();
3216 if (scriptGlobalObj) {
3217 nsCOMPtr<nsPIDOMWindow> window = do_QueryInterface(scriptGlobalObj);
3218 NS_ASSERTION(window, "Can't get nsPIDOMWindow");
3219 nsIScriptContext *scx = scriptGlobalObj->GetContext();
3220 NS_WARN_IF_FALSE(scx, "Can't get nsIScriptContext");
3221 nsresult propThere = NS_PROPTABLE_PROP_NOT_THERE;
3222 doc->GetProperty(nsGkAtoms::scriptEnabledBeforePrintOrPreview,
3223 &propThere);
3224 if (aDoTurnOn) {
3225 if (propThere != NS_PROPTABLE_PROP_NOT_THERE) {
3226 doc->DeleteProperty(nsGkAtoms::scriptEnabledBeforePrintOrPreview);
3227 if (scx) {
3228 scx->SetScriptsEnabled(PR_TRUE, PR_FALSE);
3230 window->ResumeTimeouts(PR_FALSE);
3232 } else {
3233 // Have to be careful, because people call us over and over again with
3234 // aDoTurnOn == PR_FALSE. So don't set the property if it's already
3235 // set, since in that case we'd set it to the wrong value.
3236 if (propThere == NS_PROPTABLE_PROP_NOT_THERE) {
3237 // Stash the current value of IsScriptEnabled on the document, so
3238 // that layout code running in print preview doesn't get confused.
3239 doc->SetProperty(nsGkAtoms::scriptEnabledBeforePrintOrPreview,
3240 NS_INT32_TO_PTR(doc->IsScriptEnabled()));
3241 if (scx) {
3242 scx->SetScriptsEnabled(PR_FALSE, PR_FALSE);
3244 window->SuspendTimeouts(1, PR_FALSE);
3251 //-----------------------------------------------------------------
3252 //-- Done: Misc Support Methods
3253 //-----------------------------------------------------------------
3256 //-----------------------------------------------------------------
3257 //-- Section: Finishing up or Cleaning up
3258 //-----------------------------------------------------------------
3260 //-----------------------------------------------------------------
3261 void
3262 nsPrintEngine::CloseProgressDialog(nsIWebProgressListener* aWebProgressListener)
3264 if (aWebProgressListener) {
3265 aWebProgressListener->OnStateChange(nsnull, nsnull, nsIWebProgressListener::STATE_STOP|nsIWebProgressListener::STATE_IS_DOCUMENT, nsnull);
3269 //-----------------------------------------------------------------
3270 nsresult
3271 nsPrintEngine::FinishPrintPreview()
3273 nsresult rv = NS_OK;
3275 #ifdef NS_PRINT_PREVIEW
3277 if (!mPrt) {
3278 /* we're already finished with print preview */
3279 return rv;
3282 rv = DocumentReadyForPrinting();
3284 SetIsCreatingPrintPreview(PR_FALSE);
3286 /* cleaup on failure + notify user */
3287 if (NS_FAILED(rv)) {
3288 /* cleanup done, let's fire-up an error dialog to notify the user
3289 * what went wrong...
3291 mPrt->OnEndPrinting();
3292 TurnScriptingOn(PR_TRUE);
3294 return rv;
3297 // At this point we are done preparing everything
3298 // before it is to be created
3301 if (mIsDoingPrintPreview && mOldPrtPreview) {
3302 delete mOldPrtPreview;
3303 mOldPrtPreview = nsnull;
3306 InstallPrintPreviewListener();
3308 mPrt->OnEndPrinting();
3310 // PrintPreview was built using the mPrt (code reuse)
3311 // then we assign it over
3312 mPrtPreview = mPrt;
3313 mPrt = nsnull;
3315 #endif // NS_PRINT_PREVIEW
3317 return NS_OK;
3320 //-----------------------------------------------------------------
3321 //-- Done: Finishing up or Cleaning up
3322 //-----------------------------------------------------------------
3325 /*=============== Timer Related Code ======================*/
3326 nsresult
3327 nsPrintEngine::StartPagePrintTimer(nsPrintObject* aPO)
3329 if (!mPagePrintTimer) {
3330 nsresult rv = NS_NewPagePrintTimer(&mPagePrintTimer);
3331 NS_ENSURE_SUCCESS(rv, rv);
3333 // Get the delay time in between the printing of each page
3334 // this gives the user more time to press cancel
3335 PRInt32 printPageDelay = 50;
3336 mPrt->mPrintSettings->GetPrintPageDelay(&printPageDelay);
3338 mPagePrintTimer->Init(this, mDocViewerPrint, printPageDelay);
3341 return mPagePrintTimer->Start(aPO);
3344 /*=============== nsIObserver Interface ======================*/
3345 NS_IMETHODIMP
3346 nsPrintEngine::Observe(nsISupports *aSubject, const char *aTopic, const PRUnichar *aData)
3348 nsresult rv = NS_ERROR_FAILURE;
3350 if (mIsDoingPrinting) {
3351 rv = DocumentReadyForPrinting();
3353 /* cleaup on failure + notify user */
3354 if (NS_FAILED(rv)) {
3355 CleanupOnFailure(rv, PR_TRUE);
3357 } else {
3358 rv = FinishPrintPreview();
3359 if (NS_FAILED(rv)) {
3360 CleanupOnFailure(rv, PR_FALSE);
3362 if (mPrtPreview) {
3363 mPrtPreview->OnEndPrinting();
3365 rv = NS_OK;
3368 return rv;
3372 //---------------------------------------------------------------
3373 //-- PLEvent Notification
3374 //---------------------------------------------------------------
3375 class nsPrintCompletionEvent : public nsRunnable {
3376 public:
3377 nsPrintCompletionEvent(nsIDocumentViewerPrint *docViewerPrint)
3378 : mDocViewerPrint(docViewerPrint) {
3379 NS_ASSERTION(mDocViewerPrint, "mDocViewerPrint is null.");
3382 NS_IMETHOD Run() {
3383 if (mDocViewerPrint)
3384 mDocViewerPrint->OnDonePrinting();
3385 return NS_OK;
3388 private:
3389 nsCOMPtr<nsIDocumentViewerPrint> mDocViewerPrint;
3392 //-----------------------------------------------------------
3393 void
3394 nsPrintEngine::FirePrintCompletionEvent()
3396 nsCOMPtr<nsIRunnable> event = new nsPrintCompletionEvent(mDocViewerPrint);
3397 if (NS_FAILED(NS_DispatchToCurrentThread(event)))
3398 NS_WARNING("failed to dispatch print completion event");
3401 //---------------------------------------------------------------
3402 //---------------------------------------------------------------
3403 //-- Debug helper routines
3404 //---------------------------------------------------------------
3405 //---------------------------------------------------------------
3406 #if (defined(XP_WIN) || defined(XP_OS2)) && defined(EXTENDED_DEBUG_PRINTING)
3407 #include "windows.h"
3408 #include "process.h"
3409 #include "direct.h"
3411 #define MY_FINDFIRST(a,b) FindFirstFile(a,b)
3412 #define MY_FINDNEXT(a,b) FindNextFile(a,b)
3413 #define ISDIR(a) (a.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
3414 #define MY_FINDCLOSE(a) FindClose(a)
3415 #define MY_FILENAME(a) a.cFileName
3416 #define MY_FILESIZE(a) (a.nFileSizeHigh * MAXDWORD) + a.nFileSizeLow
3418 int RemoveFilesInDir(const char * aDir)
3420 WIN32_FIND_DATA data_ptr;
3421 HANDLE find_handle;
3423 char path[MAX_PATH];
3425 strcpy(path, aDir);
3427 // Append slash to the end of the directory names if not there
3428 if (path[strlen(path)-1] != '\\')
3429 strcat(path, "\\");
3431 char findPath[MAX_PATH];
3432 strcpy(findPath, path);
3433 strcat(findPath, "*.*");
3435 find_handle = MY_FINDFIRST(findPath, &data_ptr);
3437 if (find_handle != INVALID_HANDLE_VALUE) {
3438 do {
3439 if (ISDIR(data_ptr)
3440 && (stricmp(MY_FILENAME(data_ptr),"."))
3441 && (stricmp(MY_FILENAME(data_ptr),".."))) {
3442 // skip
3444 else if (!ISDIR(data_ptr)) {
3445 if (!strncmp(MY_FILENAME(data_ptr), "print_dump", 10)) {
3446 char fileName[MAX_PATH];
3447 strcpy(fileName, aDir);
3448 strcat(fileName, "\\");
3449 strcat(fileName, MY_FILENAME(data_ptr));
3450 printf("Removing %s\n", fileName);
3451 remove(fileName);
3454 } while(MY_FINDNEXT(find_handle,&data_ptr));
3455 MY_FINDCLOSE(find_handle);
3457 return TRUE;
3459 #endif
3461 #ifdef EXTENDED_DEBUG_PRINTING
3463 /** ---------------------------------------------------
3464 * Dumps Frames for Printing
3466 static void RootFrameList(nsPresContext* aPresContext, FILE* out, PRInt32 aIndent)
3468 if (!aPresContext || !out)
3469 return;
3471 nsIPresShell *shell = aPresContext->GetPresShell();
3472 if (shell) {
3473 nsIFrame* frame = shell->FrameManager()->GetRootFrame();
3474 if (frame) {
3475 frame->List(aPresContext, out, aIndent);
3480 /** ---------------------------------------------------
3481 * Dumps Frames for Printing
3483 static void DumpFrames(FILE* out,
3484 nsPresContext* aPresContext,
3485 nsIRenderingContext * aRendContext,
3486 nsIFrame * aFrame,
3487 PRInt32 aLevel)
3489 NS_ASSERTION(out, "Pointer is null!");
3490 NS_ASSERTION(aPresContext, "Pointer is null!");
3491 NS_ASSERTION(aRendContext, "Pointer is null!");
3492 NS_ASSERTION(aFrame, "Pointer is null!");
3494 nsIFrame* child = aFrame->GetFirstChild(nsnull);
3495 while (child != nsnull) {
3496 for (PRInt32 i=0;i<aLevel;i++) {
3497 fprintf(out, " ");
3499 nsAutoString tmp;
3500 child->GetFrameName(tmp);
3501 fputs(NS_LossyConvertUTF16toASCII(tmp).get(), out);
3502 PRBool isSelected;
3503 if (NS_SUCCEEDED(child->IsVisibleForPainting(aPresContext, *aRendContext, PR_TRUE, &isSelected))) {
3504 fprintf(out, " %p %s", child, isSelected?"VIS":"UVS");
3505 nsRect rect = child->GetRect();
3506 fprintf(out, "[%d,%d,%d,%d] ", rect.x, rect.y, rect.width, rect.height);
3507 fprintf(out, "v: %p ", (void*)child->GetView());
3508 fprintf(out, "\n");
3509 DumpFrames(out, aPresContext, aRendContext, child, aLevel+1);
3510 child = child->GetNextSibling();
3516 /** ---------------------------------------------------
3517 * Dumps the Views from the DocShell
3519 static void
3520 DumpViews(nsIDocShell* aDocShell, FILE* out)
3522 NS_ASSERTION(aDocShell, "Pointer is null!");
3523 NS_ASSERTION(out, "Pointer is null!");
3525 if (nsnull != aDocShell) {
3526 fprintf(out, "docshell=%p \n", aDocShell);
3527 nsIPresShell* shell = nsPrintEngine::GetPresShellFor(aDocShell);
3528 if (shell) {
3529 nsIViewManager* vm = shell->GetViewManager();
3530 if (vm) {
3531 nsIView* root;
3532 vm->GetRootView(root);
3533 if (nsnull != root) {
3534 root->List(out);
3538 else {
3539 fputs("null pres shell\n", out);
3542 // dump the views of the sub documents
3543 PRInt32 i, n;
3544 nsCOMPtr<nsIDocShellTreeNode> docShellAsNode(do_QueryInterface(aDocShell));
3545 docShellAsNode->GetChildCount(&n);
3546 for (i = 0; i < n; i++) {
3547 nsCOMPtr<nsIDocShellTreeItem> child;
3548 docShellAsNode->GetChildAt(i, getter_AddRefs(child));
3549 nsCOMPtr<nsIDocShell> childAsShell(do_QueryInterface(child));
3550 if (childAsShell) {
3551 DumpViews(childAsShell, out);
3557 /** ---------------------------------------------------
3558 * Dumps the Views and Frames
3560 void DumpLayoutData(char* aTitleStr,
3561 char* aURLStr,
3562 nsPresContext* aPresContext,
3563 nsIDeviceContext * aDC,
3564 nsIFrame * aRootFrame,
3565 nsIDocShekk * aDocShell,
3566 FILE* aFD = nsnull)
3568 if (!kPrintingLogMod || kPrintingLogMod->level != DUMP_LAYOUT_LEVEL) return;
3570 if (aPresContext == nsnull || aDC == nsnull) {
3571 return;
3574 #ifdef NS_PRINT_PREVIEW
3575 if (aPresContext->Type() == nsPresContext::eContext_PrintPreview) {
3576 return;
3578 #endif
3580 NS_ASSERTION(aRootFrame, "Pointer is null!");
3581 NS_ASSERTION(aDocShell, "Pointer is null!");
3583 // Dump all the frames and view to a a file
3584 char filename[256];
3585 sprintf(filename, "print_dump_layout_%d.txt", gDumpLOFileNameCnt++);
3586 FILE * fd = aFD?aFD:fopen(filename, "w");
3587 if (fd) {
3588 fprintf(fd, "Title: %s\n", aTitleStr?aTitleStr:"");
3589 fprintf(fd, "URL: %s\n", aURLStr?aURLStr:"");
3590 fprintf(fd, "--------------- Frames ----------------\n");
3591 fprintf(fd, "--------------- Frames ----------------\n");
3592 nsCOMPtr<nsIRenderingContext> renderingContext;
3593 aDC->CreateRenderingContext(*getter_AddRefs(renderingContext));
3594 RootFrameList(aPresContext, fd, 0);
3595 //DumpFrames(fd, aPresContext, renderingContext, aRootFrame, 0);
3596 fprintf(fd, "---------------------------------------\n\n");
3597 fprintf(fd, "--------------- Views From Root Frame----------------\n");
3598 nsIView* v = aRootFrame->GetView();
3599 if (v) {
3600 v->List(fd);
3601 } else {
3602 printf("View is null!\n");
3604 if (aDocShell) {
3605 fprintf(fd, "--------------- All Views ----------------\n");
3606 DumpViews(aDocShell, fd);
3607 fprintf(fd, "---------------------------------------\n\n");
3609 if (aFD == nsnull) {
3610 fclose(fd);
3615 //-------------------------------------------------------------
3616 static void DumpPrintObjectsList(nsTArray<nsPrintObject*> * aDocList)
3618 if (!kPrintingLogMod || kPrintingLogMod->level != DUMP_LAYOUT_LEVEL) return;
3620 NS_ASSERTION(aDocList, "Pointer is null!");
3622 const char types[][3] = {"DC", "FR", "IF", "FS"};
3623 PR_PL(("Doc List\n***************************************************\n"));
3624 PR_PL(("T P A H PO DocShell Seq Page Root Page# Rect\n"));
3625 PRInt32 cnt = aDocList->Length();
3626 for (PRInt32 i=0;i<cnt;i++) {
3627 nsPrintObject* po = aDocList->ElementAt(i);
3628 NS_ASSERTION(po, "nsPrintObject can't be null!");
3629 nsIFrame* rootFrame = nsnull;
3630 if (po->mPresShell) {
3631 rootFrame = po->mPresShell->FrameManager()->GetRootFrame();
3632 while (rootFrame != nsnull) {
3633 nsIPageSequenceFrame * sqf = do_QueryFrame(rootFrame);
3634 if (sqf) {
3635 break;
3637 rootFrame = rootFrame->GetFirstChild(nsnull);
3641 PR_PL(("%s %d %d %d %p %p %p %p %p %d %d,%d,%d,%d\n", types[po->mFrameType],
3642 po->IsPrintable(), po->mPrintAsIs, po->mHasBeenPrinted, po, po->mDocShell.get(), po->mSeqFrame,
3643 po->mPageFrame, rootFrame, po->mPageNum, po->mRect.x, po->mRect.y, po->mRect.width, po->mRect.height));
3647 //-------------------------------------------------------------
3648 static void DumpPrintObjectsTree(nsPrintObject * aPO, int aLevel, FILE* aFD)
3650 if (!kPrintingLogMod || kPrintingLogMod->level != DUMP_LAYOUT_LEVEL) return;
3652 NS_ASSERTION(aPO, "Pointer is null!");
3654 FILE * fd = aFD?aFD:stdout;
3655 const char types[][3] = {"DC", "FR", "IF", "FS"};
3656 if (aLevel == 0) {
3657 fprintf(fd, "DocTree\n***************************************************\n");
3658 fprintf(fd, "T PO DocShell Seq Page Page# Rect\n");
3660 PRInt32 cnt = aPO->mKids.Length();
3661 for (PRInt32 i=0;i<cnt;i++) {
3662 nsPrintObject* po = aPO->mKids.ElementAt(i);
3663 NS_ASSERTION(po, "nsPrintObject can't be null!");
3664 for (PRInt32 k=0;k<aLevel;k++) fprintf(fd, " ");
3665 fprintf(fd, "%s %p %p %p %p %d %d,%d,%d,%d\n", types[po->mFrameType], po, po->mDocShell.get(), po->mSeqFrame,
3666 po->mPageFrame, po->mPageNum, po->mRect.x, po->mRect.y, po->mRect.width, po->mRect.height);
3670 //-------------------------------------------------------------
3671 static void GetDocTitleAndURL(nsPrintObject* aPO, char *& aDocStr, char *& aURLStr)
3673 aDocStr = nsnull;
3674 aURLStr = nsnull;
3676 PRUnichar * docTitleStr;
3677 PRUnichar * docURLStr;
3678 nsPrintEngine::GetDisplayTitleAndURL(aPO,
3679 &docTitleStr, &docURLStr,
3680 nsPrintEngine::eDocTitleDefURLDoc);
3682 if (docTitleStr) {
3683 nsAutoString strDocTitle(docTitleStr);
3684 aDocStr = ToNewCString(strDocTitle);
3685 nsMemory::Free(docTitleStr);
3688 if (docURLStr) {
3689 nsAutoString strURL(docURLStr);
3690 aURLStr = ToNewCString(strURL);
3691 nsMemory::Free(docURLStr);
3695 //-------------------------------------------------------------
3696 static void DumpPrintObjectsTreeLayout(nsPrintObject * aPO,
3697 nsIDeviceContext * aDC,
3698 int aLevel, FILE * aFD)
3700 if (!kPrintingLogMod || kPrintingLogMod->level != DUMP_LAYOUT_LEVEL) return;
3702 NS_ASSERTION(aPO, "Pointer is null!");
3703 NS_ASSERTION(aDC, "Pointer is null!");
3705 const char types[][3] = {"DC", "FR", "IF", "FS"};
3706 FILE * fd = nsnull;
3707 if (aLevel == 0) {
3708 fd = fopen("tree_layout.txt", "w");
3709 fprintf(fd, "DocTree\n***************************************************\n");
3710 fprintf(fd, "***************************************************\n");
3711 fprintf(fd, "T PO DocShell Seq Page Page# Rect\n");
3712 } else {
3713 fd = aFD;
3715 if (fd) {
3716 nsIFrame* rootFrame = nsnull;
3717 if (aPO->mPresShell) {
3718 rootFrame = aPO->mPresShell->FrameManager()->GetRootFrame();
3720 for (PRInt32 k=0;k<aLevel;k++) fprintf(fd, " ");
3721 fprintf(fd, "%s %p %p %p %p %d %d,%d,%d,%d\n", types[aPO->mFrameType], aPO, aPO->mDocShell.get(), aPO->mSeqFrame,
3722 aPO->mPageFrame, aPO->mPageNum, aPO->mRect.x, aPO->mRect.y, aPO->mRect.width, aPO->mRect.height);
3723 if (aPO->IsPrintable()) {
3724 char * docStr;
3725 char * urlStr;
3726 GetDocTitleAndURL(aPO, docStr, urlStr);
3727 DumpLayoutData(docStr, urlStr, aPO->mPresContext, aDC, rootFrame, aPO->mDocShell, fd);
3728 if (docStr) nsMemory::Free(docStr);
3729 if (urlStr) nsMemory::Free(urlStr);
3731 fprintf(fd, "<***************************************************>\n");
3733 PRInt32 cnt = aPO->mKids.Length();
3734 for (PRInt32 i=0;i<cnt;i++) {
3735 nsPrintObject* po = aPO->mKids.ElementAt(i);
3736 NS_ASSERTION(po, "nsPrintObject can't be null!");
3737 DumpPrintObjectsTreeLayout(po, aDC, aLevel+1, fd);
3740 if (aLevel == 0 && fd) {
3741 fclose(fd);
3745 //-------------------------------------------------------------
3746 static void DumpPrintObjectsListStart(const char * aStr, nsTArray<nsPrintObject*> * aDocList)
3748 if (!kPrintingLogMod || kPrintingLogMod->level != DUMP_LAYOUT_LEVEL) return;
3750 NS_ASSERTION(aStr, "Pointer is null!");
3751 NS_ASSERTION(aDocList, "Pointer is null!");
3753 PR_PL(("%s\n", aStr));
3754 DumpPrintObjectsList(aDocList);
3757 #define DUMP_DOC_LIST(_title) DumpPrintObjectsListStart((_title), mPrt->mPrintDocList);
3758 #define DUMP_DOC_TREE DumpPrintObjectsTree(mPrt->mPrintObject);
3759 #define DUMP_DOC_TREELAYOUT DumpPrintObjectsTreeLayout(mPrt->mPrintObject, mPrt->mPrintDC);
3761 #else
3762 #define DUMP_DOC_LIST(_title)
3763 #define DUMP_DOC_TREE
3764 #define DUMP_DOC_TREELAYOUT
3765 #endif
3767 //---------------------------------------------------------------
3768 //---------------------------------------------------------------
3769 //-- End of debug helper routines
3770 //---------------------------------------------------------------