Back out changeset fecc8ed9e813.
[mozilla-central.git] / layout / printing / nsPrintEngine.cpp
blob8c1cbec16d39323a9ae1bc899ba163033610a917
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 "nsIDocumentViewerPrint.h"
160 #include "nsPIDOMWindow.h"
161 #include "nsFocusManager.h"
162 #include "nsRange.h"
163 #include "nsCDefaultURIFixup.h"
164 #include "nsIURIFixup.h"
165 #include "mozilla/dom/Element.h"
167 using namespace mozilla::dom;
169 //-----------------------------------------------------
170 // PR LOGGING
171 #ifdef MOZ_LOGGING
172 #define FORCE_PR_LOG /* Allow logging in the release build */
173 #endif
175 #include "prlog.h"
177 #ifdef PR_LOGGING
179 #ifdef NS_DEBUG
180 // PR_LOGGING is force to always be on (even in release builds)
181 // but we only want some of it on,
182 //#define EXTENDED_DEBUG_PRINTING
183 #endif
185 #define DUMP_LAYOUT_LEVEL 9 // this turns on the dumping of each doucment's layout info
187 static PRLogModuleInfo * kPrintingLogMod = PR_NewLogModule("printing");
188 #define PR_PL(_p1) PR_LOG(kPrintingLogMod, PR_LOG_DEBUG, _p1);
190 #ifdef EXTENDED_DEBUG_PRINTING
191 static PRUint32 gDumpFileNameCnt = 0;
192 static PRUint32 gDumpLOFileNameCnt = 0;
193 #endif
195 #define PRT_YESNO(_p) ((_p)?"YES":"NO")
196 static const char * gFrameTypesStr[] = {"eDoc", "eFrame", "eIFrame", "eFrameSet"};
197 static const char * gPrintFrameTypeStr[] = {"kNoFrames", "kFramesAsIs", "kSelectedFrame", "kEachFrameSep"};
198 static const char * gFrameHowToEnableStr[] = {"kFrameEnableNone", "kFrameEnableAll", "kFrameEnableAsIsAndEach"};
199 static const char * gPrintRangeStr[] = {"kRangeAllPages", "kRangeSpecifiedPageRange", "kRangeSelection", "kRangeFocusFrame"};
200 #else
201 #define PRT_YESNO(_p)
202 #define PR_PL(_p1)
203 #endif
205 #ifdef EXTENDED_DEBUG_PRINTING
206 // Forward Declarations
207 static void DumpPrintObjectsListStart(const char * aStr, nsTArray<nsPrintObject*> * aDocList);
208 static void DumpPrintObjectsTree(nsPrintObject * aPO, int aLevel= 0, FILE* aFD = nsnull);
209 static void DumpPrintObjectsTreeLayout(nsPrintObject * aPO,nsIDeviceContext * aDC, int aLevel= 0, FILE * aFD = nsnull);
211 #define DUMP_DOC_LIST(_title) DumpPrintObjectsListStart((_title), mPrt->mPrintDocList);
212 #define DUMP_DOC_TREE DumpPrintObjectsTree(mPrt->mPrintObject);
213 #define DUMP_DOC_TREELAYOUT DumpPrintObjectsTreeLayout(mPrt->mPrintObject, mPrt->mPrintDC);
214 #else
215 #define DUMP_DOC_LIST(_title)
216 #define DUMP_DOC_TREE
217 #define DUMP_DOC_TREELAYOUT
218 #endif
220 class nsScriptSuppressor
222 public:
223 nsScriptSuppressor(nsPrintEngine* aPrintEngine)
224 : mPrintEngine(aPrintEngine), mSuppressed(PR_FALSE) {}
226 ~nsScriptSuppressor() { Unsuppress(); }
228 void Suppress()
230 if (mPrintEngine) {
231 mSuppressed = PR_TRUE;
232 mPrintEngine->TurnScriptingOn(PR_FALSE);
236 void Unsuppress()
238 if (mPrintEngine && mSuppressed) {
239 mPrintEngine->TurnScriptingOn(PR_TRUE);
241 mSuppressed = PR_FALSE;
244 void Disconnect() { mPrintEngine = nsnull; }
245 protected:
246 nsRefPtr<nsPrintEngine> mPrintEngine;
247 PRBool mSuppressed;
250 // Class IDs
251 static NS_DEFINE_CID(kViewManagerCID, NS_VIEW_MANAGER_CID);
252 static NS_DEFINE_CID(kWidgetCID, NS_CHILD_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 mParentWidget(nsnull),
270 mPrtPreview(nsnull),
271 mOldPrtPreview(nsnull),
272 mDebugFile(nsnull)
276 //-------------------------------------------------------
277 nsPrintEngine::~nsPrintEngine()
279 Destroy(); // for insurance
282 //-------------------------------------------------------
283 void nsPrintEngine::Destroy()
285 if (mPrt) {
286 delete mPrt;
287 mPrt = nsnull;
290 #ifdef NS_PRINT_PREVIEW
291 if (mPrtPreview) {
292 delete mPrtPreview;
293 mPrtPreview = nsnull;
296 // This is insruance
297 if (mOldPrtPreview) {
298 delete mOldPrtPreview;
299 mOldPrtPreview = nsnull;
302 #endif
303 mDocViewerPrint = nsnull;
306 //-------------------------------------------------------
307 void nsPrintEngine::DestroyPrintingData()
309 if (mPrt) {
310 delete mPrt;
311 mPrt = nsnull;
315 //---------------------------------------------------------------------------------
316 //-- Section: Methods needed by the DocViewer
317 //---------------------------------------------------------------------------------
319 //--------------------------------------------------------
320 nsresult nsPrintEngine::Initialize(nsIDocumentViewerPrint* aDocViewerPrint,
321 nsISupports* aContainer,
322 nsIDocument* aDocument,
323 float aScreenDPI,
324 nsIWidget* aParentWidget,
325 FILE* aDebugFile)
327 NS_ENSURE_ARG_POINTER(aDocViewerPrint);
328 NS_ENSURE_ARG_POINTER(aContainer);
329 NS_ENSURE_ARG_POINTER(aDocument);
331 mDocViewerPrint = aDocViewerPrint;
332 mContainer = aContainer; // weak reference
333 mDocument = aDocument;
334 mScreenDPI = aScreenDPI;
335 mParentWidget = aParentWidget;
337 mDebugFile = aDebugFile; // ok to be NULL
339 return NS_OK;
342 //-------------------------------------------------------
343 PRBool
344 nsPrintEngine::CheckBeforeDestroy()
346 if (mPrt && mPrt->mPreparingForPrint) {
347 mPrt->mDocWasToBeDestroyed = PR_TRUE;
348 return PR_TRUE;
350 return PR_FALSE;
353 //-------------------------------------------------------
354 nsresult
355 nsPrintEngine::Cancelled()
357 if (mPrt && mPrt->mPrintSettings) {
358 return mPrt->mPrintSettings->SetIsCancelled(PR_TRUE);
360 return NS_ERROR_FAILURE;
363 //-------------------------------------------------------
364 // Install our event listeners on the document to prevent
365 // some events from being processed while in PrintPreview
367 // No return code - if this fails, there isn't much we can do
368 void
369 nsPrintEngine::InstallPrintPreviewListener()
371 if (!mPrt->mPPEventListeners) {
372 nsCOMPtr<nsPIDOMWindow> win(do_GetInterface(mContainer));
373 nsCOMPtr<nsIDOMEventTarget> target(do_QueryInterface(win->GetFrameElementInternal()));
374 mPrt->mPPEventListeners = new nsPrintPreviewListener(target);
376 if (mPrt->mPPEventListeners) {
377 mPrt->mPPEventListeners->AddListeners();
382 //----------------------------------------------------------------------
383 nsresult
384 nsPrintEngine::GetSeqFrameAndCountPagesInternal(nsPrintObject* aPO,
385 nsIFrame*& aSeqFrame,
386 PRInt32& aCount)
388 NS_ENSURE_ARG_POINTER(aPO);
390 // Finds the SimplePageSequencer frame
391 nsIPageSequenceFrame* seqFrame = aPO->mPresShell->GetPageSequenceFrame();
392 if (seqFrame) {
393 aSeqFrame = do_QueryFrame(seqFrame);
394 } else {
395 aSeqFrame = nsnull;
397 if (aSeqFrame == nsnull) return NS_ERROR_FAILURE;
399 // first count the total number of pages
400 aCount = 0;
401 nsIFrame* pageFrame = aSeqFrame->GetFirstChild(nsnull);
402 while (pageFrame != nsnull) {
403 aCount++;
404 pageFrame = pageFrame->GetNextSibling();
407 return NS_OK;
411 //-----------------------------------------------------------------
412 nsresult nsPrintEngine::GetSeqFrameAndCountPages(nsIFrame*& aSeqFrame, PRInt32& aCount)
414 NS_ASSERTION(mPrtPreview, "mPrtPreview can't be null!");
415 return GetSeqFrameAndCountPagesInternal(mPrtPreview->mPrintObject, aSeqFrame, aCount);
417 //---------------------------------------------------------------------------------
418 //-- Done: Methods needed by the DocViewer
419 //---------------------------------------------------------------------------------
422 //---------------------------------------------------------------------------------
423 //-- Section: nsIWebBrowserPrint
424 //---------------------------------------------------------------------------------
426 // Foward decl for Debug Helper Functions
427 #ifdef EXTENDED_DEBUG_PRINTING
428 static int RemoveFilesInDir(const char * aDir);
429 static void GetDocTitleAndURL(nsPrintObject* aPO, char *& aDocStr, char *& aURLStr);
430 static void DumpPrintObjectsTree(nsPrintObject * aPO, int aLevel, FILE* aFD);
431 static void DumpPrintObjectsList(nsTArray<nsPrintObject*> * aDocList);
432 static void RootFrameList(nsPresContext* aPresContext, FILE* out, PRInt32 aIndent);
433 static void DumpViews(nsIDocShell* aDocShell, FILE* out);
434 static void DumpLayoutData(char* aTitleStr, char* aURLStr,
435 nsPresContext* aPresContext,
436 nsIDeviceContext * aDC, nsIFrame * aRootFrame,
437 nsIDocShell * aDocShell, FILE* aFD);
438 #endif
440 //--------------------------------------------------------------------------------
442 nsresult
443 nsPrintEngine::CommonPrint(PRBool aIsPrintPreview,
444 nsIPrintSettings* aPrintSettings,
445 nsIWebProgressListener* aWebProgressListener,
446 nsIDOMDocument* aDoc) {
447 nsresult rv = DoCommonPrint(aIsPrintPreview, aPrintSettings,
448 aWebProgressListener, aDoc);
449 if (NS_FAILED(rv)) {
450 if (aIsPrintPreview) {
451 SetIsCreatingPrintPreview(PR_FALSE);
452 SetIsPrintPreview(PR_FALSE);
453 } else {
454 SetIsPrinting(PR_FALSE);
456 if (mProgressDialogIsShown)
457 CloseProgressDialog(aWebProgressListener);
458 if (rv != NS_ERROR_ABORT && rv != NS_ERROR_OUT_OF_MEMORY)
459 ShowPrintErrorDialog(rv, !aIsPrintPreview);
460 delete mPrt;
461 mPrt = nsnull;
464 return rv;
467 nsresult
468 nsPrintEngine::DoCommonPrint(PRBool aIsPrintPreview,
469 nsIPrintSettings* aPrintSettings,
470 nsIWebProgressListener* aWebProgressListener,
471 nsIDOMDocument* aDoc)
473 nsresult rv;
475 if (aIsPrintPreview) {
476 // The WebProgressListener can be QI'ed to nsIPrintingPromptService
477 // then that means the progress dialog is already being shown.
478 nsCOMPtr<nsIPrintingPromptService> pps(do_QueryInterface(aWebProgressListener));
479 mProgressDialogIsShown = pps != nsnull;
481 if (mIsDoingPrintPreview) {
482 mOldPrtPreview = mPrtPreview;
483 mPrtPreview = nsnull;
485 } else {
486 mProgressDialogIsShown = PR_FALSE;
489 mPrt = new nsPrintData(aIsPrintPreview ? nsPrintData::eIsPrintPreview :
490 nsPrintData::eIsPrinting);
491 NS_ENSURE_TRUE(mPrt, NS_ERROR_OUT_OF_MEMORY);
493 // if they don't pass in a PrintSettings, then get the Global PS
494 mPrt->mPrintSettings = aPrintSettings;
495 if (!mPrt->mPrintSettings) {
496 rv = GetGlobalPrintSettings(getter_AddRefs(mPrt->mPrintSettings));
497 NS_ENSURE_SUCCESS(rv, rv);
500 rv = CheckForPrinters(mPrt->mPrintSettings);
501 NS_ENSURE_SUCCESS(rv, rv);
503 mPrt->mPrintSettings->SetIsCancelled(PR_FALSE);
504 mPrt->mPrintSettings->GetShrinkToFit(&mPrt->mShrinkToFit);
506 if (aIsPrintPreview) {
507 SetIsCreatingPrintPreview(PR_TRUE);
508 SetIsPrintPreview(PR_TRUE);
509 nsCOMPtr<nsIMarkupDocumentViewer> viewer =
510 do_QueryInterface(mDocViewerPrint);
511 if (viewer) {
512 viewer->SetTextZoom(1.0f);
513 viewer->SetFullZoom(1.0f);
515 } else {
516 SetIsPrinting(PR_TRUE);
519 // Create a print session and let the print settings know about it.
520 // The print settings hold an nsWeakPtr to the session so it does not
521 // need to be cleared from the settings at the end of the job.
522 // XXX What lifetime does the printSession need to have?
523 nsCOMPtr<nsIPrintSession> printSession;
524 if (!aIsPrintPreview) {
525 printSession = do_CreateInstance("@mozilla.org/gfx/printsession;1", &rv);
526 NS_ENSURE_SUCCESS(rv, rv);
527 mPrt->mPrintSettings->SetPrintSession(printSession);
530 if (aWebProgressListener != nsnull) {
531 mPrt->mPrintProgressListeners.AppendObject(aWebProgressListener);
534 // Get the currently focused window and cache it
535 // because the Print Dialog will "steal" focus and later when you try
536 // to get the currently focused windows it will be NULL
537 mPrt->mCurrentFocusWin = FindFocusedDOMWindow();
539 // Check to see if there is a "regular" selection
540 PRBool isSelection = IsThereARangeSelection(mPrt->mCurrentFocusWin);
542 // Get the docshell for this documentviewer
543 nsCOMPtr<nsIDocShell> webContainer(do_QueryInterface(mContainer, &rv));
544 NS_ENSURE_SUCCESS(rv, rv);
546 mPrt->mPrintObject = new nsPrintObject();
547 NS_ENSURE_TRUE(mPrt->mPrintObject, NS_ERROR_OUT_OF_MEMORY);
548 rv = mPrt->mPrintObject->Init(webContainer, aDoc, aIsPrintPreview);
549 NS_ENSURE_SUCCESS(rv, rv);
551 NS_ENSURE_TRUE(mPrt->mPrintDocList.AppendElement(mPrt->mPrintObject),
552 NS_ERROR_OUT_OF_MEMORY);
554 mPrt->mIsParentAFrameSet = IsParentAFrameSet(webContainer);
555 mPrt->mPrintObject->mFrameType = mPrt->mIsParentAFrameSet ? eFrameSet : eDoc;
557 // Build the "tree" of PrintObjects
558 nsCOMPtr<nsIDocShellTreeNode> parentAsNode =
559 do_QueryInterface(mPrt->mPrintObject->mDocShell);
560 BuildDocTree(parentAsNode, &mPrt->mPrintDocList, mPrt->mPrintObject);
562 // XXX This isn't really correct...
563 if (!mPrt->mPrintObject->mDocument ||
564 !mPrt->mPrintObject->mDocument->GetRootElement())
565 return NS_ERROR_GFX_PRINTER_STARTDOC;
567 // Create the linkage from the sub-docs back to the content element
568 // in the parent document
569 MapContentToWebShells(mPrt->mPrintObject, mPrt->mPrintObject);
571 mPrt->mIsIFrameSelected = IsThereAnIFrameSelected(webContainer, mPrt->mCurrentFocusWin, mPrt->mIsParentAFrameSet);
573 // Setup print options for UI
574 if (mPrt->mIsParentAFrameSet) {
575 if (mPrt->mCurrentFocusWin) {
576 mPrt->mPrintSettings->SetHowToEnableFrameUI(nsIPrintSettings::kFrameEnableAll);
577 } else {
578 mPrt->mPrintSettings->SetHowToEnableFrameUI(nsIPrintSettings::kFrameEnableAsIsAndEach);
580 } else {
581 mPrt->mPrintSettings->SetHowToEnableFrameUI(nsIPrintSettings::kFrameEnableNone);
583 // Now determine how to set up the Frame print UI
584 mPrt->mPrintSettings->SetPrintOptions(nsIPrintSettings::kEnableSelectionRB, isSelection || mPrt->mIsIFrameSelected);
586 nsCOMPtr<nsIDeviceContextSpec> devspec
587 (do_CreateInstance("@mozilla.org/gfx/devicecontextspec;1", &rv));
588 NS_ENSURE_SUCCESS(rv, rv);
590 nsScriptSuppressor scriptSuppressor(this);
591 if (!aIsPrintPreview) {
592 #ifdef NS_DEBUG
593 mPrt->mDebugFilePtr = mDebugFile;
594 #endif
596 scriptSuppressor.Suppress();
597 PRBool printSilently;
598 mPrt->mPrintSettings->GetPrintSilent(&printSilently);
600 // Check prefs for a default setting as to whether we should print silently
601 printSilently = nsContentUtils::GetBoolPref("print.always_print_silent",
602 printSilently);
604 // Ask dialog to be Print Shown via the Plugable Printing Dialog Service
605 // This service is for the Print Dialog and the Print Progress Dialog
606 // If printing silently or you can't get the service continue on
607 if (!printSilently) {
608 nsCOMPtr<nsIPrintingPromptService> printPromptService(do_GetService(kPrintingPromptService));
609 if (printPromptService) {
610 nsIDOMWindow *domWin = mDocument->GetWindow();
611 NS_ENSURE_TRUE(domWin, NS_ERROR_FAILURE);
613 // Platforms not implementing a given dialog for the service may
614 // return NS_ERROR_NOT_IMPLEMENTED or an error code.
616 // NS_ERROR_NOT_IMPLEMENTED indicates they want default behavior
617 // Any other error code means we must bail out
619 nsCOMPtr<nsIWebBrowserPrint> wbp(do_QueryInterface(mDocViewerPrint));
620 rv = printPromptService->ShowPrintDialog(domWin, wbp,
621 mPrt->mPrintSettings);
622 if (rv == NS_ERROR_NOT_IMPLEMENTED) {
623 // This means the Dialog service was there,
624 // but they choose not to implement this dialog and
625 // are looking for default behavior from the toolkit
626 rv = NS_OK;
627 } else if (NS_SUCCEEDED(rv)) {
628 // since we got the dialog and it worked then make sure we
629 // are telling GFX we want to print silent
630 printSilently = PR_TRUE;
632 // The user might have changed shrink-to-fit in the print dialog, so update our copy of its state
633 mPrt->mPrintSettings->GetShrinkToFit(&mPrt->mShrinkToFit);
634 } else {
635 rv = NS_ERROR_GFX_NO_PRINTROMPTSERVICE;
637 } else {
638 // Call any code that requires a run of the event loop.
639 rv = mPrt->mPrintSettings->SetupSilentPrinting();
641 // Check explicitly for abort because it's expected
642 if (rv == NS_ERROR_ABORT)
643 return rv;
644 NS_ENSURE_SUCCESS(rv, rv);
647 rv = devspec->Init(nsnull, mPrt->mPrintSettings, aIsPrintPreview);
648 NS_ENSURE_SUCCESS(rv, rv);
650 mPrt->mPrintDC = do_CreateInstance("@mozilla.org/gfx/devicecontext;1", &rv);
651 NS_ENSURE_SUCCESS(rv, rv);
652 rv = mPrt->mPrintDC->InitForPrinting(devspec);
653 NS_ENSURE_SUCCESS(rv, rv);
655 if (aIsPrintPreview) {
656 mPrt->mPrintSettings->SetPrintFrameType(nsIPrintSettings::kFramesAsIs);
658 // override any UI that wants to PrintPreview any selection or page range
659 // we want to view every page in PrintPreview each time
660 mPrt->mPrintSettings->SetPrintRange(nsIPrintSettings::kRangeAllPages);
661 } else {
662 // Always check and set the print settings first and then fall back
663 // onto the PrintService if there isn't a PrintSettings
665 // Posiible Usage values:
666 // nsIPrintSettings::kUseInternalDefault
667 // nsIPrintSettings::kUseSettingWhenPossible
669 // NOTE: The consts are the same for PrintSettings and PrintSettings
670 PRInt16 printFrameTypeUsage = nsIPrintSettings::kUseSettingWhenPossible;
671 mPrt->mPrintSettings->GetPrintFrameTypeUsage(&printFrameTypeUsage);
673 // Ok, see if we are going to use our value and override the default
674 if (printFrameTypeUsage == nsIPrintSettings::kUseSettingWhenPossible) {
675 // Get the Print Options/Settings PrintFrameType to see what is preferred
676 PRInt16 printFrameType = nsIPrintSettings::kEachFrameSep;
677 mPrt->mPrintSettings->GetPrintFrameType(&printFrameType);
679 // Don't let anybody do something stupid like try to set it to
680 // kNoFrames when we are printing a FrameSet
681 if (printFrameType == nsIPrintSettings::kNoFrames) {
682 mPrt->mPrintFrameType = nsIPrintSettings::kEachFrameSep;
683 mPrt->mPrintSettings->SetPrintFrameType(mPrt->mPrintFrameType);
684 } else {
685 // First find out from the PrinService what options are available
686 // to us for Printing FrameSets
687 PRInt16 howToEnableFrameUI;
688 mPrt->mPrintSettings->GetHowToEnableFrameUI(&howToEnableFrameUI);
689 if (howToEnableFrameUI != nsIPrintSettings::kFrameEnableNone) {
690 switch (howToEnableFrameUI) {
691 case nsIPrintSettings::kFrameEnableAll:
692 mPrt->mPrintFrameType = printFrameType;
693 break;
695 case nsIPrintSettings::kFrameEnableAsIsAndEach:
696 if (printFrameType != nsIPrintSettings::kSelectedFrame) {
697 mPrt->mPrintFrameType = printFrameType;
698 } else { // revert back to a good value
699 mPrt->mPrintFrameType = nsIPrintSettings::kEachFrameSep;
701 break;
702 } // switch
703 mPrt->mPrintSettings->SetPrintFrameType(mPrt->mPrintFrameType);
706 } else {
707 mPrt->mPrintSettings->GetPrintFrameType(&mPrt->mPrintFrameType);
711 if (aIsPrintPreview) {
712 PRBool notifyOnInit = PR_FALSE;
713 ShowPrintProgress(PR_FALSE, notifyOnInit);
715 // Very important! Turn Off scripting
716 TurnScriptingOn(PR_FALSE);
718 if (!notifyOnInit) {
719 rv = FinishPrintPreview();
720 } else {
721 rv = NS_OK;
723 NS_ENSURE_SUCCESS(rv, rv);
724 } else {
725 PRUnichar * docTitleStr;
726 PRUnichar * docURLStr;
728 GetDisplayTitleAndURL(mPrt->mPrintObject, &docTitleStr, &docURLStr, eDocTitleDefURLDoc);
730 // Nobody ever cared about the file name passed in, as far as I can tell
731 rv = mPrt->mPrintDC->PrepareDocument(docTitleStr, nsnull);
733 if (docTitleStr) nsMemory::Free(docTitleStr);
734 if (docURLStr) nsMemory::Free(docURLStr);
736 NS_ENSURE_SUCCESS(rv, rv);
738 PRBool doNotify;
739 ShowPrintProgress(PR_TRUE, doNotify);
740 if (!doNotify) {
741 // Print listener setup...
742 mPrt->OnStartPrinting();
743 rv = DocumentReadyForPrinting();
744 NS_ENSURE_SUCCESS(rv, rv);
748 // We will enable scripting later after printing has finished.
749 scriptSuppressor.Disconnect();
751 return NS_OK;
754 //---------------------------------------------------------------------------------
755 NS_IMETHODIMP
756 nsPrintEngine::Print(nsIPrintSettings* aPrintSettings,
757 nsIWebProgressListener* aWebProgressListener)
759 // If we have a print preview document, use that instead of the original
760 // mDocument. That way animated images etc. get printed using the same state
761 // as in print preview.
762 nsCOMPtr<nsIDOMDocument> doc =
763 do_QueryInterface(mPrtPreview && mPrtPreview->mPrintObject ?
764 mPrtPreview->mPrintObject->mDocument : mDocument);
766 return CommonPrint(PR_FALSE, aPrintSettings, aWebProgressListener, doc);
769 NS_IMETHODIMP
770 nsPrintEngine::PrintPreview(nsIPrintSettings* aPrintSettings,
771 nsIDOMWindow *aChildDOMWin,
772 nsIWebProgressListener* aWebProgressListener)
774 // Get the DocShell and see if it is busy
775 // (We can't Print Preview this document if it is still busy)
776 nsCOMPtr<nsIDocShell> docShell(do_QueryInterface(mContainer));
777 NS_ASSERTION(docShell, "This has to be a docshell");
779 PRUint32 busyFlags = nsIDocShell::BUSY_FLAGS_NONE;
780 if (NS_FAILED(docShell->GetBusyFlags(&busyFlags)) ||
781 busyFlags != nsIDocShell::BUSY_FLAGS_NONE) {
782 CloseProgressDialog(aWebProgressListener);
783 ShowPrintErrorDialog(NS_ERROR_GFX_PRINTER_DOC_IS_BUSY_PP, PR_FALSE);
784 return NS_ERROR_FAILURE;
787 NS_ENSURE_STATE(aChildDOMWin);
788 nsCOMPtr<nsIDOMDocument> doc;
789 aChildDOMWin->GetDocument(getter_AddRefs(doc));
790 NS_ENSURE_STATE(doc);
792 // Document is not busy -- go ahead with the Print Preview
793 return CommonPrint(PR_TRUE, aPrintSettings, aWebProgressListener, doc);
796 //----------------------------------------------------------------------------------
797 /* readonly attribute boolean isFramesetDocument; */
798 NS_IMETHODIMP
799 nsPrintEngine::GetIsFramesetDocument(PRBool *aIsFramesetDocument)
801 nsCOMPtr<nsIDocShell> webContainer(do_QueryInterface(mContainer));
802 *aIsFramesetDocument = IsParentAFrameSet(webContainer);
803 return NS_OK;
806 //----------------------------------------------------------------------------------
807 /* readonly attribute boolean isIFrameSelected; */
808 NS_IMETHODIMP
809 nsPrintEngine::GetIsIFrameSelected(PRBool *aIsIFrameSelected)
811 *aIsIFrameSelected = PR_FALSE;
813 // Get the docshell for this documentviewer
814 nsCOMPtr<nsIDocShell> webContainer(do_QueryInterface(mContainer));
815 // Get the currently focused window
816 nsCOMPtr<nsIDOMWindow> currentFocusWin = FindFocusedDOMWindow();
817 if (currentFocusWin && webContainer) {
818 // Get whether the doc contains a frameset
819 // Also, check to see if the currently focus docshell
820 // is a child of this docshell
821 PRPackedBool isParentFrameSet;
822 *aIsIFrameSelected = IsThereAnIFrameSelected(webContainer, currentFocusWin, isParentFrameSet);
824 return NS_OK;
827 //----------------------------------------------------------------------------------
828 /* readonly attribute boolean isRangeSelection; */
829 NS_IMETHODIMP
830 nsPrintEngine::GetIsRangeSelection(PRBool *aIsRangeSelection)
832 // Get the currently focused window
833 nsCOMPtr<nsIDOMWindow> currentFocusWin = FindFocusedDOMWindow();
834 *aIsRangeSelection = IsThereARangeSelection(currentFocusWin);
835 return NS_OK;
838 //----------------------------------------------------------------------------------
839 /* readonly attribute boolean isFramesetFrameSelected; */
840 NS_IMETHODIMP
841 nsPrintEngine::GetIsFramesetFrameSelected(PRBool *aIsFramesetFrameSelected)
843 // Get the currently focused window
844 nsCOMPtr<nsIDOMWindow> currentFocusWin = FindFocusedDOMWindow();
845 *aIsFramesetFrameSelected = currentFocusWin != nsnull;
846 return NS_OK;
849 //----------------------------------------------------------------------------------
850 /* readonly attribute long printPreviewNumPages; */
851 NS_IMETHODIMP
852 nsPrintEngine::GetPrintPreviewNumPages(PRInt32 *aPrintPreviewNumPages)
854 NS_ENSURE_ARG_POINTER(aPrintPreviewNumPages);
856 nsIFrame* seqFrame = nsnull;
857 *aPrintPreviewNumPages = 0;
858 if (!mPrtPreview ||
859 NS_FAILED(GetSeqFrameAndCountPagesInternal(mPrtPreview->mPrintObject, seqFrame, *aPrintPreviewNumPages))) {
860 return NS_ERROR_FAILURE;
862 return NS_OK;
865 //----------------------------------------------------------------------------------
866 // Enumerate all the documents for their titles
867 NS_IMETHODIMP
868 nsPrintEngine::EnumerateDocumentNames(PRUint32* aCount,
869 PRUnichar*** aResult)
871 NS_ENSURE_ARG(aCount);
872 NS_ENSURE_ARG_POINTER(aResult);
874 *aCount = 0;
875 *aResult = nsnull;
877 PRInt32 numDocs = mPrt->mPrintDocList.Length();
878 PRUnichar** array = (PRUnichar**) nsMemory::Alloc(numDocs * sizeof(PRUnichar*));
879 if (!array)
880 return NS_ERROR_OUT_OF_MEMORY;
882 for (PRInt32 i=0;i<numDocs;i++) {
883 nsPrintObject* po = mPrt->mPrintDocList.ElementAt(i);
884 NS_ASSERTION(po, "nsPrintObject can't be null!");
885 PRUnichar * docTitleStr;
886 PRUnichar * docURLStr;
887 GetDocumentTitleAndURL(po->mDocument, &docTitleStr, &docURLStr);
889 // Use the URL if the doc is empty
890 if (!docTitleStr || !*docTitleStr) {
891 if (docURLStr && *docURLStr) {
892 nsMemory::Free(docTitleStr);
893 docTitleStr = docURLStr;
894 } else {
895 nsMemory::Free(docURLStr);
897 docURLStr = nsnull;
898 if (!docTitleStr || !*docTitleStr) {
899 CleanupDocTitleArray(array, i);
900 return NS_ERROR_OUT_OF_MEMORY;
903 array[i] = docTitleStr;
904 if (docURLStr) nsMemory::Free(docURLStr);
906 *aCount = numDocs;
907 *aResult = array;
909 return NS_OK;
913 //----------------------------------------------------------------------------------
914 /* readonly attribute nsIPrintSettings globalPrintSettings; */
915 nsresult
916 nsPrintEngine::GetGlobalPrintSettings(nsIPrintSettings **aGlobalPrintSettings)
918 NS_ENSURE_ARG_POINTER(aGlobalPrintSettings);
920 nsresult rv = NS_ERROR_FAILURE;
921 nsCOMPtr<nsIPrintSettingsService> printSettingsService =
922 do_GetService(sPrintSettingsServiceContractID, &rv);
923 if (NS_SUCCEEDED(rv)) {
924 rv = printSettingsService->GetGlobalPrintSettings(aGlobalPrintSettings);
926 return rv;
929 //----------------------------------------------------------------------------------
930 /* readonly attribute boolean doingPrint; */
931 NS_IMETHODIMP
932 nsPrintEngine::GetDoingPrint(PRBool *aDoingPrint)
934 NS_ENSURE_ARG_POINTER(aDoingPrint);
935 *aDoingPrint = mIsDoingPrinting;
936 return NS_OK;
939 //----------------------------------------------------------------------------------
940 /* readonly attribute boolean doingPrintPreview; */
941 NS_IMETHODIMP
942 nsPrintEngine::GetDoingPrintPreview(PRBool *aDoingPrintPreview)
944 NS_ENSURE_ARG_POINTER(aDoingPrintPreview);
945 *aDoingPrintPreview = mIsDoingPrintPreview;
946 return NS_OK;
949 //----------------------------------------------------------------------------------
950 /* readonly attribute nsIPrintSettings currentPrintSettings; */
951 NS_IMETHODIMP
952 nsPrintEngine::GetCurrentPrintSettings(nsIPrintSettings * *aCurrentPrintSettings)
954 NS_ENSURE_ARG_POINTER(aCurrentPrintSettings);
956 if (mPrt) {
957 *aCurrentPrintSettings = mPrt->mPrintSettings;
959 } else if (mPrtPreview) {
960 *aCurrentPrintSettings = mPrtPreview->mPrintSettings;
962 } else {
963 *aCurrentPrintSettings = nsnull;
965 NS_IF_ADDREF(*aCurrentPrintSettings);
966 return NS_OK;
969 //-----------------------------------------------------------------
970 //-- Section: Pre-Reflow Methods
971 //-----------------------------------------------------------------
973 //---------------------------------------------------------------------
974 // This method checks to see if there is at least one printer defined
975 // and if so, it sets the first printer in the list as the default name
976 // in the PrintSettings which is then used for Printer Preview
977 nsresult
978 nsPrintEngine::CheckForPrinters(nsIPrintSettings* aPrintSettings)
980 #ifdef XP_MACOSX
981 // Mac doesn't support retrieving a printer list.
982 return NS_OK;
983 #else
984 NS_ENSURE_ARG_POINTER(aPrintSettings);
986 // See if aPrintSettings already has a printer
987 nsXPIDLString printerName;
988 nsresult rv = aPrintSettings->GetPrinterName(getter_Copies(printerName));
989 if (NS_SUCCEEDED(rv) && !printerName.IsEmpty()) {
990 return NS_OK;
993 // aPrintSettings doesn't have a printer set. Try to fetch the default.
994 nsCOMPtr<nsIPrintSettingsService> printSettingsService =
995 do_GetService(sPrintSettingsServiceContractID, &rv);
996 NS_ENSURE_SUCCESS(rv, rv);
998 rv = printSettingsService->GetDefaultPrinterName(getter_Copies(printerName));
999 if (NS_SUCCEEDED(rv) && !printerName.IsEmpty()) {
1000 rv = aPrintSettings->SetPrinterName(printerName.get());
1002 return rv;
1003 #endif
1006 //----------------------------------------------------------------------
1007 // Set up to use the "pluggable" Print Progress Dialog
1008 void
1009 nsPrintEngine::ShowPrintProgress(PRBool aIsForPrinting, PRBool& aDoNotify)
1011 // default to not notifying, that if something here goes wrong
1012 // or we aren't going to show the progress dialog we can straight into
1013 // reflowing the doc for printing.
1014 aDoNotify = PR_FALSE;
1016 // Assume we can't do progress and then see if we can
1017 PRBool showProgresssDialog = PR_FALSE;
1019 // if it is already being shown then don't bother to find out if it should be
1020 // so skip this and leave mShowProgressDialog set to FALSE
1021 if (!mProgressDialogIsShown) {
1022 showProgresssDialog =
1023 nsContentUtils::GetBoolPref("print.show_print_progress");
1026 // Turning off the showing of Print Progress in Prefs overrides
1027 // whether the calling PS desire to have it on or off, so only check PS if
1028 // prefs says it's ok to be on.
1029 if (showProgresssDialog) {
1030 mPrt->mPrintSettings->GetShowPrintProgress(&showProgresssDialog);
1033 // Now open the service to get the progress dialog
1034 // If we don't get a service, that's ok, then just don't show progress
1035 if (showProgresssDialog) {
1036 nsCOMPtr<nsIPrintingPromptService> printPromptService(do_GetService(kPrintingPromptService));
1037 if (printPromptService) {
1038 nsPIDOMWindow *domWin = mDocument->GetWindow();
1039 if (!domWin) return;
1041 nsCOMPtr<nsIDocShellTreeItem> docShellItem =
1042 do_QueryInterface(domWin->GetDocShell());
1043 if (!docShellItem) return;
1044 nsCOMPtr<nsIDocShellTreeOwner> owner;
1045 docShellItem->GetTreeOwner(getter_AddRefs(owner));
1046 nsCOMPtr<nsIWebBrowserChrome> browserChrome = do_GetInterface(owner);
1047 if (!browserChrome) return;
1048 PRBool isModal = PR_TRUE;
1049 browserChrome->IsWindowModal(&isModal);
1050 if (isModal) {
1051 // Showing a print progress dialog when printing a modal window
1052 // isn't supported. See bug 301560.
1053 return;
1056 nsCOMPtr<nsIWebProgressListener> printProgressListener;
1058 nsCOMPtr<nsIWebBrowserPrint> wbp(do_QueryInterface(mDocViewerPrint));
1059 nsresult rv = printPromptService->ShowProgress(domWin, wbp, mPrt->mPrintSettings, this, aIsForPrinting,
1060 getter_AddRefs(printProgressListener),
1061 getter_AddRefs(mPrt->mPrintProgressParams),
1062 &aDoNotify);
1063 if (NS_SUCCEEDED(rv)) {
1064 if (printProgressListener && mPrt->mPrintProgressParams) {
1065 mPrt->mPrintProgressListeners.AppendObject(printProgressListener);
1066 SetDocAndURLIntoProgress(mPrt->mPrintObject, mPrt->mPrintProgressParams);
1073 //---------------------------------------------------------------------
1074 PRBool
1075 nsPrintEngine::IsThereARangeSelection(nsIDOMWindow* aDOMWin)
1077 nsCOMPtr<nsIPresShell> presShell;
1078 if (aDOMWin) {
1079 nsCOMPtr<nsPIDOMWindow> window(do_QueryInterface(aDOMWin));
1080 window->GetDocShell()->GetPresShell(getter_AddRefs(presShell));
1083 if (!presShell)
1084 return PR_FALSE;
1086 // check here to see if there is a range selection
1087 // so we know whether to turn on the "Selection" radio button
1088 nsCOMPtr<nsISelection> selection;
1089 selection = presShell->GetCurrentSelection(nsISelectionController::SELECTION_NORMAL);
1090 if (selection) {
1091 PRInt32 count;
1092 selection->GetRangeCount(&count);
1093 if (count == 1) {
1094 nsCOMPtr<nsIDOMRange> range;
1095 if (NS_SUCCEEDED(selection->GetRangeAt(0, getter_AddRefs(range)))) {
1096 // check to make sure it isn't an insertion selection
1097 PRBool isCollapsed;
1098 selection->GetIsCollapsed(&isCollapsed);
1099 return !isCollapsed;
1102 if (count > 1) return PR_TRUE;
1104 return PR_FALSE;
1107 //---------------------------------------------------------------------
1108 PRBool
1109 nsPrintEngine::IsParentAFrameSet(nsIDocShell * aParent)
1111 // See if the incoming doc is the root document
1112 nsCOMPtr<nsIDocShellTreeItem> parentAsItem(do_QueryInterface(aParent));
1113 if (!parentAsItem) return PR_FALSE;
1115 // When it is the top level document we need to check
1116 // to see if it contains a frameset. If it does, then
1117 // we only want to print the doc's children and not the document itself
1118 // For anything else we always print all the children and the document
1119 // for example, if the doc contains an IFRAME we eant to print the child
1120 // document (the IFRAME) and then the rest of the document.
1122 // XXX we really need to search the frame tree, and not the content
1123 // but there is no way to distinguish between IFRAMEs and FRAMEs
1124 // with the GetFrameType call.
1125 // Bug 53459 has been files so we can eventually distinguish
1126 // between IFRAME frames and FRAME frames
1127 PRBool isFrameSet = PR_FALSE;
1128 // only check to see if there is a frameset if there is
1129 // NO parent doc for this doc. meaning this parent is the root doc
1130 nsCOMPtr<nsIDOMDocument> domDoc = do_GetInterface(aParent);
1131 nsCOMPtr<nsIDocument> doc = do_QueryInterface(domDoc);
1132 if (doc) {
1133 nsIContent *rootElement = doc->GetRootElement();
1134 if (rootElement) {
1135 isFrameSet = HasFramesetChild(rootElement);
1138 return isFrameSet;
1142 //---------------------------------------------------------------------
1143 // Recursively build a list of sub documents to be printed
1144 // that mirrors the document tree
1145 void
1146 nsPrintEngine::BuildDocTree(nsIDocShellTreeNode * aParentNode,
1147 nsTArray<nsPrintObject*> * aDocList,
1148 nsPrintObject * aPO)
1150 NS_ASSERTION(aParentNode, "Pointer is null!");
1151 NS_ASSERTION(aDocList, "Pointer is null!");
1152 NS_ASSERTION(aPO, "Pointer is null!");
1154 PRInt32 childWebshellCount;
1155 aParentNode->GetChildCount(&childWebshellCount);
1156 if (childWebshellCount > 0) {
1157 for (PRInt32 i=0;i<childWebshellCount;i++) {
1158 nsCOMPtr<nsIDocShellTreeItem> child;
1159 aParentNode->GetChildAt(i, getter_AddRefs(child));
1160 nsCOMPtr<nsIDocShell> childAsShell(do_QueryInterface(child));
1162 nsCOMPtr<nsIContentViewer> viewer;
1163 childAsShell->GetContentViewer(getter_AddRefs(viewer));
1164 if (viewer) {
1165 nsCOMPtr<nsIContentViewerFile> viewerFile(do_QueryInterface(viewer));
1166 if (viewerFile) {
1167 nsCOMPtr<nsIDocShell> childDocShell(do_QueryInterface(child));
1168 nsCOMPtr<nsIDocShellTreeNode> childNode(do_QueryInterface(child));
1169 nsCOMPtr<nsIDOMDocument> doc = do_GetInterface(childDocShell);
1170 nsPrintObject * po = new nsPrintObject();
1171 po->mParent = aPO;
1172 nsresult rv = po->Init(childDocShell, doc, aPO->mPrintPreview);
1173 if (NS_FAILED(rv))
1174 NS_NOTREACHED("Init failed?");
1175 aPO->mKids.AppendElement(po);
1176 aDocList->AppendElement(po);
1177 BuildDocTree(childNode, aDocList, po);
1184 //---------------------------------------------------------------------
1185 void
1186 nsPrintEngine::GetDocumentTitleAndURL(nsIDocument* aDoc,
1187 PRUnichar** aTitle,
1188 PRUnichar** aURLStr)
1190 NS_ASSERTION(aDoc, "Pointer is null!");
1191 NS_ASSERTION(aTitle, "Pointer is null!");
1192 NS_ASSERTION(aURLStr, "Pointer is null!");
1194 *aTitle = nsnull;
1195 *aURLStr = nsnull;
1197 nsAutoString docTitle;
1198 nsCOMPtr<nsIDOMNSDocument> doc = do_QueryInterface(aDoc);
1199 doc->GetTitle(docTitle);
1200 if (!docTitle.IsEmpty()) {
1201 *aTitle = ToNewUnicode(docTitle);
1204 nsIURI* url = aDoc->GetDocumentURI();
1205 if (!url) return;
1207 nsCOMPtr<nsIURIFixup> urifixup(do_GetService(NS_URIFIXUP_CONTRACTID));
1208 if (!urifixup) return;
1210 nsCOMPtr<nsIURI> exposableURI;
1211 urifixup->CreateExposableURI(url, getter_AddRefs(exposableURI));
1213 if (!exposableURI) return;
1215 nsCAutoString urlCStr;
1216 exposableURI->GetSpec(urlCStr);
1218 nsresult rv;
1219 nsCOMPtr<nsITextToSubURI> textToSubURI =
1220 do_GetService(NS_ITEXTTOSUBURI_CONTRACTID, &rv);
1221 if (NS_FAILED(rv)) return;
1223 nsAutoString unescapedURI;
1224 rv = textToSubURI->UnEscapeURIForUI(NS_LITERAL_CSTRING("UTF-8"),
1225 urlCStr, unescapedURI);
1226 if (NS_FAILED(rv)) return;
1228 *aURLStr = ToNewUnicode(unescapedURI);
1231 //---------------------------------------------------------------------
1232 // The walks the PO tree and for each document it walks the content
1233 // tree looking for any content that are sub-shells
1235 // It then sets the mContent pointer in the "found" PO object back to the
1236 // the document that contained it.
1237 void
1238 nsPrintEngine::MapContentToWebShells(nsPrintObject* aRootPO,
1239 nsPrintObject* aPO)
1241 NS_ASSERTION(aRootPO, "Pointer is null!");
1242 NS_ASSERTION(aPO, "Pointer is null!");
1244 // Recursively walk the content from the root item
1245 // XXX Would be faster to enumerate the subdocuments, although right now
1246 // nsIDocument doesn't expose quite what would be needed.
1247 nsCOMPtr<nsIContentViewer> viewer;
1248 aPO->mDocShell->GetContentViewer(getter_AddRefs(viewer));
1249 if (!viewer) return;
1251 nsCOMPtr<nsIDOMDocument> domDoc;
1252 viewer->GetDOMDocument(getter_AddRefs(domDoc));
1253 nsCOMPtr<nsIDocument> doc = do_QueryInterface(domDoc);
1254 if (!doc) return;
1256 Element* rootElement = doc->GetRootElement();
1257 if (rootElement) {
1258 MapContentForPO(aPO, rootElement);
1259 } else {
1260 NS_WARNING("Null root content on (sub)document.");
1263 // Continue recursively walking the chilren of this PO
1264 for (PRUint32 i=0;i<aPO->mKids.Length();i++) {
1265 MapContentToWebShells(aRootPO, aPO->mKids[i]);
1270 //-------------------------------------------------------
1271 // A Frame's sub-doc may contain content or a FrameSet
1272 // When it contains a FrameSet the mFrameType for the PrintObject
1273 // is always set to an eFrame. Which is fine when printing "AsIs"
1274 // but is incorrect when when printing "Each Frame Separately".
1275 // When printing "Each Frame Separately" the Frame really acts like
1276 // a frameset.
1278 // This method walks the PO tree and checks to see if the PrintObject is
1279 // an eFrame and has children that are eFrames (meaning it's a Frame containing a FrameSet)
1280 // If so, then the mFrameType need to be changed to eFrameSet
1282 // Also note: We only want to call this we are printing "Each Frame Separately"
1283 // when printing "As Is" leave it as an eFrame
1284 void
1285 nsPrintEngine::CheckForChildFrameSets(nsPrintObject* aPO)
1287 NS_ASSERTION(aPO, "Pointer is null!");
1289 // Continue recursively walking the chilren of this PO
1290 PRBool hasChildFrames = PR_FALSE;
1291 for (PRUint32 i=0;i<aPO->mKids.Length();i++) {
1292 nsPrintObject* po = aPO->mKids[i];
1293 if (po->mFrameType == eFrame) {
1294 hasChildFrames = PR_TRUE;
1295 CheckForChildFrameSets(po);
1299 if (hasChildFrames && aPO->mFrameType == eFrame) {
1300 aPO->mFrameType = eFrameSet;
1304 //---------------------------------------------------------------------
1305 // This method is key to the entire print mechanism.
1307 // This "maps" or figures out which sub-doc represents a
1308 // given Frame or IFrame in its parent sub-doc.
1310 // So the Mcontent pointer in the child sub-doc points to the
1311 // content in the its parent document, that caused it to be printed.
1312 // This is used later to (after reflow) to find the absolute location
1313 // of the sub-doc on its parent's page frame so it can be
1314 // printed in the correct location.
1316 // This method recursvely "walks" the content for a document finding
1317 // all the Frames and IFrames, then sets the "mFrameType" data member
1318 // which tells us what type of PO we have
1319 void
1320 nsPrintEngine::MapContentForPO(nsPrintObject* aPO,
1321 nsIContent* aContent)
1323 NS_PRECONDITION(aPO && aContent, "Null argument");
1325 nsIDocument* doc = aContent->GetDocument();
1327 NS_ASSERTION(doc, "Content without a document from a document tree?");
1329 nsIDocument* subDoc = doc->GetSubDocumentFor(aContent);
1331 if (subDoc) {
1332 nsCOMPtr<nsISupports> container = subDoc->GetContainer();
1333 nsCOMPtr<nsIDocShell> docShell(do_QueryInterface(container));
1335 if (docShell) {
1336 nsPrintObject * po = nsnull;
1337 PRInt32 cnt = aPO->mKids.Length();
1338 for (PRInt32 i=0;i<cnt;i++) {
1339 nsPrintObject* kid = aPO->mKids.ElementAt(i);
1340 if (kid->mDocument == subDoc) {
1341 po = kid;
1342 break;
1346 // XXX If a subdocument has no onscreen presentation, there will be no PO
1347 // This is even if there should be a print presentation
1348 if (po) {
1350 nsCOMPtr<nsIDOMHTMLFrameElement> frame(do_QueryInterface(aContent));
1351 // "frame" elements not in a frameset context should be treated
1352 // as iframes
1353 if (frame && po->mParent->mFrameType == eFrameSet) {
1354 po->mFrameType = eFrame;
1355 } else {
1356 // Assume something iframe-like, i.e. iframe, object, or embed
1357 po->mFrameType = eIFrame;
1358 SetPrintAsIs(po, PR_TRUE);
1359 NS_ASSERTION(po->mParent, "The root must be a parent");
1360 po->mParent->mPrintAsIs = PR_TRUE;
1366 // walk children content
1367 PRUint32 count = aContent->GetChildCount();
1368 for (PRUint32 i = 0; i < count; ++i) {
1369 nsIContent *child = aContent->GetChildAt(i);
1370 MapContentForPO(aPO, child);
1374 //---------------------------------------------------------------------
1375 PRBool
1376 nsPrintEngine::IsThereAnIFrameSelected(nsIDocShell* aDocShell,
1377 nsIDOMWindow* aDOMWin,
1378 PRPackedBool& aIsParentFrameSet)
1380 aIsParentFrameSet = IsParentAFrameSet(aDocShell);
1381 PRBool iFrameIsSelected = PR_FALSE;
1382 if (mPrt && mPrt->mPrintObject) {
1383 nsPrintObject* po = FindPrintObjectByDOMWin(mPrt->mPrintObject, aDOMWin);
1384 iFrameIsSelected = po && po->mFrameType == eIFrame;
1385 } else {
1386 // First, check to see if we are a frameset
1387 if (!aIsParentFrameSet) {
1388 // Check to see if there is a currenlt focused frame
1389 // if so, it means the selected frame is either the main docshell
1390 // or an IFRAME
1391 if (aDOMWin) {
1392 // Get the main docshell's DOMWin to see if it matches
1393 // the frame that is selected
1394 nsCOMPtr<nsIDOMWindow> domWin = do_GetInterface(aDocShell);
1395 if (domWin != aDOMWin) {
1396 iFrameIsSelected = PR_TRUE; // we have a selected IFRAME
1402 return iFrameIsSelected;
1405 //---------------------------------------------------------------------
1406 // Recursively sets all the PO items to be printed
1407 // from the given item down into the tree
1408 void
1409 nsPrintEngine::SetPrintPO(nsPrintObject* aPO, PRBool aPrint)
1411 NS_ASSERTION(aPO, "Pointer is null!");
1413 // Set whether to print flag
1414 aPO->mDontPrint = !aPrint;
1416 for (PRUint32 i=0;i<aPO->mKids.Length();i++) {
1417 SetPrintPO(aPO->mKids[i], aPrint);
1421 //---------------------------------------------------------------------
1422 // This will first use a Title and/or URL from the PrintSettings
1423 // if one isn't set then it uses the one from the document
1424 // then if not title is there we will make sure we send something back
1425 // depending on the situation.
1426 void
1427 nsPrintEngine::GetDisplayTitleAndURL(nsPrintObject* aPO,
1428 PRUnichar** aTitle,
1429 PRUnichar** aURLStr,
1430 eDocTitleDefault aDefType)
1432 NS_ASSERTION(aPO, "Pointer is null!");
1433 NS_ASSERTION(aTitle, "Pointer is null!");
1434 NS_ASSERTION(aURLStr, "Pointer is null!");
1436 *aTitle = nsnull;
1437 *aURLStr = nsnull;
1439 if (!mPrt)
1440 return;
1442 // First check to see if the PrintSettings has defined an alternate title
1443 // and use that if it did
1444 PRUnichar * docTitleStrPS = nsnull;
1445 PRUnichar * docURLStrPS = nsnull;
1446 if (mPrt->mPrintSettings) {
1447 mPrt->mPrintSettings->GetTitle(&docTitleStrPS);
1448 mPrt->mPrintSettings->GetDocURL(&docURLStrPS);
1450 if (docTitleStrPS && *docTitleStrPS) {
1451 *aTitle = docTitleStrPS;
1454 if (docURLStrPS && *docURLStrPS) {
1455 *aURLStr = docURLStrPS;
1458 // short circut
1459 if (docTitleStrPS && docURLStrPS) {
1460 return;
1464 PRUnichar* docTitle;
1465 PRUnichar* docUrl;
1466 GetDocumentTitleAndURL(aPO->mDocument, &docTitle, &docUrl);
1468 if (docUrl) {
1469 if (!docURLStrPS)
1470 *aURLStr = docUrl;
1471 else
1472 nsMemory::Free(docUrl);
1475 if (docTitle) {
1476 if (!docTitleStrPS)
1477 *aTitle = docTitle;
1478 else
1479 nsMemory::Free(docTitle);
1480 } else if (!docTitleStrPS) {
1481 switch (aDefType) {
1482 case eDocTitleDefBlank: *aTitle = ToNewUnicode(EmptyString());
1483 break;
1485 case eDocTitleDefURLDoc:
1486 if (*aURLStr) {
1487 *aTitle = NS_strdup(*aURLStr);
1488 } else if (mPrt->mBrandName) {
1489 *aTitle = NS_strdup(mPrt->mBrandName);
1491 break;
1492 case eDocTitleDefNone:
1493 // *aTitle defaults to nsnull
1494 break;
1499 //---------------------------------------------------------------------
1500 nsresult nsPrintEngine::DocumentReadyForPrinting()
1502 if (mPrt->mPrintFrameType == nsIPrintSettings::kEachFrameSep) {
1503 CheckForChildFrameSets(mPrt->mPrintObject);
1507 // Send the document to the printer...
1509 nsresult rv = SetupToPrintContent();
1510 if (NS_FAILED(rv)) {
1511 // The print job was canceled or there was a problem
1512 // So remove all other documents from the print list
1513 DonePrintingPages(nsnull, rv);
1515 return rv;
1518 /** ---------------------------------------------------
1519 * Cleans up when an error occurred
1521 nsresult nsPrintEngine::CleanupOnFailure(nsresult aResult, PRBool aIsPrinting)
1523 PR_PL(("**** Failed %s - rv 0x%X", aIsPrinting?"Printing":"Print Preview", aResult));
1525 /* cleanup... */
1526 if (mPagePrintTimer) {
1527 mPagePrintTimer->Stop();
1528 NS_RELEASE(mPagePrintTimer);
1531 if (aIsPrinting) {
1532 SetIsPrinting(PR_FALSE);
1533 } else {
1534 SetIsPrintPreview(PR_FALSE);
1535 SetIsCreatingPrintPreview(PR_FALSE);
1538 /* cleanup done, let's fire-up an error dialog to notify the user
1539 * what went wrong...
1541 * When rv == NS_ERROR_ABORT, it means we want out of the
1542 * print job without displaying any error messages
1544 if (aResult != NS_ERROR_ABORT) {
1545 ShowPrintErrorDialog(aResult, aIsPrinting);
1548 FirePrintCompletionEvent();
1550 return aResult;
1554 //---------------------------------------------------------------------
1555 void
1556 nsPrintEngine::ShowPrintErrorDialog(nsresult aPrintError, PRBool aIsPrinting)
1559 PR_PL(("nsPrintEngine::ShowPrintErrorDialog(nsresult aPrintError=%lx, PRBool aIsPrinting=%d)\n", (long)aPrintError, (int)aIsPrinting));
1561 nsCAutoString stringName;
1563 switch(aPrintError)
1565 #define NS_ERROR_TO_LOCALIZED_PRINT_ERROR_MSG(nserr) case nserr: stringName.AssignLiteral(#nserr); break;
1566 NS_ERROR_TO_LOCALIZED_PRINT_ERROR_MSG(NS_ERROR_GFX_PRINTER_CMD_NOT_FOUND)
1567 NS_ERROR_TO_LOCALIZED_PRINT_ERROR_MSG(NS_ERROR_GFX_PRINTER_CMD_FAILURE)
1568 NS_ERROR_TO_LOCALIZED_PRINT_ERROR_MSG(NS_ERROR_GFX_PRINTER_NO_PRINTER_AVAILABLE)
1569 NS_ERROR_TO_LOCALIZED_PRINT_ERROR_MSG(NS_ERROR_GFX_PRINTER_NAME_NOT_FOUND)
1570 NS_ERROR_TO_LOCALIZED_PRINT_ERROR_MSG(NS_ERROR_GFX_PRINTER_ACCESS_DENIED)
1571 NS_ERROR_TO_LOCALIZED_PRINT_ERROR_MSG(NS_ERROR_GFX_PRINTER_INVALID_ATTRIBUTE)
1572 NS_ERROR_TO_LOCALIZED_PRINT_ERROR_MSG(NS_ERROR_GFX_PRINTER_PRINTER_NOT_READY)
1573 NS_ERROR_TO_LOCALIZED_PRINT_ERROR_MSG(NS_ERROR_GFX_PRINTER_OUT_OF_PAPER)
1574 NS_ERROR_TO_LOCALIZED_PRINT_ERROR_MSG(NS_ERROR_GFX_PRINTER_PRINTER_IO_ERROR)
1575 NS_ERROR_TO_LOCALIZED_PRINT_ERROR_MSG(NS_ERROR_GFX_PRINTER_COULD_NOT_OPEN_FILE)
1576 NS_ERROR_TO_LOCALIZED_PRINT_ERROR_MSG(NS_ERROR_GFX_PRINTER_FILE_IO_ERROR)
1577 NS_ERROR_TO_LOCALIZED_PRINT_ERROR_MSG(NS_ERROR_GFX_PRINTER_PRINTPREVIEW)
1578 NS_ERROR_TO_LOCALIZED_PRINT_ERROR_MSG(NS_ERROR_UNEXPECTED)
1579 NS_ERROR_TO_LOCALIZED_PRINT_ERROR_MSG(NS_ERROR_OUT_OF_MEMORY)
1580 NS_ERROR_TO_LOCALIZED_PRINT_ERROR_MSG(NS_ERROR_NOT_IMPLEMENTED)
1581 NS_ERROR_TO_LOCALIZED_PRINT_ERROR_MSG(NS_ERROR_NOT_AVAILABLE)
1582 NS_ERROR_TO_LOCALIZED_PRINT_ERROR_MSG(NS_ERROR_ABORT)
1583 NS_ERROR_TO_LOCALIZED_PRINT_ERROR_MSG(NS_ERROR_GFX_PRINTER_STARTDOC)
1584 NS_ERROR_TO_LOCALIZED_PRINT_ERROR_MSG(NS_ERROR_GFX_PRINTER_ENDDOC)
1585 NS_ERROR_TO_LOCALIZED_PRINT_ERROR_MSG(NS_ERROR_GFX_PRINTER_STARTPAGE)
1586 NS_ERROR_TO_LOCALIZED_PRINT_ERROR_MSG(NS_ERROR_GFX_PRINTER_ENDPAGE)
1587 NS_ERROR_TO_LOCALIZED_PRINT_ERROR_MSG(NS_ERROR_GFX_PRINTER_PRINT_WHILE_PREVIEW)
1588 NS_ERROR_TO_LOCALIZED_PRINT_ERROR_MSG(NS_ERROR_GFX_PRINTER_PAPER_SIZE_NOT_SUPPORTED)
1589 NS_ERROR_TO_LOCALIZED_PRINT_ERROR_MSG(NS_ERROR_GFX_PRINTER_ORIENTATION_NOT_SUPPORTED)
1590 NS_ERROR_TO_LOCALIZED_PRINT_ERROR_MSG(NS_ERROR_GFX_PRINTER_COLORSPACE_NOT_SUPPORTED)
1591 NS_ERROR_TO_LOCALIZED_PRINT_ERROR_MSG(NS_ERROR_GFX_PRINTER_TOO_MANY_COPIES)
1592 NS_ERROR_TO_LOCALIZED_PRINT_ERROR_MSG(NS_ERROR_GFX_PRINTER_DRIVER_CONFIGURATION_ERROR)
1593 NS_ERROR_TO_LOCALIZED_PRINT_ERROR_MSG(NS_ERROR_GFX_PRINTER_DOC_IS_BUSY_PP)
1594 NS_ERROR_TO_LOCALIZED_PRINT_ERROR_MSG(NS_ERROR_GFX_PRINTER_DOC_WAS_DESTORYED)
1595 NS_ERROR_TO_LOCALIZED_PRINT_ERROR_MSG(NS_ERROR_GFX_NO_PRINTDIALOG_IN_TOOLKIT)
1596 NS_ERROR_TO_LOCALIZED_PRINT_ERROR_MSG(NS_ERROR_GFX_NO_PRINTROMPTSERVICE)
1597 NS_ERROR_TO_LOCALIZED_PRINT_ERROR_MSG(NS_ERROR_GFX_PRINTER_NO_XUL) // Temporary code for Bug 136185 / bug 240490
1598 NS_ERROR_TO_LOCALIZED_PRINT_ERROR_MSG(NS_ERROR_GFX_PRINTER_PLEX_NOT_SUPPORTED)
1599 NS_ERROR_TO_LOCALIZED_PRINT_ERROR_MSG(NS_ERROR_GFX_PRINTER_DOC_IS_BUSY)
1600 NS_ERROR_TO_LOCALIZED_PRINT_ERROR_MSG(NS_ERROR_GFX_PRINTING_NOT_IMPLEMENTED)
1601 NS_ERROR_TO_LOCALIZED_PRINT_ERROR_MSG(NS_ERROR_GFX_COULD_NOT_LOAD_PRINT_MODULE)
1602 NS_ERROR_TO_LOCALIZED_PRINT_ERROR_MSG(NS_ERROR_GFX_PRINTER_RESOLUTION_NOT_SUPPORTED)
1604 default:
1605 NS_ERROR_TO_LOCALIZED_PRINT_ERROR_MSG(NS_ERROR_FAILURE)
1606 #undef NS_ERROR_TO_LOCALIZED_PRINT_ERROR_MSG
1609 PR_PL(("ShowPrintErrorDialog: stringName='%s'\n", stringName.get()));
1611 nsXPIDLString msg, title;
1612 nsresult rv =
1613 nsContentUtils::GetLocalizedString(nsContentUtils::ePRINTING_PROPERTIES,
1614 stringName.get(), msg);
1615 if (NS_FAILED(rv)) {
1616 PR_PL(("GetLocalizedString failed\n"));
1617 return;
1620 rv = nsContentUtils::GetLocalizedString(nsContentUtils::ePRINTING_PROPERTIES,
1621 aIsPrinting ? "print_error_dialog_title"
1622 : "printpreview_error_dialog_title",
1623 title);
1625 nsCOMPtr<nsIWindowWatcher> wwatch = do_GetService(NS_WINDOWWATCHER_CONTRACTID, &rv);
1626 if (NS_FAILED(rv)) {
1627 PR_PL(("ShowPrintErrorDialog(): wwatch==nsnull\n"));
1628 return;
1631 nsCOMPtr<nsIDOMWindow> active;
1632 wwatch->GetActiveWindow(getter_AddRefs(active));
1634 nsCOMPtr<nsIPrompt> dialog;
1635 /* |GetNewPrompter| allows that |active| is |nsnull|
1636 * (see bug 234982 ("nsPrintEngine::ShowPrintErrorDialog() fails in many cases")) */
1637 wwatch->GetNewPrompter(active, getter_AddRefs(dialog));
1638 if (!dialog) {
1639 PR_PL(("ShowPrintErrorDialog(): dialog==nsnull\n"));
1640 return;
1643 dialog->Alert(title.get(), msg.get());
1644 PR_PL(("ShowPrintErrorDialog(): alert displayed successfully.\n"));
1647 //-----------------------------------------------------------------
1648 //-- Section: Reflow Methods
1649 //-----------------------------------------------------------------
1651 //-------------------------------------------------------
1652 nsresult
1653 nsPrintEngine::SetupToPrintContent()
1655 // In this step we figure out which documents should be printed
1656 // i.e. if we are printing the selection then only enable that nsPrintObject
1657 // for printing
1658 if (NS_FAILED(EnablePOsForPrinting())) {
1659 return NS_ERROR_FAILURE;
1661 DUMP_DOC_LIST("\nAfter Enable------------------------------------------");
1663 // This is an Optimization
1664 // If we are in PP then we already know all the shrinkage information
1665 // so just transfer it to the PrintData and we will skip the extra shrinkage reflow
1667 // doSetPixelScale tells Reflow whether to set the shrinkage value into the DC
1668 // The first time we do not want to do this, the second time through we do
1669 PRBool doSetPixelScale = PR_FALSE;
1670 PRBool ppIsShrinkToFit = mPrtPreview && mPrtPreview->mShrinkToFit;
1671 if (ppIsShrinkToFit) {
1672 mPrt->mShrinkRatio = mPrtPreview->mShrinkRatio;
1673 doSetPixelScale = PR_TRUE;
1676 // Here we reflow all the PrintObjects
1677 nsresult rv = ReflowDocList(mPrt->mPrintObject, doSetPixelScale);
1678 if (NS_FAILED(rv)) {
1679 return NS_ERROR_FAILURE;
1682 // Here is where we do the extra reflow for shrinking the content
1683 // But skip this step if we are in PrintPreview
1684 if (mPrt->mShrinkToFit && !ppIsShrinkToFit) {
1685 // Now look for the PO that has the smallest percent for shrink to fit
1686 if (mPrt->mPrintDocList.Length() > 1 && mPrt->mPrintObject->mFrameType == eFrameSet) {
1687 nsPrintObject* smallestPO = FindSmallestSTF();
1688 NS_ASSERTION(smallestPO, "There must always be an XMost PO!");
1689 if (smallestPO) {
1690 // Calc the shrinkage based on the entire content area
1691 mPrt->mShrinkRatio = smallestPO->mShrinkRatio;
1693 } else {
1694 // Single document so use the Shrink as calculated for the PO
1695 mPrt->mShrinkRatio = mPrt->mPrintObject->mShrinkRatio;
1698 // Only Shrink if we are smaller
1699 if (mPrt->mShrinkRatio < 0.998f) {
1700 // Clamp Shrink to Fit to 60%
1701 mPrt->mShrinkRatio = NS_MAX(mPrt->mShrinkRatio, 0.60f);
1703 for (PRUint32 i=0;i<mPrt->mPrintDocList.Length();i++) {
1704 nsPrintObject* po = mPrt->mPrintDocList.ElementAt(i);
1705 NS_ASSERTION(po, "nsPrintObject can't be null!");
1706 // Wipe out the presentation before we reflow
1707 po->DestroyPresentation();
1710 #if (defined(XP_WIN) || defined(XP_OS2)) && defined(EXTENDED_DEBUG_PRINTING)
1711 // We need to clear all the output files here
1712 // because they will be re-created with second reflow of the docs
1713 if (kPrintingLogMod && kPrintingLogMod->level == DUMP_LAYOUT_LEVEL) {
1714 RemoveFilesInDir(".\\");
1715 gDumpFileNameCnt = 0;
1716 gDumpLOFileNameCnt = 0;
1718 #endif
1720 // Here we reflow all the PrintObjects a second time
1721 // this time using the shrinkage values
1722 // The last param here tells reflow to NOT calc the shrinkage values
1723 if (NS_FAILED(ReflowDocList(mPrt->mPrintObject, PR_TRUE))) {
1724 return NS_ERROR_FAILURE;
1728 #ifdef PR_LOGGING
1730 float calcRatio = 0.0f;
1731 if (mPrt->mPrintDocList.Length() > 1 && mPrt->mPrintObject->mFrameType == eFrameSet) {
1732 nsPrintObject* smallestPO = FindSmallestSTF();
1733 NS_ASSERTION(smallestPO, "There must always be an XMost PO!");
1734 if (smallestPO) {
1735 // Calc the shrinkage based on the entire content area
1736 calcRatio = smallestPO->mShrinkRatio;
1738 } else {
1739 // Single document so use the Shrink as calculated for the PO
1740 calcRatio = mPrt->mPrintObject->mShrinkRatio;
1742 PR_PL(("**************************************************************************\n"));
1743 PR_PL(("STF Ratio is: %8.5f Effective Ratio: %8.5f Diff: %8.5f\n", mPrt->mShrinkRatio, calcRatio, mPrt->mShrinkRatio-calcRatio));
1744 PR_PL(("**************************************************************************\n"));
1746 #endif
1749 DUMP_DOC_LIST(("\nAfter Reflow------------------------------------------"));
1750 PR_PL(("\n"));
1751 PR_PL(("-------------------------------------------------------\n"));
1752 PR_PL(("\n"));
1754 CalcNumPrintablePages(mPrt->mNumPrintablePages);
1756 PR_PL(("--- Printing %d pages\n", mPrt->mNumPrintablePages));
1757 DUMP_DOC_TREELAYOUT;
1759 // Print listener setup...
1760 if (mPrt != nsnull) {
1761 mPrt->OnStartPrinting();
1764 PRUnichar* fileName = nsnull;
1765 // check to see if we are printing to a file
1766 PRBool isPrintToFile = PR_FALSE;
1767 mPrt->mPrintSettings->GetPrintToFile(&isPrintToFile);
1768 if (isPrintToFile) {
1769 // On some platforms The BeginDocument needs to know the name of the file
1770 // and it uses the PrintService to get it, so we need to set it into the PrintService here
1771 mPrt->mPrintSettings->GetToFileName(&fileName);
1774 PRUnichar * docTitleStr;
1775 PRUnichar * docURLStr;
1776 GetDisplayTitleAndURL(mPrt->mPrintObject, &docTitleStr, &docURLStr, eDocTitleDefURLDoc);
1778 PRInt32 startPage = 1;
1779 PRInt32 endPage = mPrt->mNumPrintablePages;
1781 PRInt16 printRangeType = nsIPrintSettings::kRangeAllPages;
1782 mPrt->mPrintSettings->GetPrintRange(&printRangeType);
1783 if (printRangeType == nsIPrintSettings::kRangeSpecifiedPageRange) {
1784 mPrt->mPrintSettings->GetStartPageRange(&startPage);
1785 mPrt->mPrintSettings->GetEndPageRange(&endPage);
1786 if (endPage > mPrt->mNumPrintablePages) {
1787 endPage = mPrt->mNumPrintablePages;
1791 rv = NS_OK;
1792 // BeginDocument may pass back a FAILURE code
1793 // i.e. On Windows, if you are printing to a file and hit "Cancel"
1794 // to the "File Name" dialog, this comes back as an error
1795 // Don't start printing when regression test are executed
1796 if (!mPrt->mDebugFilePtr && mIsDoingPrinting) {
1797 rv = mPrt->mPrintDC->BeginDocument(docTitleStr, fileName, startPage, endPage);
1800 if (mIsCreatingPrintPreview) {
1801 // Print Preview -- Pass ownership of docTitleStr and docURLStr
1802 // to the pageSequenceFrame, to be displayed in the header
1803 nsIPageSequenceFrame *seqFrame = mPrt->mPrintObject->mPresShell->GetPageSequenceFrame();
1804 if (seqFrame) {
1805 seqFrame->StartPrint(mPrt->mPrintObject->mPresContext,
1806 mPrt->mPrintSettings, docTitleStr, docURLStr);
1808 } else {
1809 if (docTitleStr) nsMemory::Free(docTitleStr);
1810 if (docURLStr) nsMemory::Free(docURLStr);
1813 PR_PL(("****************** Begin Document ************************\n"));
1815 NS_ENSURE_SUCCESS(rv, rv);
1817 // This will print the docshell document
1818 // when it completes asynchronously in the DonePrintingPages method
1819 // it will check to see if there are more docshells to be printed and
1820 // then PrintDocContent will be called again.
1822 if (mIsDoingPrinting) {
1823 PrintDocContent(mPrt->mPrintObject, rv); // ignore return value
1826 return rv;
1829 //-------------------------------------------------------
1830 // Recursively reflow each sub-doc and then calc
1831 // all the frame locations of the sub-docs
1832 nsresult
1833 nsPrintEngine::ReflowDocList(nsPrintObject* aPO, PRBool aSetPixelScale)
1835 NS_ENSURE_ARG_POINTER(aPO);
1837 // Check to see if the subdocument's element has been hidden by the parent document
1838 if (aPO->mParent && aPO->mParent->mPresShell) {
1839 nsIFrame * frame = aPO->mContent->GetPrimaryFrame();
1840 if (frame) {
1841 if (!frame->GetStyleVisibility()->IsVisible()) {
1842 aPO->mDontPrint = PR_TRUE;
1843 aPO->mInvisible = PR_TRUE;
1844 return NS_OK;
1849 // Here is where we set the shrinkage value into the DC
1850 // and this is what actually makes it shrink
1851 if (aSetPixelScale && aPO->mFrameType != eIFrame) {
1852 float ratio;
1853 if (mPrt->mPrintFrameType == nsIPrintSettings::kFramesAsIs || mPrt->mPrintFrameType == nsIPrintSettings::kNoFrames) {
1854 ratio = mPrt->mShrinkRatio - 0.005f; // round down
1855 } else {
1856 ratio = aPO->mShrinkRatio - 0.005f; // round down
1858 aPO->mZoomRatio = ratio;
1859 } else if (!mPrt->mShrinkToFit) {
1860 double scaling;
1861 mPrt->mPrintSettings->GetScaling(&scaling);
1862 aPO->mZoomRatio = float(scaling);
1865 nsresult rv;
1866 // Reflow the PO
1867 rv = ReflowPrintObject(aPO);
1868 NS_ENSURE_SUCCESS(rv, rv);
1870 PRInt32 cnt = aPO->mKids.Length();
1871 for (PRInt32 i=0;i<cnt;i++) {
1872 rv = ReflowDocList(aPO->mKids[i], aSetPixelScale);
1873 NS_ENSURE_SUCCESS(rv, rv);
1875 return NS_OK;
1878 //-------------------------------------------------------
1879 // Reflow a nsPrintObject
1880 nsresult
1881 nsPrintEngine::ReflowPrintObject(nsPrintObject * aPO)
1883 NS_ASSERTION(aPO, "Pointer is null!");
1884 if (!aPO) return NS_ERROR_FAILURE;
1886 nsSize adjSize;
1887 PRBool documentIsTopLevel;
1888 nsIFrame* frame = nsnull;
1889 if (!aPO->IsPrintable())
1890 return NS_OK;
1892 if (aPO->mParent && aPO->mParent->IsPrintable()) {
1893 frame = aPO->mContent->GetPrimaryFrame();
1894 // Without a frame, this document can't be displayed; therefore, there is no
1895 // point to reflowing it
1896 if (!frame) {
1897 SetPrintPO(aPO, PR_FALSE);
1898 return NS_OK;
1901 adjSize = frame->GetContentRect().Size();
1902 documentIsTopLevel = PR_FALSE;
1903 // presshell exists because parent is printable
1904 } else {
1905 nscoord pageWidth, pageHeight;
1906 mPrt->mPrintDC->GetDeviceSurfaceDimensions(pageWidth, pageHeight);
1907 #if defined(XP_UNIX) && !defined(XP_MACOSX)
1908 // If we're in landscape mode on Linux, the device surface will have
1909 // been rotated, so for the purposes of reflowing content, we'll
1910 // treat device's height as our width and its width as our height,
1911 PRInt32 orientation;
1912 mPrt->mPrintSettings->GetOrientation(&orientation);
1913 if (nsIPrintSettings::kLandscapeOrientation == orientation) {
1914 adjSize = nsSize(pageHeight, pageWidth);
1915 } else {
1916 adjSize = nsSize(pageWidth, pageHeight);
1918 #else
1919 adjSize = nsSize(pageWidth, pageHeight);
1920 #endif // XP_UNIX && !XP_MACOSX
1921 documentIsTopLevel = PR_TRUE;
1924 // Here we decide whether we need scrollbars and
1925 // what the parent will be of the widget
1926 // How this logic presently works: Print Preview is always as-is (as far
1927 // as I can tell; not sure how it would work in other cases); only the root
1928 // is not eIFrame or eFrame. The child documents get a parent widget from
1929 // logic in nsFrameFrame. In any case, a child widget is created for the root
1930 // view of the document.
1931 PRBool canCreateScrollbars = PR_TRUE;
1932 nsIView* parentView = nsnull;
1933 // the top nsPrintObject's widget will always have scrollbars
1934 if (frame && frame->GetType() == nsGkAtoms::subDocumentFrame) {
1935 nsIView* view = frame->GetView();
1936 NS_ENSURE_TRUE(view, NS_ERROR_FAILURE);
1937 view = view->GetFirstChild();
1938 NS_ENSURE_TRUE(view, NS_ERROR_FAILURE);
1939 parentView = view;
1940 canCreateScrollbars = PR_FALSE;
1943 NS_ASSERTION(!aPO->mPresContext, "Recreating prescontext");
1945 // create the PresContext
1946 aPO->mPresContext = new nsRootPresContext(aPO->mDocument,
1947 mIsCreatingPrintPreview ? nsPresContext::eContext_PrintPreview:
1948 nsPresContext::eContext_Print);
1949 NS_ENSURE_TRUE(aPO->mPresContext, NS_ERROR_OUT_OF_MEMORY);
1950 aPO->mPresContext->SetPrintSettings(mPrt->mPrintSettings);
1952 // set the presentation context to the value in the print settings
1953 PRBool printBGColors;
1954 mPrt->mPrintSettings->GetPrintBGColors(&printBGColors);
1955 aPO->mPresContext->SetBackgroundColorDraw(printBGColors);
1956 mPrt->mPrintSettings->GetPrintBGImages(&printBGColors);
1957 aPO->mPresContext->SetBackgroundImageDraw(printBGColors);
1959 // init it with the DC
1960 nsresult rv = aPO->mPresContext->Init(mPrt->mPrintDC);
1961 NS_ENSURE_SUCCESS(rv, rv);
1963 aPO->mViewManager = do_CreateInstance(kViewManagerCID, &rv);
1964 NS_ENSURE_SUCCESS(rv,rv);
1966 rv = aPO->mViewManager->Init(mPrt->mPrintDC);
1967 NS_ENSURE_SUCCESS(rv,rv);
1969 nsStyleSet* styleSet;
1970 rv = mDocViewerPrint->CreateStyleSet(aPO->mDocument, &styleSet);
1971 NS_ENSURE_SUCCESS(rv, rv);
1973 rv = aPO->mDocument->CreateShell(aPO->mPresContext, aPO->mViewManager,
1974 styleSet, getter_AddRefs(aPO->mPresShell));
1975 if (NS_FAILED(rv)) {
1976 delete styleSet;
1977 return rv;
1980 styleSet->EndUpdate();
1982 // The pres shell now owns the style set object.
1984 PR_PL(("In DV::ReflowPrintObject PO: %p (%9s) Setting w,h to %d,%d\n", aPO,
1985 gFrameTypesStr[aPO->mFrameType], adjSize.width, adjSize.height));
1987 // Create a child window of the parent that is our "root view/window"
1988 nsRect tbounds = nsRect(nsPoint(0, 0), adjSize);
1989 nsIView* rootView = aPO->mViewManager->CreateView(tbounds, parentView);
1990 NS_ENSURE_TRUE(rootView, NS_ERROR_OUT_OF_MEMORY);
1992 // Only create a widget for print preview; when printing, a widget is
1993 // unnecessary and unexpected
1994 // Also, no widget should be needed except for the top-level document
1995 if (mIsCreatingPrintPreview && documentIsTopLevel) {
1996 nsNativeWidget widget = nsnull;
1997 if (!frame)
1998 widget = mParentWidget->GetNativeData(NS_NATIVE_WIDGET);
1999 rv = rootView->CreateWidget(kWidgetCID, nsnull,
2000 widget, PR_TRUE, PR_TRUE,
2001 eContentTypeContent);
2002 NS_ENSURE_SUCCESS(rv, rv);
2003 aPO->mWindow = rootView->GetWidget();
2004 aPO->mPresContext->SetPaginatedScrolling(canCreateScrollbars);
2007 // Setup hierarchical relationship in view manager
2008 aPO->mViewManager->SetRootView(rootView);
2010 // This docshell stuff is weird; will go away when we stop having multiple
2011 // presentations per document
2012 nsCOMPtr<nsISupports> supps(do_QueryInterface(aPO->mDocShell));
2013 aPO->mPresContext->SetContainer(supps);
2015 aPO->mPresShell->BeginObservingDocument();
2017 aPO->mPresContext->SetPageSize(adjSize);
2018 aPO->mPresContext->SetIsRootPaginatedDocument(documentIsTopLevel);
2019 aPO->mPresContext->SetPageScale(aPO->mZoomRatio);
2020 // Calculate scale factor from printer to screen
2021 float printDPI = float(mPrt->mPrintDC->AppUnitsPerInch()) /
2022 float(mPrt->mPrintDC->AppUnitsPerDevPixel());
2023 aPO->mPresContext->SetPrintPreviewScale(mScreenDPI / printDPI);
2025 if (mIsCreatingPrintPreview && documentIsTopLevel) {
2026 mDocViewerPrint->SetPrintPreviewPresentation(aPO->mWindow,
2027 aPO->mViewManager,
2028 aPO->mPresContext,
2029 aPO->mPresShell);
2032 rv = aPO->mPresShell->InitialReflow(adjSize.width, adjSize.height);
2034 NS_ENSURE_SUCCESS(rv, rv);
2035 NS_ASSERTION(aPO->mPresShell, "Presshell should still be here");
2037 // Process the reflow event InitialReflow posted
2038 aPO->mPresShell->FlushPendingNotifications(Flush_Layout);
2040 nsCOMPtr<nsIPresShell> displayShell;
2041 aPO->mDocShell->GetPresShell(getter_AddRefs(displayShell));
2042 // Transfer Selection Ranges to the new Print PresShell
2043 nsCOMPtr<nsISelection> selection, selectionPS;
2044 // It's okay if there is no display shell, just skip copying the selection
2045 if (displayShell) {
2046 selection = displayShell->GetCurrentSelection(nsISelectionController::SELECTION_NORMAL);
2048 selectionPS = aPO->mPresShell->GetCurrentSelection(nsISelectionController::SELECTION_NORMAL);
2049 if (selection && selectionPS) {
2050 PRInt32 cnt;
2051 selection->GetRangeCount(&cnt);
2052 PRInt32 inx;
2053 for (inx=0;inx<cnt;inx++) {
2054 nsCOMPtr<nsIDOMRange> range;
2055 if (NS_SUCCEEDED(selection->GetRangeAt(inx, getter_AddRefs(range))))
2056 selectionPS->AddRange(range);
2060 // If we are trying to shrink the contents to fit on the page
2061 // we must first locate the "pageContent" frame
2062 // Then we walk the frame tree and look for the "xmost" frame
2063 // this is the frame where the right-hand side of the frame extends
2064 // the furthest
2065 if (mPrt->mShrinkToFit && documentIsTopLevel) {
2066 nsIPageSequenceFrame* pageSequence = aPO->mPresShell->GetPageSequenceFrame();
2067 NS_ENSURE_STATE(pageSequence);
2068 pageSequence->GetSTFPercent(aPO->mShrinkRatio);
2071 #ifdef EXTENDED_DEBUG_PRINTING
2072 if (kPrintingLogMod && kPrintingLogMod->level == DUMP_LAYOUT_LEVEL) {
2073 char * docStr;
2074 char * urlStr;
2075 GetDocTitleAndURL(aPO, docStr, urlStr);
2076 char filename[256];
2077 sprintf(filename, "print_dump_%d.txt", gDumpFileNameCnt++);
2078 // Dump all the frames and view to a a file
2079 FILE * fd = fopen(filename, "w");
2080 if (fd) {
2081 nsIFrame *theRootFrame =
2082 aPO->mPresShell->FrameManager()->GetRootFrame();
2083 fprintf(fd, "Title: %s\n", docStr?docStr:"");
2084 fprintf(fd, "URL: %s\n", urlStr?urlStr:"");
2085 fprintf(fd, "--------------- Frames ----------------\n");
2086 nsCOMPtr<nsIRenderingContext> renderingContext;
2087 mPrt->mPrintDocDC->CreateRenderingContext(*getter_AddRefs(renderingContext));
2088 RootFrameList(aPO->mPresContext, fd, 0);
2089 //DumpFrames(fd, aPO->mPresContext, renderingContext, theRootFrame, 0);
2090 fprintf(fd, "---------------------------------------\n\n");
2091 fprintf(fd, "--------------- Views From Root Frame----------------\n");
2092 nsIView* v = theRootFrame->GetView();
2093 if (v) {
2094 v->List(fd);
2095 } else {
2096 printf("View is null!\n");
2098 if (docShell) {
2099 fprintf(fd, "--------------- All Views ----------------\n");
2100 DumpViews(docShell, fd);
2101 fprintf(fd, "---------------------------------------\n\n");
2103 fclose(fd);
2105 if (docStr) nsMemory::Free(docStr);
2106 if (urlStr) nsMemory::Free(urlStr);
2108 #endif
2110 return NS_OK;
2113 //-------------------------------------------------------
2114 // Figure out how many documents and how many total pages we are printing
2115 void
2116 nsPrintEngine::CalcNumPrintablePages(PRInt32& aNumPages)
2118 aNumPages = 0;
2119 // Count the number of printable documents
2120 // and printable pages
2121 for (PRUint32 i=0; i<mPrt->mPrintDocList.Length(); i++) {
2122 nsPrintObject* po = mPrt->mPrintDocList.ElementAt(i);
2123 NS_ASSERTION(po, "nsPrintObject can't be null!");
2124 if (po->mPresContext && po->mPresContext->IsRootPaginatedDocument()) {
2125 nsIPageSequenceFrame* pageSequence = po->mPresShell->GetPageSequenceFrame();
2126 nsIFrame * seqFrame = do_QueryFrame(pageSequence);
2127 if (seqFrame) {
2128 nsIFrame* frame = seqFrame->GetFirstChild(nsnull);
2129 while (frame) {
2130 aNumPages++;
2131 frame = frame->GetNextSibling();
2137 //-----------------------------------------------------------------
2138 //-- Done: Reflow Methods
2139 //-----------------------------------------------------------------
2141 //-----------------------------------------------------------------
2142 //-- Section: Printing Methods
2143 //-----------------------------------------------------------------
2145 //-------------------------------------------------------
2146 // Called for each DocShell that needs to be printed
2147 PRBool
2148 nsPrintEngine::PrintDocContent(nsPrintObject* aPO, nsresult& aStatus)
2150 NS_ASSERTION(aPO, "Pointer is null!");
2151 aStatus = NS_OK;
2153 if (!aPO->mHasBeenPrinted && aPO->IsPrintable()) {
2154 aStatus = DoPrint(aPO);
2155 return PR_TRUE;
2158 // If |aPO->mPrintAsIs| and |aPO->mHasBeenPrinted| are true,
2159 // the kids frames are already processed in |PrintPage|.
2160 if (!aPO->mInvisible && !(aPO->mPrintAsIs && aPO->mHasBeenPrinted)) {
2161 for (PRUint32 i=0;i<aPO->mKids.Length();i++) {
2162 nsPrintObject* po = aPO->mKids[i];
2163 PRBool printed = PrintDocContent(po, aStatus);
2164 if (printed || NS_FAILED(aStatus)) {
2165 return PR_TRUE;
2169 return PR_FALSE;
2172 static already_AddRefed<nsIDOMNode>
2173 GetEqualNodeInCloneTree(nsIDOMNode* aNode, nsIDocument* aDoc)
2175 nsCOMPtr<nsIContent> content = do_QueryInterface(aNode);
2176 // Selections in anonymous subtrees aren't supported.
2177 if (content && content->IsInAnonymousSubtree()) {
2178 return nsnull;
2181 nsCOMPtr<nsINode> node = do_QueryInterface(aNode);
2182 NS_ENSURE_TRUE(node, nsnull);
2184 nsTArray<PRInt32> indexArray;
2185 nsINode* current = node;
2186 NS_ENSURE_TRUE(current, nsnull);
2187 while (current) {
2188 nsINode* parent = current->GetNodeParent();
2189 if (!parent) {
2190 break;
2192 PRInt32 index = parent->IndexOf(current);
2193 NS_ENSURE_TRUE(index >= 0, nsnull);
2194 indexArray.AppendElement(index);
2195 current = parent;
2197 NS_ENSURE_TRUE(current->IsNodeOfType(nsINode::eDOCUMENT), nsnull);
2199 current = aDoc;
2200 for (PRInt32 i = indexArray.Length() - 1; i >= 0; --i) {
2201 current = current->GetChildAt(indexArray[i]);
2202 NS_ENSURE_TRUE(current, nsnull);
2204 nsCOMPtr<nsIDOMNode> result = do_QueryInterface(current);
2205 return result.forget();
2208 static nsresult CloneRangeToSelection(nsIDOMRange* aRange,
2209 nsIDocument* aDoc,
2210 nsISelection* aSelection)
2212 PRBool collapsed = PR_FALSE;
2213 aRange->GetCollapsed(&collapsed);
2214 if (collapsed) {
2215 return NS_OK;
2218 nsCOMPtr<nsIDOMNode> startContainer, endContainer;
2219 PRInt32 startOffset = -1, endOffset = -1;
2220 aRange->GetStartContainer(getter_AddRefs(startContainer));
2221 aRange->GetStartOffset(&startOffset);
2222 aRange->GetEndContainer(getter_AddRefs(endContainer));
2223 aRange->GetEndOffset(&endOffset);
2224 NS_ENSURE_STATE(startContainer && endContainer);
2226 nsCOMPtr<nsIDOMNode> newStart = GetEqualNodeInCloneTree(startContainer, aDoc);
2227 nsCOMPtr<nsIDOMNode> newEnd = GetEqualNodeInCloneTree(endContainer, aDoc);
2228 NS_ENSURE_STATE(newStart && newEnd);
2230 nsCOMPtr<nsIDOMRange> range;
2231 NS_NewRange(getter_AddRefs(range));
2232 NS_ENSURE_TRUE(range, NS_ERROR_OUT_OF_MEMORY);
2234 nsresult rv = range->SetStart(newStart, startOffset);
2235 NS_ENSURE_SUCCESS(rv, rv);
2236 rv = range->SetEnd(newEnd, endOffset);
2237 NS_ENSURE_SUCCESS(rv, rv);
2239 return aSelection->AddRange(range);
2242 static nsresult CloneSelection(nsIDocument* aOrigDoc, nsIDocument* aDoc)
2244 nsIPresShell* origShell = aOrigDoc->GetPrimaryShell();
2245 nsIPresShell* shell = aDoc->GetPrimaryShell();
2246 NS_ENSURE_STATE(origShell && shell);
2248 nsCOMPtr<nsISelection> origSelection =
2249 origShell->GetCurrentSelection(nsISelectionController::SELECTION_NORMAL);
2250 nsCOMPtr<nsISelection> selection =
2251 shell->GetCurrentSelection(nsISelectionController::SELECTION_NORMAL);
2252 NS_ENSURE_STATE(origSelection && selection);
2254 PRInt32 rangeCount = 0;
2255 origSelection->GetRangeCount(&rangeCount);
2256 for (PRInt32 i = 0; i < rangeCount; ++i) {
2257 nsCOMPtr<nsIDOMRange> range;
2258 origSelection->GetRangeAt(i, getter_AddRefs(range));
2259 if (range) {
2260 CloneRangeToSelection(range, aDoc, selection);
2263 return NS_OK;
2266 //-------------------------------------------------------
2267 nsresult
2268 nsPrintEngine::DoPrint(nsPrintObject * aPO)
2270 PR_PL(("\n"));
2271 PR_PL(("**************************** %s ****************************\n", gFrameTypesStr[aPO->mFrameType]));
2272 PR_PL(("****** In DV::DoPrint PO: %p \n", aPO));
2274 nsIPresShell* poPresShell = aPO->mPresShell;
2275 nsPresContext* poPresContext = aPO->mPresContext;
2277 NS_ASSERTION(poPresContext, "PrintObject has not been reflowed");
2278 NS_ASSERTION(poPresContext->Type() != nsPresContext::eContext_PrintPreview,
2279 "How did this context end up here?");
2281 if (mPrt->mPrintProgressParams) {
2282 SetDocAndURLIntoProgress(aPO, mPrt->mPrintProgressParams);
2286 PRInt16 printRangeType = nsIPrintSettings::kRangeAllPages;
2287 nsresult rv;
2288 if (mPrt->mPrintSettings != nsnull) {
2289 mPrt->mPrintSettings->GetPrintRange(&printRangeType);
2292 // Ask the page sequence frame to print all the pages
2293 nsIPageSequenceFrame* pageSequence = poPresShell->GetPageSequenceFrame();
2294 NS_ASSERTION(nsnull != pageSequence, "no page sequence frame");
2296 // We are done preparing for printing, so we can turn this off
2297 mPrt->mPreparingForPrint = PR_FALSE;
2299 // mPrt->mDebugFilePtr this is onlu non-null when compiled for debugging
2300 if (nsnull != mPrt->mDebugFilePtr) {
2301 #ifdef NS_DEBUG
2302 // output the regression test
2303 nsIFrame* root = poPresShell->FrameManager()->GetRootFrame();
2304 root->DumpRegressionData(poPresContext, mPrt->mDebugFilePtr, 0);
2305 fclose(mPrt->mDebugFilePtr);
2306 SetIsPrinting(PR_FALSE);
2307 #endif
2308 } else {
2309 #ifdef EXTENDED_DEBUG_PRINTING
2310 nsIFrame* rootFrame = poPresShell->FrameManager()->GetRootFrame();
2311 if (aPO->IsPrintable()) {
2312 char * docStr;
2313 char * urlStr;
2314 GetDocTitleAndURL(aPO, docStr, urlStr);
2315 DumpLayoutData(docStr, urlStr, poPresContext, mPrt->mPrintDocDC, rootFrame, docShell, nsnull);
2316 if (docStr) nsMemory::Free(docStr);
2317 if (urlStr) nsMemory::Free(urlStr);
2319 #endif
2321 if (mPrt->mPrintSettings) {
2322 PRUnichar * docTitleStr = nsnull;
2323 PRUnichar * docURLStr = nsnull;
2325 GetDisplayTitleAndURL(aPO, &docTitleStr, &docURLStr, eDocTitleDefBlank);
2327 if (nsIPrintSettings::kRangeSelection == printRangeType) {
2328 CloneSelection(aPO->mDocument->GetOriginalDocument(), aPO->mDocument);
2330 poPresContext->SetIsRenderingOnlySelection(PR_TRUE);
2331 // temporarily creating rendering context
2332 // which is needed to dinf the selection frames
2333 nsCOMPtr<nsIRenderingContext> rc;
2334 mPrt->mPrintDC->CreateRenderingContext(*getter_AddRefs(rc));
2336 // find the starting and ending page numbers
2337 // via the selection
2338 nsIFrame* startFrame;
2339 nsIFrame* endFrame;
2340 PRInt32 startPageNum;
2341 PRInt32 endPageNum;
2342 nsRect startRect;
2343 nsRect endRect;
2345 nsCOMPtr<nsISelection> selectionPS;
2346 selectionPS = poPresShell->GetCurrentSelection(nsISelectionController::SELECTION_NORMAL);
2348 rv = GetPageRangeForSelection(poPresShell, poPresContext, *rc, selectionPS, pageSequence,
2349 &startFrame, startPageNum, startRect,
2350 &endFrame, endPageNum, endRect);
2351 if (NS_SUCCEEDED(rv)) {
2352 mPrt->mPrintSettings->SetStartPageRange(startPageNum);
2353 mPrt->mPrintSettings->SetEndPageRange(endPageNum);
2354 nsIntMargin marginTwips(0,0,0,0);
2355 nsIntMargin unwrtMarginTwips(0,0,0,0);
2356 mPrt->mPrintSettings->GetMarginInTwips(marginTwips);
2357 mPrt->mPrintSettings->GetUnwriteableMarginInTwips(unwrtMarginTwips);
2358 nsMargin totalMargin = poPresContext->TwipsToAppUnits(marginTwips +
2359 unwrtMarginTwips);
2360 if (startPageNum == endPageNum) {
2362 startRect.y -= totalMargin.top;
2363 endRect.y -= totalMargin.top;
2365 // Clip out selection regions above the top of the first page
2366 if (startRect.y < 0) {
2367 // Reduce height to be the height of the positive-territory
2368 // region of original rect
2369 startRect.height = NS_MAX(0, startRect.YMost());
2370 startRect.y = 0;
2372 if (endRect.y < 0) {
2373 // Reduce height to be the height of the positive-territory
2374 // region of original rect
2375 endRect.height = NS_MAX(0, endRect.YMost());
2376 endRect.y = 0;
2378 NS_ASSERTION(endRect.y >= startRect.y,
2379 "Selection end point should be after start point");
2380 NS_ASSERTION(startRect.height >= 0,
2381 "rect should have non-negative height.");
2382 NS_ASSERTION(endRect.height >= 0,
2383 "rect should have non-negative height.");
2385 nscoord selectionHgt = endRect.y + endRect.height - startRect.y;
2386 // XXX This is temporary fix for printing more than one page of a selection
2387 pageSequence->SetSelectionHeight(startRect.y * aPO->mZoomRatio,
2388 selectionHgt * aPO->mZoomRatio);
2390 // calc total pages by getting calculating the selection's height
2391 // and then dividing it by how page content frames will fit.
2392 nscoord pageWidth, pageHeight;
2393 mPrt->mPrintDC->GetDeviceSurfaceDimensions(pageWidth, pageHeight);
2394 pageHeight -= totalMargin.top + totalMargin.bottom;
2395 PRInt32 totalPages = NSToIntCeil(float(selectionHgt) * aPO->mZoomRatio / float(pageHeight));
2396 pageSequence->SetTotalNumPages(totalPages);
2402 nsIFrame * seqFrame = do_QueryFrame(pageSequence);
2403 if (!seqFrame) {
2404 SetIsPrinting(PR_FALSE);
2405 return NS_ERROR_FAILURE;
2408 mPageSeqFrame = pageSequence;
2409 mPageSeqFrame->StartPrint(poPresContext, mPrt->mPrintSettings, docTitleStr, docURLStr);
2411 // Schedule Page to Print
2412 PR_PL(("Scheduling Print of PO: %p (%s) \n", aPO, gFrameTypesStr[aPO->mFrameType]));
2413 StartPagePrintTimer(aPO);
2414 } else {
2415 // not sure what to do here!
2416 SetIsPrinting(PR_FALSE);
2417 return NS_ERROR_FAILURE;
2422 return NS_OK;
2425 //---------------------------------------------------------------------
2426 void
2427 nsPrintEngine::SetDocAndURLIntoProgress(nsPrintObject* aPO,
2428 nsIPrintProgressParams* aParams)
2430 NS_ASSERTION(aPO, "Must have vaild nsPrintObject");
2431 NS_ASSERTION(aParams, "Must have vaild nsIPrintProgressParams");
2433 if (!aPO || !aPO->mDocShell || !aParams) {
2434 return;
2436 const PRUint32 kTitleLength = 64;
2438 PRUnichar * docTitleStr;
2439 PRUnichar * docURLStr;
2440 GetDisplayTitleAndURL(aPO, &docTitleStr, &docURLStr, eDocTitleDefURLDoc);
2442 // Make sure the Titles & URLS don't get too long for the progress dialog
2443 ElipseLongString(docTitleStr, kTitleLength, PR_FALSE);
2444 ElipseLongString(docURLStr, kTitleLength, PR_TRUE);
2446 aParams->SetDocTitle(docTitleStr);
2447 aParams->SetDocURL(docURLStr);
2449 if (docTitleStr != nsnull) nsMemory::Free(docTitleStr);
2450 if (docURLStr != nsnull) nsMemory::Free(docURLStr);
2453 //---------------------------------------------------------------------
2454 void
2455 nsPrintEngine::ElipseLongString(PRUnichar *& aStr, const PRUint32 aLen, PRBool aDoFront)
2457 // Make sure the URLS don't get too long for the progress dialog
2458 if (aStr && nsCRT::strlen(aStr) > aLen) {
2459 if (aDoFront) {
2460 PRUnichar * ptr = &aStr[nsCRT::strlen(aStr)-aLen+3];
2461 nsAutoString newStr;
2462 newStr.AppendLiteral("...");
2463 newStr += ptr;
2464 nsMemory::Free(aStr);
2465 aStr = ToNewUnicode(newStr);
2466 } else {
2467 nsAutoString newStr(aStr);
2468 newStr.SetLength(aLen-3);
2469 newStr.AppendLiteral("...");
2470 nsMemory::Free(aStr);
2471 aStr = ToNewUnicode(newStr);
2476 //-------------------------------------------------------
2477 PRBool
2478 nsPrintEngine::PrintPage(nsPrintObject* aPO,
2479 PRBool& aInRange)
2481 NS_ASSERTION(aPO, "aPO is null!");
2482 NS_ASSERTION(mPageSeqFrame, "mPageSeqFrame is null!");
2483 NS_ASSERTION(mPrt, "mPrt is null!");
2485 // Although these should NEVER be NULL
2486 // This is added insurance, to make sure we don't crash in optimized builds
2487 if (!mPrt || !aPO || !mPageSeqFrame) {
2488 ShowPrintErrorDialog(NS_ERROR_FAILURE);
2489 return PR_TRUE; // means we are done printing
2492 PR_PL(("-----------------------------------\n"));
2493 PR_PL(("------ In DV::PrintPage PO: %p (%s)\n", aPO, gFrameTypesStr[aPO->mFrameType]));
2495 // Check setting to see if someone request it be cancelled
2496 PRBool isCancelled = PR_FALSE;
2497 mPrt->mPrintSettings->GetIsCancelled(&isCancelled);
2498 if (isCancelled)
2499 return PR_TRUE;
2501 PRInt32 pageNum, numPages, endPage;
2502 mPageSeqFrame->GetCurrentPageNum(&pageNum);
2503 mPageSeqFrame->GetNumPages(&numPages);
2505 PRBool donePrinting;
2506 PRBool isDoingPrintRange;
2507 mPageSeqFrame->IsDoingPrintRange(&isDoingPrintRange);
2508 if (isDoingPrintRange) {
2509 PRInt32 fromPage;
2510 PRInt32 toPage;
2511 mPageSeqFrame->GetPrintRange(&fromPage, &toPage);
2513 if (fromPage > numPages) {
2514 return PR_TRUE;
2516 if (toPage > numPages) {
2517 toPage = numPages;
2520 PR_PL(("****** Printing Page %d printing from %d to page %d\n", pageNum, fromPage, toPage));
2522 donePrinting = pageNum >= toPage;
2523 aInRange = pageNum >= fromPage && pageNum <= toPage;
2524 endPage = (toPage - fromPage)+1;
2525 } else {
2526 PR_PL(("****** Printing Page %d of %d page(s)\n", pageNum, numPages));
2528 donePrinting = pageNum >= numPages;
2529 endPage = numPages;
2530 aInRange = PR_TRUE;
2533 // XXX This is wrong, but the actual behavior in the presence of a print
2534 // range sucks.
2535 if (mPrt->mPrintFrameType == nsIPrintSettings::kEachFrameSep)
2536 endPage = mPrt->mNumPrintablePages;
2538 mPrt->DoOnProgressChange(++mPrt->mNumPagesPrinted, endPage, PR_FALSE, 0);
2540 // Print the Page
2541 // if a print job was cancelled externally, an EndPage or BeginPage may
2542 // fail and the failure is passed back here.
2543 // Returning PR_TRUE means we are done printing.
2545 // When rv == NS_ERROR_ABORT, it means we want out of the
2546 // print job without displaying any error messages
2547 nsresult rv = mPageSeqFrame->PrintNextPage();
2548 if (NS_FAILED(rv)) {
2549 if (rv != NS_ERROR_ABORT) {
2550 ShowPrintErrorDialog(rv);
2551 mPrt->mIsAborted = PR_TRUE;
2553 return PR_TRUE;
2556 mPageSeqFrame->DoPageEnd();
2558 return donePrinting;
2561 /** ---------------------------------------------------
2562 * Find by checking frames type
2564 nsresult
2565 nsPrintEngine::FindSelectionBoundsWithList(nsPresContext* aPresContext,
2566 nsIRenderingContext& aRC,
2567 nsIAtom* aList,
2568 nsIFrame * aParentFrame,
2569 nsRect& aRect,
2570 nsIFrame *& aStartFrame,
2571 nsRect& aStartRect,
2572 nsIFrame *& aEndFrame,
2573 nsRect& aEndRect)
2575 NS_ASSERTION(aPresContext, "Pointer is null!");
2576 NS_ASSERTION(aParentFrame, "Pointer is null!");
2578 nsIFrame* child = aParentFrame->GetFirstChild(aList);
2579 aRect += aParentFrame->GetPosition();
2580 while (child) {
2581 // only leaf frames have this bit flipped
2582 // then check the hard way
2583 PRBool isSelected = (child->GetStateBits() & NS_FRAME_SELECTED_CONTENT)
2584 == NS_FRAME_SELECTED_CONTENT;
2585 if (isSelected) {
2586 isSelected = child->IsVisibleForPainting();
2589 if (isSelected) {
2590 nsRect r = child->GetRect();
2591 if (aStartFrame == nsnull) {
2592 aStartFrame = child;
2593 aStartRect.SetRect(aRect.x + r.x, aRect.y + r.y, r.width, r.height);
2594 } else {
2595 aEndFrame = child;
2596 aEndRect.SetRect(aRect.x + r.x, aRect.y + r.y, r.width, r.height);
2599 FindSelectionBounds(aPresContext, aRC, child, aRect, aStartFrame, aStartRect, aEndFrame, aEndRect);
2600 child = child->GetNextSibling();
2602 aRect -= aParentFrame->GetPosition();
2603 return NS_OK;
2606 //-------------------------------------------------------
2607 // Find the Frame that is XMost
2608 nsresult
2609 nsPrintEngine::FindSelectionBounds(nsPresContext* aPresContext,
2610 nsIRenderingContext& aRC,
2611 nsIFrame * aParentFrame,
2612 nsRect& aRect,
2613 nsIFrame *& aStartFrame,
2614 nsRect& aStartRect,
2615 nsIFrame *& aEndFrame,
2616 nsRect& aEndRect)
2618 NS_ASSERTION(aPresContext, "Pointer is null!");
2619 NS_ASSERTION(aParentFrame, "Pointer is null!");
2621 // loop through named child lists
2622 nsIAtom* childListName = nsnull;
2623 PRInt32 childListIndex = 0;
2624 do {
2625 nsresult rv = FindSelectionBoundsWithList(aPresContext, aRC, childListName, aParentFrame, aRect, aStartFrame, aStartRect, aEndFrame, aEndRect);
2626 NS_ENSURE_SUCCESS(rv, rv);
2627 childListName = aParentFrame->GetAdditionalChildListName(childListIndex++);
2628 } while (childListName);
2629 return NS_OK;
2632 /** ---------------------------------------------------
2633 * This method finds the starting and ending page numbers
2634 * of the selection and also returns rect for each where
2635 * the x,y of the rect is relative to the very top of the
2636 * frame tree (absolutely positioned)
2638 nsresult
2639 nsPrintEngine::GetPageRangeForSelection(nsIPresShell * aPresShell,
2640 nsPresContext* aPresContext,
2641 nsIRenderingContext& aRC,
2642 nsISelection* aSelection,
2643 nsIPageSequenceFrame* aPageSeqFrame,
2644 nsIFrame** aStartFrame,
2645 PRInt32& aStartPageNum,
2646 nsRect& aStartRect,
2647 nsIFrame** aEndFrame,
2648 PRInt32& aEndPageNum,
2649 nsRect& aEndRect)
2651 NS_ASSERTION(aPresShell, "Pointer is null!");
2652 NS_ASSERTION(aPresContext, "Pointer is null!");
2653 NS_ASSERTION(aSelection, "Pointer is null!");
2654 NS_ASSERTION(aPageSeqFrame, "Pointer is null!");
2655 NS_ASSERTION(aStartFrame, "Pointer is null!");
2656 NS_ASSERTION(aEndFrame, "Pointer is null!");
2658 nsIFrame * seqFrame = do_QueryFrame(aPageSeqFrame);
2659 if (!seqFrame) {
2660 return NS_ERROR_FAILURE;
2663 nsIFrame * startFrame = nsnull;
2664 nsIFrame * endFrame = nsnull;
2666 // start out with the sequence frame and search the entire frame tree
2667 // capturing the starting and ending child frames of the selection
2668 // and their rects
2669 nsRect r = seqFrame->GetRect();
2670 FindSelectionBounds(aPresContext, aRC, seqFrame, r,
2671 startFrame, aStartRect, endFrame, aEndRect);
2673 #ifdef DEBUG_rodsX
2674 printf("Start Frame: %p\n", startFrame);
2675 printf("End Frame: %p\n", endFrame);
2676 #endif
2678 // initial the page numbers here
2679 // in case we don't find and frames
2680 aStartPageNum = -1;
2681 aEndPageNum = -1;
2683 nsIFrame * startPageFrame;
2684 nsIFrame * endPageFrame;
2686 // check to make sure we found a starting frame
2687 if (startFrame != nsnull) {
2688 // Now search up the tree to find what page the
2689 // start/ending selections frames are on
2691 // Check to see if start should be same as end if
2692 // the end frame comes back null
2693 if (endFrame == nsnull) {
2694 // XXX the "GetPageFrame" step could be integrated into
2695 // the FindSelectionBounds step, but walking up to find
2696 // the parent of a child frame isn't expensive and it makes
2697 // FindSelectionBounds a little easier to understand
2698 startPageFrame = nsLayoutUtils::GetPageFrame(startFrame);
2699 endPageFrame = startPageFrame;
2700 aEndRect = aStartRect;
2701 } else {
2702 startPageFrame = nsLayoutUtils::GetPageFrame(startFrame);
2703 endPageFrame = nsLayoutUtils::GetPageFrame(endFrame);
2705 } else {
2706 return NS_ERROR_FAILURE;
2709 #ifdef DEBUG_rodsX
2710 printf("Start Page: %p\n", startPageFrame);
2711 printf("End Page: %p\n", endPageFrame);
2713 // dump all the pages and their pointers
2715 PRInt32 pageNum = 1;
2716 nsIFrame* child = seqFrame->GetFirstChild(nsnull);
2717 while (child != nsnull) {
2718 printf("Page: %d - %p\n", pageNum, child);
2719 pageNum++;
2720 child = child->GetNextSibling();
2723 #endif
2725 // Now that we have the page frames
2726 // find out what the page numbers are for each frame
2727 PRInt32 pageNum = 1;
2728 nsIFrame* page = seqFrame->GetFirstChild(nsnull);
2729 while (page != nsnull) {
2730 if (page == startPageFrame) {
2731 aStartPageNum = pageNum;
2733 if (page == endPageFrame) {
2734 aEndPageNum = pageNum;
2736 pageNum++;
2737 page = page->GetNextSibling();
2740 #ifdef DEBUG_rodsX
2741 printf("Start Page No: %d\n", aStartPageNum);
2742 printf("End Page No: %d\n", aEndPageNum);
2743 #endif
2745 *aStartFrame = startPageFrame;
2746 *aEndFrame = endPageFrame;
2748 return NS_OK;
2751 //-----------------------------------------------------------------
2752 //-- Done: Printing Methods
2753 //-----------------------------------------------------------------
2756 //-----------------------------------------------------------------
2757 //-- Section: Misc Support Methods
2758 //-----------------------------------------------------------------
2760 //---------------------------------------------------------------------
2761 void nsPrintEngine::SetIsPrinting(PRBool aIsPrinting)
2763 mIsDoingPrinting = aIsPrinting;
2764 // Calling SetIsPrinting while in print preview confuses the document viewer
2765 // This is safe because we prevent exiting print preview while printing
2766 if (mDocViewerPrint && !mIsDoingPrintPreview) {
2767 mDocViewerPrint->SetIsPrinting(aIsPrinting);
2769 if (mPrt && aIsPrinting) {
2770 mPrt->mPreparingForPrint = PR_TRUE;
2774 //---------------------------------------------------------------------
2775 void nsPrintEngine::SetIsPrintPreview(PRBool aIsPrintPreview)
2777 mIsDoingPrintPreview = aIsPrintPreview;
2779 if (mDocViewerPrint) {
2780 mDocViewerPrint->SetIsPrintPreview(aIsPrintPreview);
2784 //---------------------------------------------------------------------
2785 void
2786 nsPrintEngine::CleanupDocTitleArray(PRUnichar**& aArray, PRInt32& aCount)
2788 for (PRInt32 i = aCount - 1; i >= 0; i--) {
2789 nsMemory::Free(aArray[i]);
2791 nsMemory::Free(aArray);
2792 aArray = NULL;
2793 aCount = 0;
2796 //---------------------------------------------------------------------
2797 // static
2798 PRBool nsPrintEngine::HasFramesetChild(nsIContent* aContent)
2800 if (!aContent) {
2801 return PR_FALSE;
2804 PRUint32 numChildren = aContent->GetChildCount();
2806 // do a breadth search across all siblings
2807 for (PRUint32 i = 0; i < numChildren; ++i) {
2808 nsIContent *child = aContent->GetChildAt(i);
2809 if (child->Tag() == nsGkAtoms::frameset &&
2810 child->IsHTML()) {
2811 return PR_TRUE;
2815 return PR_FALSE;
2820 /** ---------------------------------------------------
2821 * Get the Focused Frame for a documentviewer
2823 already_AddRefed<nsIDOMWindow>
2824 nsPrintEngine::FindFocusedDOMWindow()
2826 nsIFocusManager* fm = nsFocusManager::GetFocusManager();
2827 NS_ENSURE_TRUE(fm, nsnull);
2829 nsCOMPtr<nsPIDOMWindow> window(mDocument->GetWindow());
2830 NS_ENSURE_TRUE(window, nsnull);
2832 nsCOMPtr<nsPIDOMWindow> rootWindow = window->GetPrivateRoot();
2833 NS_ENSURE_TRUE(rootWindow, nsnull);
2835 nsPIDOMWindow* focusedWindow;
2836 nsFocusManager::GetFocusedDescendant(rootWindow, PR_TRUE, &focusedWindow);
2837 NS_ENSURE_TRUE(focusedWindow, nsnull);
2839 if (IsWindowsInOurSubTree(focusedWindow)) {
2840 return focusedWindow;
2843 NS_IF_RELEASE(focusedWindow);
2844 return nsnull;
2847 //---------------------------------------------------------------------
2848 PRBool
2849 nsPrintEngine::IsWindowsInOurSubTree(nsPIDOMWindow * window)
2851 PRBool found = PR_FALSE;
2853 // now check to make sure it is in "our" tree of docshells
2854 if (window) {
2855 nsCOMPtr<nsIDocShellTreeItem> docShellAsItem =
2856 do_QueryInterface(window->GetDocShell());
2858 if (docShellAsItem) {
2859 // get this DocViewer docshell
2860 nsCOMPtr<nsIDocShell> thisDVDocShell(do_QueryInterface(mContainer));
2861 while (!found) {
2862 nsCOMPtr<nsIDocShell> parentDocshell(do_QueryInterface(docShellAsItem));
2863 if (parentDocshell) {
2864 if (parentDocshell == thisDVDocShell) {
2865 found = PR_TRUE;
2866 break;
2868 } else {
2869 break; // at top of tree
2871 nsCOMPtr<nsIDocShellTreeItem> docShellParent;
2872 docShellAsItem->GetSameTypeParent(getter_AddRefs(docShellParent));
2873 docShellAsItem = docShellParent;
2874 } // while
2876 } // scriptobj
2878 return found;
2881 //-------------------------------------------------------
2882 PRBool
2883 nsPrintEngine::DonePrintingPages(nsPrintObject* aPO, nsresult aResult)
2885 //NS_ASSERTION(aPO, "Pointer is null!");
2886 PR_PL(("****** In DV::DonePrintingPages PO: %p (%s)\n", aPO, aPO?gFrameTypesStr[aPO->mFrameType]:""));
2888 if (aPO != nsnull) {
2889 aPO->mHasBeenPrinted = PR_TRUE;
2890 nsresult rv;
2891 PRBool didPrint = PrintDocContent(mPrt->mPrintObject, rv);
2892 if (NS_SUCCEEDED(rv) && didPrint) {
2893 PR_PL(("****** In DV::DonePrintingPages PO: %p (%s) didPrint:%s (Not Done Printing)\n", aPO, gFrameTypesStr[aPO->mFrameType], PRT_YESNO(didPrint)));
2894 return PR_FALSE;
2898 if (NS_SUCCEEDED(aResult)) {
2899 FirePrintCompletionEvent();
2902 TurnScriptingOn(PR_TRUE);
2903 SetIsPrinting(PR_FALSE);
2905 // Release reference to mPagePrintTimer; the timer object destroys itself
2906 // after this returns true
2907 NS_IF_RELEASE(mPagePrintTimer);
2909 return PR_TRUE;
2912 //-------------------------------------------------------
2913 // Recursively sets the PO items to be printed "As Is"
2914 // from the given item down into the tree
2915 void
2916 nsPrintEngine::SetPrintAsIs(nsPrintObject* aPO, PRBool aAsIs)
2918 NS_ASSERTION(aPO, "Pointer is null!");
2920 aPO->mPrintAsIs = aAsIs;
2921 for (PRUint32 i=0;i<aPO->mKids.Length();i++) {
2922 SetPrintAsIs(aPO->mKids[i], aAsIs);
2926 //-------------------------------------------------------
2927 // Given a DOMWindow it recursively finds the PO object that matches
2928 nsPrintObject*
2929 nsPrintEngine::FindPrintObjectByDOMWin(nsPrintObject* aPO,
2930 nsIDOMWindow* aDOMWin)
2932 NS_ASSERTION(aPO, "Pointer is null!");
2934 // Often the CurFocused DOMWindow is passed in
2935 // andit is valid for it to be null, so short circut
2936 if (!aDOMWin) {
2937 return nsnull;
2940 nsCOMPtr<nsIDOMDocument> domDoc;
2941 aDOMWin->GetDocument(getter_AddRefs(domDoc));
2942 nsCOMPtr<nsIDocument> doc = do_QueryInterface(domDoc);
2943 if (aPO->mDocument && aPO->mDocument->GetOriginalDocument() == doc) {
2944 return aPO;
2947 PRInt32 cnt = aPO->mKids.Length();
2948 for (PRInt32 i = 0; i < cnt; ++i) {
2949 nsPrintObject* po = FindPrintObjectByDOMWin(aPO->mKids[i], aDOMWin);
2950 if (po) {
2951 return po;
2955 return nsnull;
2958 //-------------------------------------------------------
2959 nsresult
2960 nsPrintEngine::EnablePOsForPrinting()
2962 // NOTE: All POs have been "turned off" for printing
2963 // this is where we decided which POs get printed.
2964 mPrt->mSelectedPO = nsnull;
2966 if (mPrt->mPrintSettings == nsnull) {
2967 return NS_ERROR_FAILURE;
2970 mPrt->mPrintFrameType = nsIPrintSettings::kNoFrames;
2971 mPrt->mPrintSettings->GetPrintFrameType(&mPrt->mPrintFrameType);
2973 PRInt16 printHowEnable = nsIPrintSettings::kFrameEnableNone;
2974 mPrt->mPrintSettings->GetHowToEnableFrameUI(&printHowEnable);
2976 PRInt16 printRangeType = nsIPrintSettings::kRangeAllPages;
2977 mPrt->mPrintSettings->GetPrintRange(&printRangeType);
2979 PR_PL(("\n"));
2980 PR_PL(("********* nsPrintEngine::EnablePOsForPrinting *********\n"));
2981 PR_PL(("PrintFrameType: %s \n", gPrintFrameTypeStr[mPrt->mPrintFrameType]));
2982 PR_PL(("HowToEnableFrameUI: %s \n", gFrameHowToEnableStr[printHowEnable]));
2983 PR_PL(("PrintRange: %s \n", gPrintRangeStr[printRangeType]));
2984 PR_PL(("----\n"));
2986 // ***** This is the ultimate override *****
2987 // if we are printing the selection (either an IFrame or selection range)
2988 // then set the mPrintFrameType as if it were the selected frame
2989 if (printRangeType == nsIPrintSettings::kRangeSelection) {
2990 mPrt->mPrintFrameType = nsIPrintSettings::kSelectedFrame;
2991 printHowEnable = nsIPrintSettings::kFrameEnableNone;
2994 // This tells us that the "Frame" UI has turned off,
2995 // so therefore there are no FrameSets/Frames/IFrames to be printed
2997 // This means there are not FrameSets,
2998 // but the document could contain an IFrame
2999 if (printHowEnable == nsIPrintSettings::kFrameEnableNone) {
3001 // Print all the pages or a sub range of pages
3002 if (printRangeType == nsIPrintSettings::kRangeAllPages ||
3003 printRangeType == nsIPrintSettings::kRangeSpecifiedPageRange) {
3004 SetPrintPO(mPrt->mPrintObject, PR_TRUE);
3006 // Set the children so they are PrinAsIs
3007 // In this case, the children are probably IFrames
3008 if (mPrt->mPrintObject->mKids.Length() > 0) {
3009 for (PRUint32 i=0;i<mPrt->mPrintObject->mKids.Length();i++) {
3010 nsPrintObject* po = mPrt->mPrintObject->mKids[i];
3011 NS_ASSERTION(po, "nsPrintObject can't be null!");
3012 SetPrintAsIs(po);
3015 // ***** Another override *****
3016 mPrt->mPrintFrameType = nsIPrintSettings::kFramesAsIs;
3018 PR_PL(("PrintFrameType: %s \n", gPrintFrameTypeStr[mPrt->mPrintFrameType]));
3019 PR_PL(("HowToEnableFrameUI: %s \n", gFrameHowToEnableStr[printHowEnable]));
3020 PR_PL(("PrintRange: %s \n", gPrintRangeStr[printRangeType]));
3021 return NS_OK;
3024 // This means we are either printed a selected IFrame or
3025 // we are printing the current selection
3026 if (printRangeType == nsIPrintSettings::kRangeSelection) {
3028 // If the currentFocusDOMWin can'r be null if something is selected
3029 if (mPrt->mCurrentFocusWin) {
3030 // Find the selected IFrame
3031 nsPrintObject * po = FindPrintObjectByDOMWin(mPrt->mPrintObject, mPrt->mCurrentFocusWin);
3032 if (po != nsnull) {
3033 mPrt->mSelectedPO = po;
3034 // Makes sure all of its children are be printed "AsIs"
3035 SetPrintAsIs(po);
3037 // Now, only enable this POs (the selected PO) and all of its children
3038 SetPrintPO(po, PR_TRUE);
3040 // check to see if we have a range selection,
3041 // as oppose to a insert selection
3042 // this means if the user just clicked on the IFrame then
3043 // there will not be a selection so we want the entire page to print
3045 // XXX this is sort of a hack right here to make the page
3046 // not try to reposition itself when printing selection
3047 nsCOMPtr<nsIDOMWindow> domWin =
3048 do_QueryInterface(po->mDocument->GetOriginalDocument()->GetWindow());
3049 if (!IsThereARangeSelection(domWin)) {
3050 printRangeType = nsIPrintSettings::kRangeAllPages;
3051 mPrt->mPrintSettings->SetPrintRange(printRangeType);
3053 PR_PL(("PrintFrameType: %s \n", gPrintFrameTypeStr[mPrt->mPrintFrameType]));
3054 PR_PL(("HowToEnableFrameUI: %s \n", gFrameHowToEnableStr[printHowEnable]));
3055 PR_PL(("PrintRange: %s \n", gPrintRangeStr[printRangeType]));
3056 return NS_OK;
3058 } else {
3059 for (PRUint32 i=0;i<mPrt->mPrintDocList.Length();i++) {
3060 nsPrintObject* po = mPrt->mPrintDocList.ElementAt(i);
3061 NS_ASSERTION(po, "nsPrintObject can't be null!");
3062 nsCOMPtr<nsIDOMWindow> domWin = do_GetInterface(po->mDocShell);
3063 if (IsThereARangeSelection(domWin)) {
3064 mPrt->mCurrentFocusWin = domWin;
3065 SetPrintPO(po, PR_TRUE);
3066 break;
3069 return NS_OK;
3074 // check to see if there is a selection when a FrameSet is present
3075 if (printRangeType == nsIPrintSettings::kRangeSelection) {
3076 // If the currentFocusDOMWin can'r be null if something is selected
3077 if (mPrt->mCurrentFocusWin) {
3078 // Find the selected IFrame
3079 nsPrintObject * po = FindPrintObjectByDOMWin(mPrt->mPrintObject, mPrt->mCurrentFocusWin);
3080 if (po != nsnull) {
3081 mPrt->mSelectedPO = po;
3082 // Makes sure all of its children are be printed "AsIs"
3083 SetPrintAsIs(po);
3085 // Now, only enable this POs (the selected PO) and all of its children
3086 SetPrintPO(po, PR_TRUE);
3088 // check to see if we have a range selection,
3089 // as oppose to a insert selection
3090 // this means if the user just clicked on the IFrame then
3091 // there will not be a selection so we want the entire page to print
3093 // XXX this is sort of a hack right here to make the page
3094 // not try to reposition itself when printing selection
3095 nsCOMPtr<nsIDOMWindow> domWin =
3096 do_QueryInterface(po->mDocument->GetOriginalDocument()->GetWindow());
3097 if (!IsThereARangeSelection(domWin)) {
3098 printRangeType = nsIPrintSettings::kRangeAllPages;
3099 mPrt->mPrintSettings->SetPrintRange(printRangeType);
3101 PR_PL(("PrintFrameType: %s \n", gPrintFrameTypeStr[mPrt->mPrintFrameType]));
3102 PR_PL(("HowToEnableFrameUI: %s \n", gFrameHowToEnableStr[printHowEnable]));
3103 PR_PL(("PrintRange: %s \n", gPrintRangeStr[printRangeType]));
3104 return NS_OK;
3109 // If we are printing "AsIs" then sets all the POs to be printed as is
3110 if (mPrt->mPrintFrameType == nsIPrintSettings::kFramesAsIs) {
3111 SetPrintAsIs(mPrt->mPrintObject);
3112 SetPrintPO(mPrt->mPrintObject, PR_TRUE);
3113 return NS_OK;
3116 // If we are printing the selected Frame then
3117 // find that PO for that selected DOMWin and set it all of its
3118 // children to be printed
3119 if (mPrt->mPrintFrameType == nsIPrintSettings::kSelectedFrame) {
3121 if ((mPrt->mIsParentAFrameSet && mPrt->mCurrentFocusWin) || mPrt->mIsIFrameSelected) {
3122 nsPrintObject * po = FindPrintObjectByDOMWin(mPrt->mPrintObject, mPrt->mCurrentFocusWin);
3123 if (po != nsnull) {
3124 mPrt->mSelectedPO = po;
3125 // NOTE: Calling this sets the "po" and
3126 // we don't want to do this for documents that have no children,
3127 // because then the "DoEndPage" gets called and it shouldn't
3128 if (po->mKids.Length() > 0) {
3129 // Makes sure that itself, and all of its children are printed "AsIs"
3130 SetPrintAsIs(po);
3133 // Now, only enable this POs (the selected PO) and all of its children
3134 SetPrintPO(po, PR_TRUE);
3137 return NS_OK;
3140 // If we are print each subdoc separately,
3141 // then don't print any of the FraneSet Docs
3142 if (mPrt->mPrintFrameType == nsIPrintSettings::kEachFrameSep) {
3143 SetPrintPO(mPrt->mPrintObject, PR_TRUE);
3144 PRInt32 cnt = mPrt->mPrintDocList.Length();
3145 for (PRInt32 i=0;i<cnt;i++) {
3146 nsPrintObject* po = mPrt->mPrintDocList.ElementAt(i);
3147 NS_ASSERTION(po, "nsPrintObject can't be null!");
3148 if (po->mFrameType == eFrameSet) {
3149 po->mDontPrint = PR_TRUE;
3154 return NS_OK;
3157 //-------------------------------------------------------
3158 // Return the nsPrintObject with that is XMost (The widest frameset frame) AND
3159 // contains the XMost (widest) layout frame
3160 nsPrintObject*
3161 nsPrintEngine::FindSmallestSTF()
3163 float smallestRatio = 1.0f;
3164 nsPrintObject* smallestPO = nsnull;
3166 for (PRUint32 i=0;i<mPrt->mPrintDocList.Length();i++) {
3167 nsPrintObject* po = mPrt->mPrintDocList.ElementAt(i);
3168 NS_ASSERTION(po, "nsPrintObject can't be null!");
3169 if (po->mFrameType != eFrameSet && po->mFrameType != eIFrame) {
3170 if (po->mShrinkRatio < smallestRatio) {
3171 smallestRatio = po->mShrinkRatio;
3172 smallestPO = po;
3177 #ifdef EXTENDED_DEBUG_PRINTING
3178 if (smallestPO) printf("*PO: %p Type: %d %10.3f\n", smallestPO, smallestPO->mFrameType, smallestPO->mShrinkRatio);
3179 #endif
3180 return smallestPO;
3183 //-------------------------------------------------------
3184 void
3185 nsPrintEngine::TurnScriptingOn(PRBool aDoTurnOn)
3187 if (mIsDoingPrinting && aDoTurnOn && mDocViewerPrint &&
3188 mDocViewerPrint->GetIsPrintPreview()) {
3189 // We don't want to turn scripting on if print preview is shown still after
3190 // printing.
3191 return;
3194 nsPrintData* prt = mPrt;
3195 #ifdef NS_PRINT_PREVIEW
3196 if (!prt) {
3197 prt = mPrtPreview;
3199 #endif
3200 if (!prt) {
3201 return;
3204 NS_ASSERTION(mDocument, "We MUST have a document.");
3205 // First, get the script global object from the document...
3207 for (PRUint32 i=0;i<prt->mPrintDocList.Length();i++) {
3208 nsPrintObject* po = prt->mPrintDocList.ElementAt(i);
3209 NS_ASSERTION(po, "nsPrintObject can't be null!");
3211 nsIDocument* doc = po->mDocument;
3212 if (!doc) {
3213 continue;
3216 // get the script global object
3217 nsIScriptGlobalObject *scriptGlobalObj = doc->GetScriptGlobalObject();
3219 if (scriptGlobalObj) {
3220 nsCOMPtr<nsPIDOMWindow> window = do_QueryInterface(scriptGlobalObj);
3221 NS_ASSERTION(window, "Can't get nsPIDOMWindow");
3222 nsIScriptContext *scx = scriptGlobalObj->GetContext();
3223 NS_WARN_IF_FALSE(scx, "Can't get nsIScriptContext");
3224 nsresult propThere = NS_PROPTABLE_PROP_NOT_THERE;
3225 doc->GetProperty(nsGkAtoms::scriptEnabledBeforePrintOrPreview,
3226 &propThere);
3227 if (aDoTurnOn) {
3228 if (propThere != NS_PROPTABLE_PROP_NOT_THERE) {
3229 doc->DeleteProperty(nsGkAtoms::scriptEnabledBeforePrintOrPreview);
3230 if (scx) {
3231 scx->SetScriptsEnabled(PR_TRUE, PR_FALSE);
3233 window->ResumeTimeouts(PR_FALSE);
3235 } else {
3236 // Have to be careful, because people call us over and over again with
3237 // aDoTurnOn == PR_FALSE. So don't set the property if it's already
3238 // set, since in that case we'd set it to the wrong value.
3239 if (propThere == NS_PROPTABLE_PROP_NOT_THERE) {
3240 // Stash the current value of IsScriptEnabled on the document, so
3241 // that layout code running in print preview doesn't get confused.
3242 doc->SetProperty(nsGkAtoms::scriptEnabledBeforePrintOrPreview,
3243 NS_INT32_TO_PTR(doc->IsScriptEnabled()));
3244 if (scx) {
3245 scx->SetScriptsEnabled(PR_FALSE, PR_FALSE);
3247 window->SuspendTimeouts(1, PR_FALSE);
3254 //-----------------------------------------------------------------
3255 //-- Done: Misc Support Methods
3256 //-----------------------------------------------------------------
3259 //-----------------------------------------------------------------
3260 //-- Section: Finishing up or Cleaning up
3261 //-----------------------------------------------------------------
3263 //-----------------------------------------------------------------
3264 void
3265 nsPrintEngine::CloseProgressDialog(nsIWebProgressListener* aWebProgressListener)
3267 if (aWebProgressListener) {
3268 aWebProgressListener->OnStateChange(nsnull, nsnull, nsIWebProgressListener::STATE_STOP|nsIWebProgressListener::STATE_IS_DOCUMENT, nsnull);
3272 //-----------------------------------------------------------------
3273 nsresult
3274 nsPrintEngine::FinishPrintPreview()
3276 nsresult rv = NS_OK;
3278 #ifdef NS_PRINT_PREVIEW
3280 if (!mPrt) {
3281 /* we're already finished with print preview */
3282 return rv;
3285 rv = DocumentReadyForPrinting();
3287 SetIsCreatingPrintPreview(PR_FALSE);
3289 /* cleaup on failure + notify user */
3290 if (NS_FAILED(rv)) {
3291 /* cleanup done, let's fire-up an error dialog to notify the user
3292 * what went wrong...
3294 mPrt->OnEndPrinting();
3295 TurnScriptingOn(PR_TRUE);
3297 return rv;
3300 // At this point we are done preparing everything
3301 // before it is to be created
3304 if (mIsDoingPrintPreview && mOldPrtPreview) {
3305 delete mOldPrtPreview;
3306 mOldPrtPreview = nsnull;
3309 InstallPrintPreviewListener();
3311 mPrt->OnEndPrinting();
3313 // PrintPreview was built using the mPrt (code reuse)
3314 // then we assign it over
3315 mPrtPreview = mPrt;
3316 mPrt = nsnull;
3318 #endif // NS_PRINT_PREVIEW
3320 return NS_OK;
3323 //-----------------------------------------------------------------
3324 //-- Done: Finishing up or Cleaning up
3325 //-----------------------------------------------------------------
3328 /*=============== Timer Related Code ======================*/
3329 nsresult
3330 nsPrintEngine::StartPagePrintTimer(nsPrintObject* aPO)
3332 if (!mPagePrintTimer) {
3333 nsresult rv = NS_NewPagePrintTimer(&mPagePrintTimer);
3334 NS_ENSURE_SUCCESS(rv, rv);
3336 // Get the delay time in between the printing of each page
3337 // this gives the user more time to press cancel
3338 PRInt32 printPageDelay = 50;
3339 mPrt->mPrintSettings->GetPrintPageDelay(&printPageDelay);
3341 mPagePrintTimer->Init(this, mDocViewerPrint, printPageDelay);
3344 return mPagePrintTimer->Start(aPO);
3347 /*=============== nsIObserver Interface ======================*/
3348 NS_IMETHODIMP
3349 nsPrintEngine::Observe(nsISupports *aSubject, const char *aTopic, const PRUnichar *aData)
3351 nsresult rv = NS_ERROR_FAILURE;
3353 if (mIsDoingPrinting) {
3354 rv = DocumentReadyForPrinting();
3356 /* cleaup on failure + notify user */
3357 if (NS_FAILED(rv)) {
3358 CleanupOnFailure(rv, PR_TRUE);
3360 } else {
3361 rv = FinishPrintPreview();
3362 if (NS_FAILED(rv)) {
3363 CleanupOnFailure(rv, PR_FALSE);
3365 if (mPrtPreview) {
3366 mPrtPreview->OnEndPrinting();
3368 rv = NS_OK;
3371 return rv;
3375 //---------------------------------------------------------------
3376 //-- PLEvent Notification
3377 //---------------------------------------------------------------
3378 class nsPrintCompletionEvent : public nsRunnable {
3379 public:
3380 nsPrintCompletionEvent(nsIDocumentViewerPrint *docViewerPrint)
3381 : mDocViewerPrint(docViewerPrint) {
3382 NS_ASSERTION(mDocViewerPrint, "mDocViewerPrint is null.");
3385 NS_IMETHOD Run() {
3386 if (mDocViewerPrint)
3387 mDocViewerPrint->OnDonePrinting();
3388 return NS_OK;
3391 private:
3392 nsCOMPtr<nsIDocumentViewerPrint> mDocViewerPrint;
3395 //-----------------------------------------------------------
3396 void
3397 nsPrintEngine::FirePrintCompletionEvent()
3399 nsCOMPtr<nsIRunnable> event = new nsPrintCompletionEvent(mDocViewerPrint);
3400 if (NS_FAILED(NS_DispatchToCurrentThread(event)))
3401 NS_WARNING("failed to dispatch print completion event");
3404 //---------------------------------------------------------------
3405 //---------------------------------------------------------------
3406 //-- Debug helper routines
3407 //---------------------------------------------------------------
3408 //---------------------------------------------------------------
3409 #if (defined(XP_WIN) || defined(XP_OS2)) && defined(EXTENDED_DEBUG_PRINTING)
3410 #include "windows.h"
3411 #include "process.h"
3412 #include "direct.h"
3414 #define MY_FINDFIRST(a,b) FindFirstFile(a,b)
3415 #define MY_FINDNEXT(a,b) FindNextFile(a,b)
3416 #define ISDIR(a) (a.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
3417 #define MY_FINDCLOSE(a) FindClose(a)
3418 #define MY_FILENAME(a) a.cFileName
3419 #define MY_FILESIZE(a) (a.nFileSizeHigh * MAXDWORD) + a.nFileSizeLow
3421 int RemoveFilesInDir(const char * aDir)
3423 WIN32_FIND_DATA data_ptr;
3424 HANDLE find_handle;
3426 char path[MAX_PATH];
3428 strcpy(path, aDir);
3430 // Append slash to the end of the directory names if not there
3431 if (path[strlen(path)-1] != '\\')
3432 strcat(path, "\\");
3434 char findPath[MAX_PATH];
3435 strcpy(findPath, path);
3436 strcat(findPath, "*.*");
3438 find_handle = MY_FINDFIRST(findPath, &data_ptr);
3440 if (find_handle != INVALID_HANDLE_VALUE) {
3441 do {
3442 if (ISDIR(data_ptr)
3443 && (stricmp(MY_FILENAME(data_ptr),"."))
3444 && (stricmp(MY_FILENAME(data_ptr),".."))) {
3445 // skip
3447 else if (!ISDIR(data_ptr)) {
3448 if (!strncmp(MY_FILENAME(data_ptr), "print_dump", 10)) {
3449 char fileName[MAX_PATH];
3450 strcpy(fileName, aDir);
3451 strcat(fileName, "\\");
3452 strcat(fileName, MY_FILENAME(data_ptr));
3453 printf("Removing %s\n", fileName);
3454 remove(fileName);
3457 } while(MY_FINDNEXT(find_handle,&data_ptr));
3458 MY_FINDCLOSE(find_handle);
3460 return TRUE;
3462 #endif
3464 #ifdef EXTENDED_DEBUG_PRINTING
3466 /** ---------------------------------------------------
3467 * Dumps Frames for Printing
3469 static void RootFrameList(nsPresContext* aPresContext, FILE* out, PRInt32 aIndent)
3471 if (!aPresContext || !out)
3472 return;
3474 nsIPresShell *shell = aPresContext->GetPresShell();
3475 if (shell) {
3476 nsIFrame* frame = shell->FrameManager()->GetRootFrame();
3477 if (frame) {
3478 frame->List(aPresContext, out, aIndent);
3483 /** ---------------------------------------------------
3484 * Dumps Frames for Printing
3486 static void DumpFrames(FILE* out,
3487 nsPresContext* aPresContext,
3488 nsIRenderingContext * aRendContext,
3489 nsIFrame * aFrame,
3490 PRInt32 aLevel)
3492 NS_ASSERTION(out, "Pointer is null!");
3493 NS_ASSERTION(aPresContext, "Pointer is null!");
3494 NS_ASSERTION(aRendContext, "Pointer is null!");
3495 NS_ASSERTION(aFrame, "Pointer is null!");
3497 nsIFrame* child = aFrame->GetFirstChild(nsnull);
3498 while (child != nsnull) {
3499 for (PRInt32 i=0;i<aLevel;i++) {
3500 fprintf(out, " ");
3502 nsAutoString tmp;
3503 child->GetFrameName(tmp);
3504 fputs(NS_LossyConvertUTF16toASCII(tmp).get(), out);
3505 PRBool isSelected;
3506 if (NS_SUCCEEDED(child->IsVisibleForPainting(aPresContext, *aRendContext, PR_TRUE, &isSelected))) {
3507 fprintf(out, " %p %s", child, isSelected?"VIS":"UVS");
3508 nsRect rect = child->GetRect();
3509 fprintf(out, "[%d,%d,%d,%d] ", rect.x, rect.y, rect.width, rect.height);
3510 fprintf(out, "v: %p ", (void*)child->GetView());
3511 fprintf(out, "\n");
3512 DumpFrames(out, aPresContext, aRendContext, child, aLevel+1);
3513 child = child->GetNextSibling();
3519 /** ---------------------------------------------------
3520 * Dumps the Views from the DocShell
3522 static void
3523 DumpViews(nsIDocShell* aDocShell, FILE* out)
3525 NS_ASSERTION(aDocShell, "Pointer is null!");
3526 NS_ASSERTION(out, "Pointer is null!");
3528 if (nsnull != aDocShell) {
3529 fprintf(out, "docshell=%p \n", aDocShell);
3530 nsIPresShell* shell = nsPrintEngine::GetPresShellFor(aDocShell);
3531 if (shell) {
3532 nsIViewManager* vm = shell->GetViewManager();
3533 if (vm) {
3534 nsIView* root;
3535 vm->GetRootView(root);
3536 if (nsnull != root) {
3537 root->List(out);
3541 else {
3542 fputs("null pres shell\n", out);
3545 // dump the views of the sub documents
3546 PRInt32 i, n;
3547 nsCOMPtr<nsIDocShellTreeNode> docShellAsNode(do_QueryInterface(aDocShell));
3548 docShellAsNode->GetChildCount(&n);
3549 for (i = 0; i < n; i++) {
3550 nsCOMPtr<nsIDocShellTreeItem> child;
3551 docShellAsNode->GetChildAt(i, getter_AddRefs(child));
3552 nsCOMPtr<nsIDocShell> childAsShell(do_QueryInterface(child));
3553 if (childAsShell) {
3554 DumpViews(childAsShell, out);
3560 /** ---------------------------------------------------
3561 * Dumps the Views and Frames
3563 void DumpLayoutData(char* aTitleStr,
3564 char* aURLStr,
3565 nsPresContext* aPresContext,
3566 nsIDeviceContext * aDC,
3567 nsIFrame * aRootFrame,
3568 nsIDocShekk * aDocShell,
3569 FILE* aFD = nsnull)
3571 if (!kPrintingLogMod || kPrintingLogMod->level != DUMP_LAYOUT_LEVEL) return;
3573 if (aPresContext == nsnull || aDC == nsnull) {
3574 return;
3577 #ifdef NS_PRINT_PREVIEW
3578 if (aPresContext->Type() == nsPresContext::eContext_PrintPreview) {
3579 return;
3581 #endif
3583 NS_ASSERTION(aRootFrame, "Pointer is null!");
3584 NS_ASSERTION(aDocShell, "Pointer is null!");
3586 // Dump all the frames and view to a a file
3587 char filename[256];
3588 sprintf(filename, "print_dump_layout_%d.txt", gDumpLOFileNameCnt++);
3589 FILE * fd = aFD?aFD:fopen(filename, "w");
3590 if (fd) {
3591 fprintf(fd, "Title: %s\n", aTitleStr?aTitleStr:"");
3592 fprintf(fd, "URL: %s\n", aURLStr?aURLStr:"");
3593 fprintf(fd, "--------------- Frames ----------------\n");
3594 fprintf(fd, "--------------- Frames ----------------\n");
3595 nsCOMPtr<nsIRenderingContext> renderingContext;
3596 aDC->CreateRenderingContext(*getter_AddRefs(renderingContext));
3597 RootFrameList(aPresContext, fd, 0);
3598 //DumpFrames(fd, aPresContext, renderingContext, aRootFrame, 0);
3599 fprintf(fd, "---------------------------------------\n\n");
3600 fprintf(fd, "--------------- Views From Root Frame----------------\n");
3601 nsIView* v = aRootFrame->GetView();
3602 if (v) {
3603 v->List(fd);
3604 } else {
3605 printf("View is null!\n");
3607 if (aDocShell) {
3608 fprintf(fd, "--------------- All Views ----------------\n");
3609 DumpViews(aDocShell, fd);
3610 fprintf(fd, "---------------------------------------\n\n");
3612 if (aFD == nsnull) {
3613 fclose(fd);
3618 //-------------------------------------------------------------
3619 static void DumpPrintObjectsList(nsTArray<nsPrintObject*> * aDocList)
3621 if (!kPrintingLogMod || kPrintingLogMod->level != DUMP_LAYOUT_LEVEL) return;
3623 NS_ASSERTION(aDocList, "Pointer is null!");
3625 const char types[][3] = {"DC", "FR", "IF", "FS"};
3626 PR_PL(("Doc List\n***************************************************\n"));
3627 PR_PL(("T P A H PO DocShell Seq Page Root Page# Rect\n"));
3628 PRInt32 cnt = aDocList->Length();
3629 for (PRInt32 i=0;i<cnt;i++) {
3630 nsPrintObject* po = aDocList->ElementAt(i);
3631 NS_ASSERTION(po, "nsPrintObject can't be null!");
3632 nsIFrame* rootFrame = nsnull;
3633 if (po->mPresShell) {
3634 rootFrame = po->mPresShell->FrameManager()->GetRootFrame();
3635 while (rootFrame != nsnull) {
3636 nsIPageSequenceFrame * sqf = do_QueryFrame(rootFrame);
3637 if (sqf) {
3638 break;
3640 rootFrame = rootFrame->GetFirstChild(nsnull);
3644 PR_PL(("%s %d %d %d %p %p %p %p %p %d %d,%d,%d,%d\n", types[po->mFrameType],
3645 po->IsPrintable(), po->mPrintAsIs, po->mHasBeenPrinted, po, po->mDocShell.get(), po->mSeqFrame,
3646 po->mPageFrame, rootFrame, po->mPageNum, po->mRect.x, po->mRect.y, po->mRect.width, po->mRect.height));
3650 //-------------------------------------------------------------
3651 static void DumpPrintObjectsTree(nsPrintObject * aPO, int aLevel, FILE* aFD)
3653 if (!kPrintingLogMod || kPrintingLogMod->level != DUMP_LAYOUT_LEVEL) return;
3655 NS_ASSERTION(aPO, "Pointer is null!");
3657 FILE * fd = aFD?aFD:stdout;
3658 const char types[][3] = {"DC", "FR", "IF", "FS"};
3659 if (aLevel == 0) {
3660 fprintf(fd, "DocTree\n***************************************************\n");
3661 fprintf(fd, "T PO DocShell Seq Page Page# Rect\n");
3663 PRInt32 cnt = aPO->mKids.Length();
3664 for (PRInt32 i=0;i<cnt;i++) {
3665 nsPrintObject* po = aPO->mKids.ElementAt(i);
3666 NS_ASSERTION(po, "nsPrintObject can't be null!");
3667 for (PRInt32 k=0;k<aLevel;k++) fprintf(fd, " ");
3668 fprintf(fd, "%s %p %p %p %p %d %d,%d,%d,%d\n", types[po->mFrameType], po, po->mDocShell.get(), po->mSeqFrame,
3669 po->mPageFrame, po->mPageNum, po->mRect.x, po->mRect.y, po->mRect.width, po->mRect.height);
3673 //-------------------------------------------------------------
3674 static void GetDocTitleAndURL(nsPrintObject* aPO, char *& aDocStr, char *& aURLStr)
3676 aDocStr = nsnull;
3677 aURLStr = nsnull;
3679 PRUnichar * docTitleStr;
3680 PRUnichar * docURLStr;
3681 nsPrintEngine::GetDisplayTitleAndURL(aPO,
3682 &docTitleStr, &docURLStr,
3683 nsPrintEngine::eDocTitleDefURLDoc);
3685 if (docTitleStr) {
3686 nsAutoString strDocTitle(docTitleStr);
3687 aDocStr = ToNewCString(strDocTitle);
3688 nsMemory::Free(docTitleStr);
3691 if (docURLStr) {
3692 nsAutoString strURL(docURLStr);
3693 aURLStr = ToNewCString(strURL);
3694 nsMemory::Free(docURLStr);
3698 //-------------------------------------------------------------
3699 static void DumpPrintObjectsTreeLayout(nsPrintObject * aPO,
3700 nsIDeviceContext * aDC,
3701 int aLevel, FILE * aFD)
3703 if (!kPrintingLogMod || kPrintingLogMod->level != DUMP_LAYOUT_LEVEL) return;
3705 NS_ASSERTION(aPO, "Pointer is null!");
3706 NS_ASSERTION(aDC, "Pointer is null!");
3708 const char types[][3] = {"DC", "FR", "IF", "FS"};
3709 FILE * fd = nsnull;
3710 if (aLevel == 0) {
3711 fd = fopen("tree_layout.txt", "w");
3712 fprintf(fd, "DocTree\n***************************************************\n");
3713 fprintf(fd, "***************************************************\n");
3714 fprintf(fd, "T PO DocShell Seq Page Page# Rect\n");
3715 } else {
3716 fd = aFD;
3718 if (fd) {
3719 nsIFrame* rootFrame = nsnull;
3720 if (aPO->mPresShell) {
3721 rootFrame = aPO->mPresShell->FrameManager()->GetRootFrame();
3723 for (PRInt32 k=0;k<aLevel;k++) fprintf(fd, " ");
3724 fprintf(fd, "%s %p %p %p %p %d %d,%d,%d,%d\n", types[aPO->mFrameType], aPO, aPO->mDocShell.get(), aPO->mSeqFrame,
3725 aPO->mPageFrame, aPO->mPageNum, aPO->mRect.x, aPO->mRect.y, aPO->mRect.width, aPO->mRect.height);
3726 if (aPO->IsPrintable()) {
3727 char * docStr;
3728 char * urlStr;
3729 GetDocTitleAndURL(aPO, docStr, urlStr);
3730 DumpLayoutData(docStr, urlStr, aPO->mPresContext, aDC, rootFrame, aPO->mDocShell, fd);
3731 if (docStr) nsMemory::Free(docStr);
3732 if (urlStr) nsMemory::Free(urlStr);
3734 fprintf(fd, "<***************************************************>\n");
3736 PRInt32 cnt = aPO->mKids.Length();
3737 for (PRInt32 i=0;i<cnt;i++) {
3738 nsPrintObject* po = aPO->mKids.ElementAt(i);
3739 NS_ASSERTION(po, "nsPrintObject can't be null!");
3740 DumpPrintObjectsTreeLayout(po, aDC, aLevel+1, fd);
3743 if (aLevel == 0 && fd) {
3744 fclose(fd);
3748 //-------------------------------------------------------------
3749 static void DumpPrintObjectsListStart(const char * aStr, nsTArray<nsPrintObject*> * aDocList)
3751 if (!kPrintingLogMod || kPrintingLogMod->level != DUMP_LAYOUT_LEVEL) return;
3753 NS_ASSERTION(aStr, "Pointer is null!");
3754 NS_ASSERTION(aDocList, "Pointer is null!");
3756 PR_PL(("%s\n", aStr));
3757 DumpPrintObjectsList(aDocList);
3760 #define DUMP_DOC_LIST(_title) DumpPrintObjectsListStart((_title), mPrt->mPrintDocList);
3761 #define DUMP_DOC_TREE DumpPrintObjectsTree(mPrt->mPrintObject);
3762 #define DUMP_DOC_TREELAYOUT DumpPrintObjectsTreeLayout(mPrt->mPrintObject, mPrt->mPrintDC);
3764 #else
3765 #define DUMP_DOC_LIST(_title)
3766 #define DUMP_DOC_TREE
3767 #define DUMP_DOC_TREELAYOUT
3768 #endif
3770 //---------------------------------------------------------------
3771 //---------------------------------------------------------------
3772 //-- End of debug helper routines
3773 //---------------------------------------------------------------