Back to index

lightning-sunbird  0.9+nobinonly
nsPrintEngine.cpp
Go to the documentation of this file.
00001 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
00002 /* ***** BEGIN LICENSE BLOCK *****
00003  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
00004  *
00005  * The contents of this file are subject to the Mozilla Public License Version
00006  * 1.1 (the "License"); you may not use this file except in compliance with
00007  * the License. You may obtain a copy of the License at
00008  * http://www.mozilla.org/MPL/
00009  *
00010  * Software distributed under the License is distributed on an "AS IS" basis,
00011  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
00012  * for the specific language governing rights and limitations under the
00013  * License.
00014  *
00015  * The Original Code is mozilla.org code.
00016  *
00017  * The Initial Developer of the Original Code is
00018  * Netscape Communications Corporation.
00019  * Portions created by the Initial Developer are Copyright (C) 1998
00020  * the Initial Developer. All Rights Reserved.
00021  *
00022  * Contributor(s):
00023  *   Roland Mainz <roland.mainz@informatik.med.uni-giessen.de>
00024  *
00025  * Alternatively, the contents of this file may be used under the terms of
00026  * either of the GNU General Public License Version 2 or later (the "GPL"),
00027  * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00028  * in which case the provisions of the GPL or the LGPL are applicable instead
00029  * of those above. If you wish to allow use of your version of this file only
00030  * under the terms of either the GPL or the LGPL, and not to allow others to
00031  * use your version of this file under the terms of the MPL, indicate your
00032  * decision by deleting the provisions above and replace them with the notice
00033  * and other provisions required by the GPL or the LGPL. If you do not delete
00034  * the provisions above, a recipient may use your version of this file under
00035  * the terms of any one of the MPL, the GPL or the LGPL.
00036  *
00037  * ***** END LICENSE BLOCK ***** */
00038 
00039 #include "nsPrintEngine.h"
00040 
00041 #include "nsIStringBundle.h"
00042 #include "nsReadableUtils.h"
00043 #include "nsCRT.h"
00044 
00045 #include "nsISelection.h"
00046 #include "nsIScriptGlobalObject.h"
00047 #include "nsIDOMWindowInternal.h"
00048 #include "nsIDocShell.h"
00049 #include "nsIURI.h"
00050 #include "nsINodeInfo.h"
00051 #include "nsContentErrors.h"
00052 
00053 // Print Options
00054 #include "nsIPrintSettings.h"
00055 #include "nsIPrintSettingsService.h"
00056 #include "nsIPrintOptions.h"
00057 #include "nsGfxCIID.h"
00058 #include "nsIServiceManager.h"
00059 #include "nsHTMLAtoms.h" // XXX until atoms get factored into nsLayoutAtoms
00060 #include "nsISimpleEnumerator.h"
00061 #include "nsXPCOM.h"
00062 #include "nsISupportsPrimitives.h"
00063 
00064 // PrintOptions is now implemented by PrintSettingsService
00065 static const char sPrintSettingsServiceContractID[] = "@mozilla.org/gfx/printsettings-service;1";
00066 static const char sPrintOptionsContractID[]         = "@mozilla.org/gfx/printsettings-service;1";
00067 
00068 // Printing Events
00069 #include "nsIEventQueue.h"
00070 #include "nsIEventQueueService.h"
00071 #include "nsEventQueueUtils.h"
00072 #include "nsPrintPreviewListener.h"
00073 
00074 // Printing
00075 #include "nsIWebBrowserPrint.h"
00076 #include "nsIDOMHTMLFrameElement.h"
00077 #include "nsIDOMHTMLFrameSetElement.h"
00078 #include "nsIDOMHTMLIFrameElement.h"
00079 #include "nsIDOMHTMLObjectElement.h"
00080 #include "nsIDOMHTMLEmbedElement.h"
00081 
00082 // Print Preview
00083 #include "imgIContainer.h" // image animation mode constants
00084 #include "nsIScrollableView.h"
00085 #include "nsIScrollable.h"
00086 #include "nsIWebBrowserPrint.h" // needed for PrintPreview Navigation constants
00087 
00088 // Print Progress
00089 #include "nsIPrintProgress.h"
00090 #include "nsIPrintProgressParams.h"
00091 #include "nsIObserver.h"
00092 
00093 // Print error dialog
00094 #include "nsIPrompt.h"
00095 #include "nsIWindowWatcher.h"
00096 #include "nsIStringBundle.h"
00097 
00098 // Printing Prompts
00099 #include "nsIPrintingPromptService.h"
00100 static const char kPrintingPromptService[] = "@mozilla.org/embedcomp/printingprompt-service;1";
00101 
00102 // Printing Timer
00103 #include "nsPagePrintTimer.h"
00104 
00105 // FrameSet
00106 #include "nsINodeInfo.h"
00107 #include "nsIDocument.h"
00108 #include "nsHTMLAtoms.h"
00109 
00110 // Focus
00111 #include "nsIDOMEventReceiver.h"
00112 #include "nsIDOMFocusListener.h"
00113 #include "nsISelectionController.h"
00114 
00115 // Misc
00116 #include "nsISupportsUtils.h"
00117 #include "nsIFrame.h"
00118 #include "nsIScriptContext.h"
00119 #include "nsILinkHandler.h"
00120 #include "nsIDOMDocument.h"
00121 #include "nsISelectionListener.h"
00122 #include "nsISelectionPrivate.h"
00123 #include "nsIDOMHTMLDocument.h"
00124 #include "nsIDOMNSHTMLDocument.h"
00125 #include "nsIDOMHTMLCollection.h"
00126 #include "nsIDOMHTMLElement.h"
00127 #include "nsIDOMRange.h"
00128 #include "nsContentCID.h"
00129 #include "nsLayoutCID.h"
00130 #include "nsContentUtils.h"
00131 #include "nsIPresShell.h"
00132 #include "nsLayoutUtils.h"
00133 
00134 #include "nsViewsCID.h"
00135 #include "nsWidgetsCID.h"
00136 #include "nsIDeviceContext.h"
00137 #include "nsIDeviceContextSpec.h"
00138 #include "nsIDeviceContextSpecFactory.h"
00139 #include "nsIViewManager.h"
00140 #include "nsIView.h"
00141 
00142 #include "nsIPageSequenceFrame.h"
00143 #include "nsIURL.h"
00144 #include "nsIContentViewerEdit.h"
00145 #include "nsIContentViewerFile.h"
00146 #include "nsIMarkupDocumentViewer.h"
00147 #include "nsIInterfaceRequestor.h"
00148 #include "nsIInterfaceRequestorUtils.h"
00149 #include "nsIDocShellTreeItem.h"
00150 #include "nsIDocShellTreeNode.h"
00151 #include "nsIDocShellTreeOwner.h"
00152 #include "nsIDocShell.h"
00153 #include "nsIBaseWindow.h"
00154 #include "nsIFrameDebug.h"
00155 #include "nsILayoutHistoryState.h"
00156 #include "nsLayoutAtoms.h"
00157 #include "nsFrameManager.h"
00158 #include "nsIParser.h"
00159 #include "nsGUIEvent.h"
00160 #include "nsHTMLReflowState.h"
00161 #include "nsIDOMHTMLAnchorElement.h"
00162 #include "nsIDOMHTMLAreaElement.h"
00163 #include "nsIDOMHTMLLinkElement.h"
00164 #include "nsIDOMHTMLImageElement.h"
00165 #include "nsIContentViewerContainer.h"
00166 #include "nsIContentViewer.h"
00167 
00168 #include "nsIEventQueueService.h"
00169 #include "nsIEventQueue.h"
00170 
00171 #include "nsPIDOMWindow.h"
00172 #include "nsIFocusController.h"
00173 
00174 #include "nsCDefaultURIFixup.h"
00175 #include "nsIURIFixup.h"
00176 
00177 //-----------------------------------------------------
00178 // PR LOGGING
00179 #ifdef MOZ_LOGGING
00180 #define FORCE_PR_LOG /* Allow logging in the release build */
00181 #endif
00182 
00183 #include "prlog.h"
00184 
00185 #ifdef PR_LOGGING
00186 
00187 #ifdef NS_DEBUG
00188 // PR_LOGGING is force to always be on (even in release builds)
00189 // but we only want some of it on,
00190 //#define EXTENDED_DEBUG_PRINTING 
00191 #endif
00192 
00193 #define DUMP_LAYOUT_LEVEL 9 // this turns on the dumping of each doucment's layout info
00194 
00195 static PRLogModuleInfo * kPrintingLogMod = PR_NewLogModule("printing");
00196 #define PR_PL(_p1)  PR_LOG(kPrintingLogMod, PR_LOG_DEBUG, _p1);
00197 
00198 #ifdef EXTENDED_DEBUG_PRINTING
00199 static PRUint32 gDumpFileNameCnt   = 0;
00200 static PRUint32 gDumpLOFileNameCnt = 0;
00201 #endif
00202 
00203 #define PRT_YESNO(_p) ((_p)?"YES":"NO")
00204 static const char * gFrameTypesStr[]       = {"eDoc", "eFrame", "eIFrame", "eFrameSet"};
00205 static const char * gPrintFrameTypeStr[]   = {"kNoFrames", "kFramesAsIs", "kSelectedFrame", "kEachFrameSep"};
00206 static const char * gFrameHowToEnableStr[] = {"kFrameEnableNone", "kFrameEnableAll", "kFrameEnableAsIsAndEach"};
00207 static const char * gPrintRangeStr[]       = {"kRangeAllPages", "kRangeSpecifiedPageRange", "kRangeSelection", "kRangeFocusFrame"};
00208 #else
00209 #define PRT_YESNO(_p)
00210 #define PR_PL(_p1)
00211 #endif
00212 
00213 #ifdef EXTENDED_DEBUG_PRINTING
00214 // Forward Declarations
00215 static void DumpPrintObjectsListStart(const char * aStr, nsVoidArray * aDocList);
00216 static void DumpPrintObjectsTree(nsPrintObject * aPO, int aLevel= 0, FILE* aFD = nsnull);
00217 static void DumpPrintObjectsTreeLayout(nsPrintObject * aPO,nsIDeviceContext * aDC, int aLevel= 0, FILE * aFD = nsnull);
00218 
00219 #define DUMP_DOC_LIST(_title) DumpPrintObjectsListStart((_title), mPrt->mPrintDocList);
00220 #define DUMP_DOC_TREE DumpPrintObjectsTree(mPrt->mPrintObject);
00221 #define DUMP_DOC_TREELAYOUT DumpPrintObjectsTreeLayout(mPrt->mPrintObject, mPrt->mPrintDC);
00222 #else
00223 #define DUMP_DOC_LIST(_title)
00224 #define DUMP_DOC_TREE
00225 #define DUMP_DOC_TREELAYOUT
00226 #endif
00227 
00228 
00229 // Class IDs
00230 static NS_DEFINE_CID(kViewManagerCID,       NS_VIEW_MANAGER_CID);
00231 static NS_DEFINE_CID(kWidgetCID,            NS_CHILD_CID);
00232 
00233 static NS_DEFINE_IID(kDeviceContextSpecFactoryCID, NS_DEVICE_CONTEXT_SPEC_FACTORY_CID);
00234 
00235 NS_IMPL_ISUPPORTS2(nsPrintEngine,
00236                    nsIWebBrowserPrint,
00237                    nsIObserver)
00238 
00239 //---------------------------------------------------
00240 //-- nsPrintEngine Class Impl
00241 //---------------------------------------------------
00242 nsPrintEngine::nsPrintEngine() :
00243   mIsCreatingPrintPreview(PR_FALSE),
00244   mIsDoingPrinting(PR_FALSE),
00245   mDocViewerPrint(nsnull),
00246   mDocViewer(nsnull),
00247   mContainer(nsnull),
00248   mDeviceContext(nsnull),
00249   mPresContext(nsnull),
00250   mPrt(nsnull),
00251   mPagePrintTimer(nsnull),
00252   mPageSeqFrame(nsnull),
00253   mIsDoingPrintPreview(PR_FALSE),
00254   mParentWidget(nsnull),
00255   mPrtPreview(nsnull),
00256   mOldPrtPreview(nsnull),
00257   mIsCachingPresentation(PR_FALSE),
00258   mCachedPresObj(nsnull),
00259   mDebugFile(nsnull)
00260 
00261 {
00262 }
00263 
00264 //-------------------------------------------------------
00265 nsPrintEngine::~nsPrintEngine()
00266 {
00267 #ifdef MOZ_LAYOUTDEBUG
00268   nsPrintEngine::mLayoutDebugObj = nsnull;
00269 #endif
00270 
00271   Destroy(); // for insurance
00272 }
00273 
00274 //-------------------------------------------------------
00275 void nsPrintEngine::Destroy()
00276 {
00277   // removed any cached
00278   if (mCachedPresObj) {
00279     delete mCachedPresObj;
00280     mCachedPresObj = nsnull;
00281   }
00282 
00283   if (mPrt) {
00284     delete mPrt;
00285     mPrt = nsnull;
00286   }
00287 
00288 #ifdef NS_PRINT_PREVIEW
00289   if (mPrtPreview) {
00290     delete mPrtPreview;
00291     mPrtPreview = nsnull;
00292   }
00293 
00294   // This is insruance
00295   if (mOldPrtPreview) {
00296     delete mOldPrtPreview;
00297     mOldPrtPreview = nsnull;
00298   }
00299 
00300 #endif
00301 
00302 }
00303 
00304 //-------------------------------------------------------
00305 void nsPrintEngine::DestroyPrintingData()
00306 {
00307   if (mPrt) {
00308     delete mPrt;
00309     mPrt = nsnull;
00310   }
00311 }
00312 
00313 //---------------------------------------------------------------------------------
00314 //-- Section: Methods needed by the DocViewer
00315 //---------------------------------------------------------------------------------
00316 
00317 //--------------------------------------------------------
00318 nsresult nsPrintEngine::Initialize(nsIDocumentViewer*      aDocViewer, 
00319                                    nsIDocumentViewerPrint* aDocViewerPrint, 
00320                                    nsISupports*            aContainer,
00321                                    nsIDocument*            aDocument,
00322                                    nsIDeviceContext*       aDevContext,
00323                                    nsPresContext*         aPresContext,
00324                                    nsIWidget*              aWindow,
00325                                    nsIWidget*              aParentWidget,
00326                                    FILE*                   aDebugFile)
00327 {
00328   NS_ENSURE_ARG_POINTER(aDocViewer);
00329   NS_ENSURE_ARG_POINTER(aDocViewerPrint);
00330   NS_ENSURE_ARG_POINTER(aContainer);
00331   NS_ENSURE_ARG_POINTER(aDocument);
00332   NS_ENSURE_ARG_POINTER(aDevContext);
00333   NS_ENSURE_ARG_POINTER(aPresContext);
00334   NS_ENSURE_ARG_POINTER(aWindow);
00335   NS_ENSURE_ARG_POINTER(aParentWidget);
00336 
00337   mDocViewer      = aDocViewer;      // weak reference
00338   mDocViewerPrint = aDocViewerPrint; // weak reference
00339   mContainer      = aContainer;      // weak reference
00340   mDocument       = aDocument;
00341   mDeviceContext  = aDevContext;     // weak reference
00342   mPresContext    = aPresContext;    // weak reference
00343   mWindow         = aWindow;    
00344   mParentWidget   = aParentWidget;    
00345 
00346   mDebugFile      = aDebugFile;      // ok to be NULL
00347 
00348   return NS_OK;
00349 }
00350 
00351 //-------------------------------------------------------
00352 PRBool
00353 nsPrintEngine::CheckBeforeDestroy()
00354 {
00355   if (mPrt && mPrt->mPreparingForPrint) {
00356     mPrt->mDocWasToBeDestroyed = PR_TRUE;
00357     return PR_TRUE;
00358   }
00359   return PR_FALSE;
00360 }
00361 
00362 //-------------------------------------------------------
00363 nsresult
00364 nsPrintEngine::Cancelled()
00365 {
00366   if (mPrt && mPrt->mPrintSettings) {
00367     return mPrt->mPrintSettings->SetIsCancelled(PR_TRUE);
00368   }
00369   return NS_ERROR_FAILURE;
00370 }
00371 
00372 //-------------------------------------------------------
00373 void
00374 nsPrintEngine::CachePresentation(nsIPresShell*   aShell, 
00375                                  nsPresContext* aPC,
00376                                  nsIViewManager* aVM, 
00377                                  nsIWidget*      aW)
00378 {
00379   NS_ASSERTION(!mCachedPresObj, "Cached Pres Object must be null!");
00380   mCachedPresObj = new CachedPresentationObj(aShell, aPC, aVM, aW);
00381 }
00382 
00383 //-------------------------------------------------------
00384 void
00385 nsPrintEngine::GetCachedPresentation(nsCOMPtr<nsIPresShell>& aShell, 
00386                                      nsCOMPtr<nsPresContext>& aPC, 
00387                                      nsCOMPtr<nsIViewManager>& aVM, 
00388                                      nsCOMPtr<nsIWidget>& aW)
00389 {
00390   aShell = mCachedPresObj->mPresShell;
00391   aPC    = mCachedPresObj->mPresContext;
00392   aVM    = mCachedPresObj->mViewManager;
00393   aW     = mCachedPresObj->mWindow;
00394 }
00395 
00396 //------------------------------------------------------------
00397 void
00398 nsPrintEngine::GetNewPresentation(nsCOMPtr<nsIPresShell>& aShell, 
00399                                   nsCOMPtr<nsPresContext>& aPC, 
00400                                   nsCOMPtr<nsIViewManager>& aVM, 
00401                                   nsCOMPtr<nsIWidget>& aW)
00402 {
00403   // Default to the main Print Object
00404   nsPrintObject * prtObjToDisplay = mPrt->mPrintObject;
00405 
00406   // This is the new code for selecting the appropriate Frame of a Frameset
00407   // for Print Preview. But it can't be turned on yet
00408 #if 0
00409   // If it is a Frameset then choose the selected one
00410   // or select the one with the largest area
00411   if (mPrt->mPrintObject->mFrameType == eFrameSet) {
00412     if (mPrt->mCurrentFocusWin) {
00413       PRInt32 cnt = mPrt->mPrintObject->mKids.Count();
00414       // Start at "1" and skip the FrameSet document itself
00415       for (PRInt32 i=1;i<cnt;i++) {
00416         nsPrintObject* po = (nsPrintObject *)mPrt->mPrintObject->mKids[i];
00417         nsCOMPtr<nsIDOMWindow> domWin(do_GetInterface(po->mDocShell));
00418         if (domWin.get() == mPrt->mCurrentFocusWin.get()) {
00419           prtObjToDisplay = po;
00420           break;
00421         }
00422       }
00423     } else {
00424       nsPrintObject* largestPO = nsnull;
00425       nscoord area = 0;
00426       PRInt32 cnt = mPrt->mPrintObject->mKids.Count();
00427       // Start at "1" and skip the FrameSet document itself
00428       for (PRInt32 i=1;i<cnt;i++) {
00429         nsPrintObject* po = (nsPrintObject *)mPrt->mPrintObject->mKids[i];
00430         nsCOMPtr<nsIDOMWindow> domWin(do_GetInterface(po->mDocShell));
00431         if (domWin.get() == mPrt->mCurrentFocusWin.get()) {
00432           nscoord width;
00433           nscoord height;
00434           domWin->GetInnerWidth(&width);
00435           domWin->GetInnerHeight(&height);
00436           nscoord newArea = width * height;
00437           if (newArea > area) {
00438             largestPO = po;
00439             area = newArea;
00440           }
00441         }
00442       }
00443       // make sure we got one
00444       if (largestPO) {
00445         prtObjToDisplay = largestPO;
00446       }
00447     }
00448   }
00449 #endif
00450 
00451   // Set the new Presentation
00452   aShell = prtObjToDisplay->mPresShell;
00453   aPC    = prtObjToDisplay->mPresContext;
00454   aVM    = prtObjToDisplay->mViewManager;
00455   aW     = prtObjToDisplay->mWindow;
00456 
00457   //mPresShell   = prtObjToDisplay->mPresShell;
00458   mPresContext = prtObjToDisplay->mPresContext;
00459   //mViewManager = prtObjToDisplay->mViewManager;
00460   //mWindow      = prtObjToDisplay->mWindow;
00461 
00462   if (mIsDoingPrintPreview && mOldPrtPreview) {
00463     delete mOldPrtPreview;
00464     mOldPrtPreview = nsnull;
00465   }
00466 
00467   prtObjToDisplay->mSharedPresShell = PR_TRUE;
00468 
00469 }
00470 
00471 //-------------------------------------------------------
00472 // Install our event listeners on the document to prevent 
00473 // some events from being processed while in PrintPreview 
00474 //
00475 // No return code - if this fails, there isn't much we can do
00476 void
00477 nsPrintEngine::InstallPrintPreviewListener()
00478 {
00479   if (!mPrt->mPPEventListeners) {
00480     nsCOMPtr<nsPIDOMWindow> win(do_GetInterface(mContainer));
00481     nsCOMPtr<nsIDOMEventTarget> target(do_QueryInterface(win->GetFrameElementInternal()));
00482     mPrt->mPPEventListeners = new nsPrintPreviewListener(target);
00483 
00484     if (mPrt->mPPEventListeners) {
00485       mPrt->mPPEventListeners->AddListeners();
00486     }
00487   }
00488 }
00489 
00490 //----------------------------------------------------------------------
00491 nsresult 
00492 nsPrintEngine::GetSeqFrameAndCountPagesInternal(nsPrintObject*  aPO,
00493                                                 nsIFrame*&    aSeqFrame,
00494                                                 PRInt32&      aCount)
00495 {
00496   NS_ENSURE_ARG_POINTER(aPO);
00497 
00498   // Finds the SimplePageSequencer frame
00499   // in PP mPrtPreview->mPrintObject->mSeqFrame is null
00500   nsIPageSequenceFrame* seqFrame = nsnull;
00501   aPO->mPresShell->GetPageSequenceFrame(&seqFrame);
00502   if (seqFrame) {
00503     CallQueryInterface(seqFrame, &aSeqFrame);
00504   } else {
00505     aSeqFrame = nsnull;
00506   }
00507   if (aSeqFrame == nsnull) return NS_ERROR_FAILURE;
00508 
00509   // first count the total number of pages
00510   aCount = 0;
00511   nsIFrame* pageFrame = aSeqFrame->GetFirstChild(nsnull);
00512   while (pageFrame != nsnull) {
00513     aCount++;
00514     pageFrame = pageFrame->GetNextSibling();
00515   }
00516 
00517   return NS_OK;
00518 
00519 }
00520 
00521 //-----------------------------------------------------------------
00522 nsresult nsPrintEngine::GetSeqFrameAndCountPages(nsIFrame*& aSeqFrame, PRInt32& aCount)
00523 {
00524   NS_ASSERTION(mPrtPreview, "mPrtPreview can't be null!");
00525   return GetSeqFrameAndCountPagesInternal(mPrtPreview->mPrintObject, aSeqFrame, aCount);
00526 }
00527 //---------------------------------------------------------------------------------
00528 //-- Done: Methods needed by the DocViewer
00529 //---------------------------------------------------------------------------------
00530 
00531 
00532 //---------------------------------------------------------------------------------
00533 //-- Section: nsIWebBrowserPrint
00534 //---------------------------------------------------------------------------------
00535 
00536 // Foward decl for Debug Helper Functions
00537 #ifdef EXTENDED_DEBUG_PRINTING
00538 static int RemoveFilesInDir(const char * aDir);
00539 static void GetDocTitleAndURL(nsPrintObject* aPO, char *& aDocStr, char *& aURLStr);
00540 static void DumpPrintObjectsTree(nsPrintObject * aPO, int aLevel, FILE* aFD);
00541 static void DumpPrintObjectsList(nsVoidArray * aDocList);
00542 static void RootFrameList(nsPresContext* aPresContext, FILE* out, PRInt32 aIndent);
00543 static void DumpViews(nsIDocShell* aDocShell, FILE* out);
00544 static void DumpLayoutData(char* aTitleStr, char* aURLStr,
00545                            nsPresContext* aPresContext,
00546                            nsIDeviceContext * aDC, nsIFrame * aRootFrame,
00547                            nsIDocShell * aDocShell, FILE* aFD);
00548 #endif
00549 
00550 //---------------------------------------------------------------------------------
00551 NS_IMETHODIMP
00552 nsPrintEngine::Print(nsIPrintSettings*       aPrintSettings,
00553                      nsIWebProgressListener* aWebProgressListener)
00554 {
00555 #ifdef EXTENDED_DEBUG_PRINTING
00556   // need for capturing result on each doc and sub-doc that is printed
00557   gDumpFileNameCnt   = 0;
00558   gDumpLOFileNameCnt = 0;
00559 #if defined(XP_WIN) || defined(XP_OS2)
00560   if (kPrintingLogMod && kPrintingLogMod->level == DUMP_LAYOUT_LEVEL) {
00561     RemoveFilesInDir(".\\");
00562   }
00563 #endif // XP_WIN || XP_OS2
00564 #endif // EXTENDED_DEBUG_PRINTING
00565 
00566   nsresult rv = NS_ERROR_FAILURE;
00567 
00568   nsCOMPtr<nsIDocShell> docShell(do_QueryInterface(mContainer));
00569   NS_ASSERTION(docShell, "This has to be a docshell");
00570 
00571   mPrt = new nsPrintData(nsPrintData::eIsPrinting);
00572   if (!mPrt) {
00573     PR_PL(("NS_ERROR_OUT_OF_MEMORY - Creating PrintData"));
00574     return NS_ERROR_OUT_OF_MEMORY;
00575   }
00576 
00577   // if they don't pass in a PrintSettings, then get the Global PS
00578   mPrt->mPrintSettings = aPrintSettings;
00579   if (!mPrt->mPrintSettings) {
00580     GetGlobalPrintSettings(getter_AddRefs(mPrt->mPrintSettings));
00581   }
00582 
00583   mPrt->mPrintOptions = do_GetService(sPrintOptionsContractID, &rv);
00584   if (NS_SUCCEEDED(rv) && mPrt->mPrintOptions && mPrt->mPrintSettings) {
00585     // Get the default printer name and set it into the PrintSettings
00586     rv = CheckForPrinters(mPrt->mPrintOptions, mPrt->mPrintSettings);
00587   } else {
00588     NS_ASSERTION(mPrt->mPrintSettings, "You can't Print without a PrintSettings!");
00589     rv = NS_ERROR_FAILURE;
00590   }
00591 
00592   if (NS_FAILED(rv)) {
00593     PR_PL(("NS_ERROR_FAILURE - CheckForPrinters for Printers failed"));
00594     return CleanupOnFailure(rv, PR_TRUE);
00595   }
00596 
00597   mPrt->mPrintSettings->SetIsCancelled(PR_FALSE);
00598   mPrt->mPrintSettings->GetShrinkToFit(&mPrt->mShrinkToFit);
00599 
00600   // Create a print session and let the print settings know about it.
00601   // The print settings hold an nsWeakPtr to the session so it does not
00602   // need to be cleared from the settings at the end of the job.
00603   mPrt->mPrintSession = do_CreateInstance("@mozilla.org/gfx/printsession;1", &rv);
00604   CHECK_RUNTIME_ERROR_CONDITION(nsIDebugObject::PRT_RUNTIME_CREATEPRTSESSION, rv, NS_ERROR_FAILURE);
00605   if (NS_FAILED(rv)) {
00606     PR_PL(("NS_ERROR_FAILURE - do_CreateInstance for printsession failed"));
00607     return CleanupOnFailure(rv, PR_TRUE);
00608   }
00609   mPrt->mPrintSettings->SetPrintSession(mPrt->mPrintSession);
00610 
00611   // Let's print ...
00612   SetIsPrinting(PR_TRUE);
00613 
00614   // We need to  make sure this document doesn't get unloaded
00615   // before we have a chance to print, so this stops the Destroy from
00616   // being called
00617   mPrt->mPreparingForPrint = PR_TRUE;
00618 
00619   if (aWebProgressListener != nsnull) {
00620     mPrt->mPrintProgressListeners.AppendElement((void*)aWebProgressListener);
00621     NS_ADDREF(aWebProgressListener);
00622   }
00623 
00624   // Get the currently focused window and cache it
00625   // because the Print Dialog will "steal" focus and later when you try
00626   // to get the currently focused windows it will be NULL
00627   mPrt->mCurrentFocusWin = FindFocusedDOMWindow();
00628 
00629   // Check to see if there is a "regular" selection
00630   PRBool isSelection = IsThereARangeSelection(mPrt->mCurrentFocusWin);
00631 
00632   // Create a list for storing the DocShells that need to be printed
00633   if (mPrt->mPrintDocList == nsnull) {
00634     mPrt->mPrintDocList = new nsVoidArray();
00635     if (mPrt->mPrintDocList == nsnull) {
00636       SetIsPrinting(PR_FALSE);
00637       PR_PL(("NS_ERROR_FAILURE - Couldn't create mPrintDocList"));
00638       return CleanupOnFailure(NS_ERROR_FAILURE, PR_TRUE);
00639     }
00640   } else {
00641     mPrt->mPrintDocList->Clear();
00642   }
00643 
00644   // Get the docshell for this documentviewer
00645   nsCOMPtr<nsIDocShell> webContainer(do_QueryInterface(mContainer));
00646 
00647   // Add Root Doc to Tree and List
00648   mPrt->mPrintObject = new nsPrintObject();
00649   rv = mPrt->mPrintObject->Init(webContainer);
00650   CHECK_RUNTIME_ERROR_CONDITION(nsIDebugObject::PRT_RUNTIME_INITPRTOBJ, rv, NS_ERROR_FAILURE);
00651   if (NS_FAILED(rv)) {
00652     PR_PL(("NS_ERROR_FAILURE - Failed on Init of PrintObject"));
00653     ShowPrintErrorDialog(NS_ERROR_FAILURE);
00654     return rv;
00655   }
00656   mPrt->mPrintDocList->AppendElement(mPrt->mPrintObject);
00657 
00658   mPrt->mIsParentAFrameSet = IsParentAFrameSet(webContainer);
00659   mPrt->mPrintObject->mFrameType = mPrt->mIsParentAFrameSet?eFrameSet:eDoc;
00660 
00661   // Build the "tree" of PrintObjects
00662   nsCOMPtr<nsIDocShellTreeNode>  parentAsNode(do_QueryInterface(webContainer));
00663   BuildDocTree(parentAsNode, mPrt->mPrintDocList, mPrt->mPrintObject);
00664 
00665   // Create the linkage from the suv-docs back to the content element
00666   // in the parent document
00667   MapContentToWebShells(mPrt->mPrintObject, mPrt->mPrintObject);
00668 
00669   // Get whether the doc contains a frameset
00670   // Also, check to see if the currently focus docshell
00671   // is a child of this docshell
00672   mPrt->mIsIFrameSelected = IsThereAnIFrameSelected(webContainer, mPrt->mCurrentFocusWin, mPrt->mIsParentAFrameSet);
00673 
00674   DUMP_DOC_LIST("\nAfter Mapping------------------------------------------");
00675 
00676   rv = NS_ERROR_FAILURE;
00677   // Setup print options for UI
00678   if (mPrt->mIsParentAFrameSet) {
00679     if (mPrt->mCurrentFocusWin) {
00680       mPrt->mPrintSettings->SetHowToEnableFrameUI(nsIPrintSettings::kFrameEnableAll);
00681     } else {
00682       mPrt->mPrintSettings->SetHowToEnableFrameUI(nsIPrintSettings::kFrameEnableAsIsAndEach);
00683     }
00684   } else {
00685     mPrt->mPrintSettings->SetHowToEnableFrameUI(nsIPrintSettings::kFrameEnableNone);
00686   }
00687   // Now determine how to set up the Frame print UI
00688   mPrt->mPrintSettings->SetPrintOptions(nsIPrintSettings::kEnableSelectionRB, isSelection || mPrt->mIsIFrameSelected);
00689 
00690 #ifdef PR_LOGGING
00691   if (mPrt->mPrintSettings) {
00692     PRInt16 printHowEnable = nsIPrintSettings::kFrameEnableNone;
00693     mPrt->mPrintSettings->GetHowToEnableFrameUI(&printHowEnable);
00694     PRBool val;
00695     mPrt->mPrintSettings->GetPrintOptions(nsIPrintSettings::kEnableSelectionRB, &val);
00696 
00697     PR_PL(("********* nsPrintEngine::Print *********\n"));
00698     PR_PL(("IsParentAFrameSet:   %s \n", PRT_YESNO(mPrt->mIsParentAFrameSet)));
00699     PR_PL(("IsIFrameSelected:    %s \n", PRT_YESNO(mPrt->mIsIFrameSelected)));
00700     PR_PL(("Main Doc Frame Type: %s \n", gFrameTypesStr[mPrt->mPrintObject->mFrameType]));
00701     PR_PL(("HowToEnableFrameUI:  %s \n", gFrameHowToEnableStr[printHowEnable]));
00702     PR_PL(("EnableSelectionRB:   %s \n", PRT_YESNO(val)));
00703     PR_PL(("*********************************************\n"));
00704   }
00705 #endif
00706 
00707   /* create factory (incl. create print dialog) */
00708   nsCOMPtr<nsIDeviceContextSpecFactory> factory =
00709           do_CreateInstance(kDeviceContextSpecFactoryCID, &rv);
00710 
00711   CHECK_RUNTIME_ERROR_CONDITION(nsIDebugObject::PRT_RUNTIME_CREATESPECFACTORY, rv, NS_ERROR_FAILURE);
00712   if (NS_SUCCEEDED(rv)) {
00713 #ifdef DEBUG_dcone
00714     printf("PRINT JOB STARTING\n");
00715 #endif
00716 
00717     nsCOMPtr<nsIDeviceContextSpec> devspec;
00718     mPrt->mPrintDC = nsnull; // XXX why?
00719 
00720 #ifdef NS_DEBUG
00721     mPrt->mDebugFilePtr = mDebugFile;
00722 #endif
00723 
00724     PRBool printSilently;
00725     mPrt->mPrintSettings->GetPrintSilent(&printSilently);
00726 
00727     // Check prefs for a default setting as to whether we should print silently
00728     printSilently = nsContentUtils::GetBoolPref("print.always_print_silent",
00729                                                 printSilently);
00730 
00731     // Ask dialog to be Print Shown via the Plugable Printing Dialog Service
00732     // This service is for the Print Dialog and the Print Progress Dialog
00733     // If printing silently or you can't get the service continue on
00734     if (!printSilently) {
00735       nsCOMPtr<nsIPrintingPromptService> printPromptService(do_GetService(kPrintingPromptService));
00736       if (printPromptService) {
00737         nsCOMPtr<nsIDOMWindow> domWin = do_QueryInterface(mDocument->GetScriptGlobalObject()); 
00738         NS_ENSURE_TRUE(domWin, NS_ERROR_FAILURE);
00739 
00740         // Platforms not implementing a given dialog for the service may
00741         // return NS_ERROR_NOT_IMPLEMENTED or an error code.
00742         //
00743         // NS_ERROR_NOT_IMPLEMENTED indicates they want default behavior
00744         // Any other error code means we must bail out
00745         //
00746         if (mDialogParentWin) {
00747           domWin = mDialogParentWin;
00748         }
00749         rv = printPromptService->ShowPrintDialog(domWin, this, mPrt->mPrintSettings);
00750         if (rv == NS_ERROR_NOT_IMPLEMENTED) {
00751           // This means the Dialog service was there, 
00752           // but they choose not to implement this dialog and 
00753           // are looking for default behavior from the toolkit
00754           rv = NS_OK;
00755 
00756         } else if (NS_SUCCEEDED(rv)) {
00757           // since we got the dialog and it worked then make sure we 
00758           // are telling GFX we want to print silent
00759           printSilently = PR_TRUE;
00760         }
00761       } else {
00762         rv = NS_ERROR_GFX_NO_PRINTROMPTSERVICE;
00763       }
00764     }
00765 
00766     CHECK_RUNTIME_ERROR_CONDITION(nsIDebugObject::PRT_RUNTIME_NOPROMPTSERVICE, rv, NS_ERROR_GFX_NO_PRINTROMPTSERVICE);
00767     if (NS_FAILED(rv)) {
00768       PR_PL(("**** Printing Stopped before CreateDeviceContextSpec"));
00769       return CleanupOnFailure(rv, PR_TRUE);
00770     }
00771 
00772     // Create DeviceSpec for Printing
00773     rv = factory->CreateDeviceContextSpec(mWindow, mPrt->mPrintSettings, *getter_AddRefs(devspec), PR_FALSE);
00774 
00775     // If the page was intended to be destroyed while we were in the print dialog 
00776     // then we need to clean up and abort the printing.
00777     if (mPrt->mDocWasToBeDestroyed) {
00778       mPrt->mPreparingForPrint = PR_FALSE;
00779       // XXX Destroy();
00780       SetIsPrinting(PR_FALSE);
00781       // If they hit cancel then rv will equal NS_ERROR_ABORT and 
00782       // then we don't want to display the message
00783       if (rv != NS_ERROR_ABORT) {
00784         ShowPrintErrorDialog(NS_ERROR_GFX_PRINTER_DOC_WAS_DESTORYED);
00785       }
00786       PR_PL(("**** mDocWasToBeDestroyed - %s", rv != NS_ERROR_ABORT?"NS_ERROR_GFX_PRINTER_DOC_WAS_DESTORYED":"NS_ERROR_ABORT"));
00787       return NS_ERROR_ABORT;
00788     }
00789 
00790     CHECK_RUNTIME_ERROR_CONDITION(nsIDebugObject::PRT_RUNTIME_NODEVSPEC, rv, NS_ERROR_FAILURE);
00791     if (NS_SUCCEEDED(rv)) {
00792       rv = mPresContext->DeviceContext()->
00793         GetDeviceContextFor(devspec, *getter_AddRefs(mPrt->mPrintDC));
00794       if (NS_SUCCEEDED(rv)) {
00795         // Get the Original PixelScale incase we need to start changing it
00796         mPrt->mPrintDC->GetCanonicalPixelScale(mPrt->mOrigDCScale);
00797         // Shrink to Fit over rides and scaling values
00798         if (!mPrt->mShrinkToFit) {
00799           double scaling;
00800           mPrt->mPrintSettings->GetScaling(&scaling);
00801           mPrt->mPrintDC->SetCanonicalPixelScale(float(scaling)*mPrt->mOrigDCScale);
00802         }
00803 
00804         if(webContainer) {
00805 #ifdef DEBUG_dcone
00806           float   a1,a2;
00807           PRInt32 i1,i2;
00808 
00809           printf("CRITICAL PRINTING INFORMATION\n");
00810 
00811           // DEVICE CONTEXT INFORMATION from PresContext
00812           nsIDeviceContext *dx = mPresContext->DeviceContext();
00813           printf("DeviceContext of Presentation Context(%x)\n", dx);
00814           a1 = dx->DevUnitsToTwips();
00815           a2 = dx->TwipsToDevUnits();
00816           printf("    DevToTwips = %f TwipToDev = %f\n",a1,a2);
00817           a1 = dx->AppUnitsToDevUnits();
00818           a2 = dx->DevUnitsToAppUnits();
00819           printf("    AppUnitsToDev = %f DevUnitsToApp = %f\n",a1,a2);
00820           dx->GetCanonicalPixelScale(a1);
00821           printf("    GetCanonicalPixelScale = %f\n",a1);
00822           dx->GetScrollBarDimensions(a1, a2);
00823           printf("    ScrollBar x = %f y = %f\n",a1,a2);
00824           dx->GetZoom(a1);
00825           printf("    Zoom = %f\n",a1);
00826           dx->GetDepth((PRUint32&)i1);
00827           printf("    Depth = %d\n",i1);
00828           dx->GetDeviceSurfaceDimensions(i1,i2);
00829           printf("    DeviceDimension w = %d h = %d\n",i1,i2);
00830 
00831 
00832           // DEVICE CONTEXT INFORMATION
00833           printf("DeviceContext created for print(%x)\n",mPrt->mPrintDC);
00834           a1 = mPrt->mPrintDC->DevUnitsToTwips();
00835           a2 = mPrt->mPrintDC->TwipsToDevUnits();
00836           printf("    DevToTwips = %f TwipToDev = %f\n",a1,a2);
00837           a1 = mPrt->mPrintDC->AppUnitsToDevUnits();
00838           a2 = mPrt->mPrintDC->DevUnitsToAppUnits();
00839           printf("    AppUnitsToDev = %f DevUnitsToApp = %f\n",a1,a2);
00840           mPrt->mPrintDC->GetCanonicalPixelScale(a1);
00841           printf("    GetCanonicalPixelScale = %f\n",a1);
00842           mPrt->mPrintDC->GetScrollBarDimensions(a1, a2);
00843           printf("    ScrollBar x = %f y = %f\n",a1,a2);
00844           mPrt->mPrintDC->GetZoom(a1);
00845           printf("    Zoom = %f\n",a1);
00846           mPrt->mPrintDC->GetDepth((PRUint32&)i1);
00847           printf("    Depth = %d\n",i1);
00848           mPrt->mPrintDC->GetDeviceSurfaceDimensions(i1,i2);
00849           printf("    DeviceDimension w = %d h = %d\n",i1,i2);
00850 
00851 #endif /* DEBUG_dcone */
00852 
00853           // Always check and set the print settings first and then fall back
00854           // onto the PrintService if there isn't a PrintSettings
00855           //
00856           // Posiible Usage values:
00857           //   nsIPrintSettings::kUseInternalDefault
00858           //   nsIPrintSettings::kUseSettingWhenPossible
00859           //
00860           // NOTE: The consts are the same for PrintSettings and PrintSettings
00861           PRInt16 printFrameTypeUsage = nsIPrintSettings::kUseSettingWhenPossible;
00862           mPrt->mPrintSettings->GetPrintFrameTypeUsage(&printFrameTypeUsage);
00863 
00864           // Ok, see if we are going to use our value and override the default
00865           if (printFrameTypeUsage == nsIPrintSettings::kUseSettingWhenPossible) {
00866             // Get the Print Options/Settings PrintFrameType to see what is preferred
00867             PRInt16 printFrameType = nsIPrintSettings::kEachFrameSep;
00868             mPrt->mPrintSettings->GetPrintFrameType(&printFrameType);
00869 
00870             // Don't let anybody do something stupid like try to set it to
00871             // kNoFrames when we are printing a FrameSet
00872             if (printFrameType == nsIPrintSettings::kNoFrames) {
00873               mPrt->mPrintFrameType = nsIPrintSettings::kEachFrameSep;
00874               mPrt->mPrintSettings->SetPrintFrameType(mPrt->mPrintFrameType);
00875             } else {
00876               // First find out from the PrinService what options are available
00877               // to us for Printing FrameSets
00878               PRInt16 howToEnableFrameUI;
00879               mPrt->mPrintSettings->GetHowToEnableFrameUI(&howToEnableFrameUI);
00880               if (howToEnableFrameUI != nsIPrintSettings::kFrameEnableNone) {
00881                 switch (howToEnableFrameUI) {
00882                 case nsIPrintSettings::kFrameEnableAll:
00883                   mPrt->mPrintFrameType = printFrameType;
00884                   break;
00885 
00886                 case nsIPrintSettings::kFrameEnableAsIsAndEach:
00887                   if (printFrameType != nsIPrintSettings::kSelectedFrame) {
00888                     mPrt->mPrintFrameType = printFrameType;
00889                   } else { // revert back to a good value
00890                     mPrt->mPrintFrameType = nsIPrintSettings::kEachFrameSep;
00891                   }
00892                   break;
00893                 } // switch
00894                 mPrt->mPrintSettings->SetPrintFrameType(mPrt->mPrintFrameType);
00895               }
00896             }
00897           } else {
00898             mPrt->mPrintSettings->GetPrintFrameType(&mPrt->mPrintFrameType);
00899           }
00900 
00901 #ifdef MOZ_LAYOUTDEBUG
00902           {
00903             // This is a special debugging regression tool section
00904             PRUnichar* tempFileName = nsnull;
00905             if (nsPrintEngine::IsDoingRuntimeTesting()) {
00906               // Here we check for a special filename (the destination for the print job)
00907               // and sets into the print settings if there is a name then we want to 
00908               // print to a file. if not, let it print normally.
00909               if (NS_SUCCEEDED(mLayoutDebugObj->GetPrintFileName(&tempFileName)) && tempFileName) {
00910                 if (*tempFileName) {
00911                   mPrt->mPrintSettings->SetPrintToFile(PR_TRUE);
00912                   mPrt->mPrintSettings->SetToFileName(tempFileName);
00913                 }
00914                 nsMemory::Free(tempFileName);
00915               }
00916 
00917               // Here we check to see how we should print a frameset (if there is one)
00918               PRBool asIs = PR_FALSE;
00919               if (NS_SUCCEEDED(mLayoutDebugObj->GetPrintAsIs(&asIs))) {
00920                 PRInt16 howToEnableFrameUI;
00921                 mPrt->mPrintSettings->GetHowToEnableFrameUI(&howToEnableFrameUI);
00922                 if (howToEnableFrameUI != nsIPrintSettings::kFrameEnableNone) {
00923                   mPrt->mPrintFrameType = asIs?nsIPrintSettings::kFramesAsIs:nsIPrintSettings::kEachFrameSep;
00924                   mPrt->mPrintSettings->SetPrintFrameType(mPrt->mPrintFrameType);
00925                 }
00926               }
00927             }
00928           }
00929 #endif
00930 
00931           // Get the Needed info for Calling PrepareDocument
00932           PRUnichar* fileName = nsnull;
00933           // check to see if we are printing to a file
00934           PRBool isPrintToFile = PR_FALSE;
00935           mPrt->mPrintSettings->GetPrintToFile(&isPrintToFile);
00936           if (isPrintToFile) {
00937             // On some platforms The PrepareDocument needs to know the name of the file
00938             // and it uses the PrintService to get it, so we need to set it into the PrintService here
00939             mPrt->mPrintSettings->GetToFileName(&fileName);
00940           }
00941 
00942           PRUnichar * docTitleStr;
00943           PRUnichar * docURLStr;
00944 
00945           GetDisplayTitleAndURL(mPrt->mPrintObject, mPrt->mPrintSettings, mPrt->mBrandName, &docTitleStr, &docURLStr, eDocTitleDefURLDoc); 
00946           PR_PL(("Title: %s\n", docTitleStr?NS_LossyConvertUCS2toASCII(docTitleStr).get():""));
00947           PR_PL(("URL:   %s\n", docURLStr?NS_LossyConvertUCS2toASCII(docURLStr).get():""));
00948 
00949           rv = mPrt->mPrintDC->PrepareDocument(docTitleStr, fileName);
00950 
00951           if (docTitleStr) nsMemory::Free(docTitleStr);
00952           if (docURLStr) nsMemory::Free(docURLStr);
00953 
00954           CHECK_RUNTIME_ERROR_CONDITION(nsIDebugObject::PRT_RUNTIME_PREPAREDOC, rv, NS_ERROR_FAILURE);
00955           if (NS_FAILED(rv)) {
00956             return CleanupOnFailure(rv, PR_TRUE);
00957           }
00958 
00959           PRBool doNotify;
00960           ShowPrintProgress(PR_TRUE, doNotify);
00961 
00962           if (!doNotify) {
00963             // Print listener setup...
00964             if (mPrt != nsnull) {
00965               mPrt->OnStartPrinting();    
00966             }
00967             rv = DocumentReadyForPrinting();
00968           }
00969         }
00970       }
00971     } else {
00972       mPrt->mPrintSettings->SetIsCancelled(PR_TRUE);
00973     }
00974   }
00975 
00976   /* cleaup on failure + notify user */
00977   if (NS_FAILED(rv)) {
00978     CleanupOnFailure(rv, PR_TRUE);
00979   }
00980 
00981   return rv;
00982 }
00983 
00991 NS_IMETHODIMP
00992 nsPrintEngine::PrintPreview(nsIPrintSettings* aPrintSettings, 
00993                                  nsIDOMWindow *aChildDOMWin, 
00994                                  nsIWebProgressListener* aWebProgressListener)
00995 {
00996   nsresult rv = NS_OK;
00997 
00998 #ifdef NS_PRINT_PREVIEW
00999 
01000   // Get the DocShell and see if it is busy
01001   // We can't Print or Print Preview this document if it is still busy
01002   nsCOMPtr<nsIDocShell> docShell(do_QueryInterface(mContainer));
01003   NS_ASSERTION(docShell, "This has to be a docshell");
01004 
01005   PRUint32 busyFlags = nsIDocShell::BUSY_FLAGS_NONE;
01006 
01007   // Preview this document if it is still busy
01008 
01009   if (NS_FAILED(docShell->GetBusyFlags(&busyFlags)) ||
01010       busyFlags != nsIDocShell::BUSY_FLAGS_NONE) {
01011     CloseProgressDialog(aWebProgressListener);
01012     ShowPrintErrorDialog(NS_ERROR_GFX_PRINTER_DOC_IS_BUSY_PP, PR_FALSE);
01013     return NS_ERROR_FAILURE;
01014   }
01015 
01016 #if (defined(XP_WIN) || defined(XP_OS2)) && defined(EXTENDED_DEBUG_PRINTING)
01017   if (!mIsDoingPrintPreview) {
01018     if (kPrintingLogMod && kPrintingLogMod->level == DUMP_LAYOUT_LEVEL) {
01019       RemoveFilesInDir(".\\");
01020     }
01021   }
01022 #endif
01023 
01024   if (mIsDoingPrintPreview) {
01025     mOldPrtPreview = mPrtPreview;
01026     mPrtPreview = nsnull;
01027   }
01028 
01029   mPrt = new nsPrintData(nsPrintData::eIsPrintPreview);
01030   if (!mPrt) {
01031     CloseProgressDialog(aWebProgressListener);
01032     SetIsCreatingPrintPreview(PR_FALSE);
01033     return NS_ERROR_OUT_OF_MEMORY;
01034   }
01035 
01036   // The WebProgressListener can be QI'ed to nsIPrintingPromptService
01037   // then that means the progress dialog is already being shown.
01038   nsCOMPtr<nsIPrintingPromptService> pps(do_QueryInterface(aWebProgressListener));
01039   mPrt->mProgressDialogIsShown = pps != nsnull;
01040 
01041   // Check to see if we need to transfer any of our old values
01042   // over to the new PrintData object
01043   if (mOldPrtPreview) {
01044     mPrt->mOrigZoom     = mOldPrtPreview->mOrigZoom;
01045     mPrt->mOrigDCScale  = mOldPrtPreview->mOrigDCScale;
01046 
01047   } else {
01048     // Get the Original PixelScale in case we need to start changing it
01049     mDeviceContext->GetCanonicalPixelScale(mPrt->mOrigDCScale);
01050   }
01051 
01052   // You have to have both a PrintOptions and a PrintSetting to call
01053   // CheckForPrinters.
01054   // The user can pass in a null PrintSettings, but you can only
01055   // create one if you have a PrintOptions.  So we we might as check
01056   // to if we have a PrintOptions first, because we can't do anything
01057   // below without it then inside we check to se if the printSettings
01058   // is null to know if we need to create on.
01059   // if they don't pass in a PrintSettings, then get the Global PS
01060   mPrt->mPrintSettings = aPrintSettings;
01061   if (!mPrt->mPrintSettings) {
01062     GetGlobalPrintSettings(getter_AddRefs(mPrt->mPrintSettings));
01063   }
01064 
01065   mPrt->mPrintOptions = do_GetService(sPrintOptionsContractID, &rv);
01066   if (NS_SUCCEEDED(rv) && mPrt->mPrintOptions && mPrt->mPrintSettings) {
01067     // Get the default printer name and set it into the PrintSettings
01068     rv = CheckForPrinters(mPrt->mPrintOptions, mPrt->mPrintSettings);
01069   } else {
01070     NS_ASSERTION(mPrt->mPrintSettings, "You can't Print without a PrintSettings!");
01071     rv = NS_ERROR_FAILURE;
01072   }
01073   if (NS_FAILED(rv)) {
01074     ShowPrintErrorDialog(rv, PR_FALSE);
01075     CloseProgressDialog(aWebProgressListener);
01076     return NS_ERROR_FAILURE;
01077   }
01078 
01079   // Let's print preview...
01080   SetIsCreatingPrintPreview(PR_TRUE);
01081   SetIsPrintPreview(PR_TRUE);
01082 
01083   // Get the currently focused window and cache it
01084   // because the Print Dialog will "steal" focus and later when you try
01085   // to get the currently focused windows it will be NULL
01086   mPrt->mCurrentFocusWin = FindFocusedDOMWindow();
01087 
01088   // Check to see if there is a "regular" selection
01089   PRBool isSelection = IsThereARangeSelection(mPrt->mCurrentFocusWin);
01090 
01091   // Create a list for storing the DocShells that need to be printed
01092   if (!mPrt->mPrintDocList) {
01093     mPrt->mPrintDocList = new nsVoidArray();
01094     if (!mPrt->mPrintDocList) {
01095       SetIsCreatingPrintPreview(PR_FALSE);
01096       SetIsPrintPreview(PR_FALSE);
01097       return NS_ERROR_OUT_OF_MEMORY;
01098     }
01099   } else {
01100     mPrt->mPrintDocList->Clear();
01101   }
01102 
01103   // Get the docshell for this documentviewer
01104   nsCOMPtr<nsIDocShell> webContainer(do_QueryInterface(mContainer));
01105 
01106   // Add Root Doc to Tree and List
01107   mPrt->mPrintObject = new nsPrintObject();
01108   if (NS_FAILED(mPrt->mPrintObject->Init(webContainer))) {
01109     CloseProgressDialog(aWebProgressListener);
01110     PR_PL(("NS_ERROR_FAILURE - Failed on Init of PrintObject"));
01111     return NS_ERROR_FAILURE;
01112   }
01113   mPrt->mPrintDocList->AppendElement(mPrt->mPrintObject);
01114 
01115   mPrt->mIsParentAFrameSet = IsParentAFrameSet(webContainer);
01116   mPrt->mPrintObject->mFrameType = mPrt->mIsParentAFrameSet ? eFrameSet : eDoc;
01117 
01118   // Build the "tree" of PrintObjects
01119   nsCOMPtr<nsIDocShellTreeNode>  parentAsNode(do_QueryInterface(webContainer));
01120   BuildDocTree(parentAsNode, mPrt->mPrintDocList, mPrt->mPrintObject);
01121 
01122   // Create the linkage from the suv-docs back to the content element
01123   // in the parent document
01124   MapContentToWebShells(mPrt->mPrintObject, mPrt->mPrintObject);
01125 
01126   // Get whether the doc contains a frameset
01127   // Also, check to see if the currently focus docshell
01128   // is a child of this docshell
01129   mPrt->mIsIFrameSelected = IsThereAnIFrameSelected(webContainer, mPrt->mCurrentFocusWin, mPrt->mIsParentAFrameSet);
01130 
01131 
01132   DUMP_DOC_LIST("\nAfter Mapping------------------------------------------");
01133 
01134   // Setup print options for UI
01135   rv = NS_ERROR_FAILURE;
01136   if (mPrt->mPrintSettings != nsnull) {
01137     mPrt->mPrintSettings->GetShrinkToFit(&mPrt->mShrinkToFit);
01138 
01139     if (mPrt->mIsParentAFrameSet) {
01140       if (mPrt->mCurrentFocusWin) {
01141         mPrt->mPrintSettings->SetHowToEnableFrameUI(nsIPrintSettings::kFrameEnableAll);
01142       } else {
01143         mPrt->mPrintSettings->SetHowToEnableFrameUI(nsIPrintSettings::kFrameEnableAsIsAndEach);
01144       }
01145     } else {
01146       mPrt->mPrintSettings->SetHowToEnableFrameUI(nsIPrintSettings::kFrameEnableNone);
01147     }
01148     // Now determine how to set up the Frame print UI
01149     mPrt->mPrintSettings->SetPrintOptions(nsIPrintSettings::kEnableSelectionRB, isSelection || mPrt->mIsIFrameSelected);
01150   }
01151 
01152 #ifdef PR_LOGGING
01153   if (mPrt->mPrintSettings) {
01154     PRInt16 printHowEnable = nsIPrintSettings::kFrameEnableNone;
01155     mPrt->mPrintSettings->GetHowToEnableFrameUI(&printHowEnable);
01156     PRBool val;
01157     mPrt->mPrintSettings->GetPrintOptions(nsIPrintSettings::kEnableSelectionRB, &val);
01158 
01159     PR_PL(("********* nsPrintEngine::Print *********\n"));
01160     PR_PL(("IsParentAFrameSet:   %s \n", PRT_YESNO(mPrt->mIsParentAFrameSet)));
01161     PR_PL(("IsIFrameSelected:    %s \n", PRT_YESNO(mPrt->mIsIFrameSelected)));
01162     PR_PL(("Main Doc Frame Type: %s \n", gFrameTypesStr[mPrt->mPrintObject->mFrameType]));
01163     PR_PL(("HowToEnableFrameUI:  %s \n", gFrameHowToEnableStr[printHowEnable]));
01164     PR_PL(("EnableSelectionRB:   %s \n", PRT_YESNO(val)));
01165     PR_PL(("*********************************************\n"));
01166   }
01167 #endif
01168 
01169   nscoord width  = NS_INCHES_TO_TWIPS(8.5);
01170   nscoord height = NS_INCHES_TO_TWIPS(11.0);
01171 
01172   nsCOMPtr<nsIDeviceContext> ppDC;
01173   nsCOMPtr<nsIDeviceContextSpecFactory> factory = do_CreateInstance(kDeviceContextSpecFactoryCID);
01174   if (factory) {
01175     nsCOMPtr<nsIDeviceContextSpec> devspec;
01176     nsCOMPtr<nsIDeviceContext> dx;
01177     rv = factory->CreateDeviceContextSpec(mWindow, mPrt->mPrintSettings,
01178                                           *getter_AddRefs(devspec), PR_TRUE);
01179     if (NS_SUCCEEDED(rv)) {
01180       rv = mDeviceContext->GetDeviceContextFor(devspec, *getter_AddRefs(ppDC));
01181       if (NS_SUCCEEDED(rv)) {
01182         mDeviceContext->SetAltDevice(ppDC);
01183         if (mPrt->mPrintSettings != nsnull) {
01184           // Shrink to Fit over rides and scaling values
01185           if (!mPrt->mShrinkToFit) {
01186             double scaling;
01187             mPrt->mPrintSettings->GetScaling(&scaling);
01188             mDeviceContext->SetCanonicalPixelScale(float(scaling)*mPrt->mOrigDCScale);
01189           }
01190         }
01191         ppDC->GetDeviceSurfaceDimensions(width, height);
01192       }
01193     }
01194   }
01195 
01196   mPrt->mPrintSettings->SetPrintFrameType(nsIPrintSettings::kFramesAsIs);
01197 
01198   // override any UI that wants to PrintPreview any selection or page range
01199   // we want to view every page in PrintPreview each time
01200   mPrt->mPrintSettings->SetPrintRange(nsIPrintSettings::kRangeAllPages);
01201 
01202   mPrt->mPrintDC = mDeviceContext;
01203 
01204   // Cache original Zoom value and then set it to 1.0
01205   mPrt->mPrintDC->GetZoom(mPrt->mOrigZoom);
01206   mPrt->mPrintDC->SetZoom(1.0f);
01207 
01208   if (mDeviceContext) {
01209     mDeviceContext->SetUseAltDC(kUseAltDCFor_FONTMETRICS, PR_TRUE);
01210     mDeviceContext->SetUseAltDC(kUseAltDCFor_CREATERC_REFLOW, PR_TRUE);
01211     mDeviceContext->SetUseAltDC(kUseAltDCFor_SURFACE_DIM, PR_TRUE);
01212   }
01213 
01214   PRBool cacheOldPres = CheckDocumentForPPCaching();
01215 
01216   // If we are caching the Presentation then
01217   // end observing the document BEFORE we do any new reflows
01218   if (cacheOldPres && !HasCachedPres()) {
01219     SetCacheOldPres(PR_TRUE);
01220     mPresContext->PresShell()->EndObservingDocument();
01221   }
01222 
01223   if (aWebProgressListener != nsnull) {
01224     mPrt->mPrintProgressListeners.AppendElement((void*)aWebProgressListener);
01225     NS_ADDREF(aWebProgressListener);
01226   }
01227 
01228   PRBool notifyOnInit = PR_FALSE;
01229   ShowPrintProgress(PR_FALSE, notifyOnInit);
01230 
01231   // Very important! Turn Off scripting
01232   TurnScriptingOn(PR_FALSE);
01233   
01234   if (!notifyOnInit) {
01235     rv = FinishPrintPreview();
01236   } else {
01237     rv = NS_OK;
01238   }
01239 
01240 #endif // NS_PRINT_PREVIEW
01241 
01242   return rv;
01243 }
01244 
01245 //----------------------------------------------------------------------
01246 NS_IMETHODIMP
01247 nsPrintEngine::PrintPreviewNavigate(PRInt16 aType, PRInt32 aPageNum)
01248 {
01249   return NS_ERROR_FAILURE;
01250 }
01251 
01252 //----------------------------------------------------------------------------------
01253 /* readonly attribute boolean isFramesetDocument; */
01254 NS_IMETHODIMP
01255 nsPrintEngine::GetIsFramesetDocument(PRBool *aIsFramesetDocument)
01256 {
01257   nsCOMPtr<nsIDocShell> webContainer(do_QueryInterface(mContainer));
01258   *aIsFramesetDocument = IsParentAFrameSet(webContainer);
01259   return NS_OK;
01260 }
01261 
01262 //----------------------------------------------------------------------------------
01263 /* readonly attribute boolean isIFrameSelected; */
01264 NS_IMETHODIMP 
01265 nsPrintEngine::GetIsIFrameSelected(PRBool *aIsIFrameSelected)
01266 {
01267   *aIsIFrameSelected = PR_FALSE;
01268 
01269   // Get the docshell for this documentviewer
01270   nsCOMPtr<nsIDocShell> webContainer(do_QueryInterface(mContainer));
01271   // Get the currently focused window
01272   nsCOMPtr<nsIDOMWindow> currentFocusWin = FindFocusedDOMWindow();
01273   if (currentFocusWin && webContainer) {
01274     // Get whether the doc contains a frameset 
01275     // Also, check to see if the currently focus docshell
01276     // is a child of this docshell
01277     PRPackedBool isParentFrameSet;
01278     *aIsIFrameSelected = IsThereAnIFrameSelected(webContainer, currentFocusWin, isParentFrameSet);
01279   }
01280   return NS_OK;
01281 }
01282 
01283 //----------------------------------------------------------------------------------
01284 /* readonly attribute boolean isRangeSelection; */
01285 NS_IMETHODIMP 
01286 nsPrintEngine::GetIsRangeSelection(PRBool *aIsRangeSelection)
01287 {
01288   // Get the currently focused window 
01289   nsCOMPtr<nsIDOMWindow> currentFocusWin = FindFocusedDOMWindow();
01290   *aIsRangeSelection = IsThereARangeSelection(currentFocusWin);
01291   return NS_OK;
01292 }
01293 
01294 //----------------------------------------------------------------------------------
01295 /* readonly attribute boolean isFramesetFrameSelected; */
01296 NS_IMETHODIMP 
01297 nsPrintEngine::GetIsFramesetFrameSelected(PRBool *aIsFramesetFrameSelected)
01298 {
01299   // Get the currently focused window 
01300   nsCOMPtr<nsIDOMWindow> currentFocusWin = FindFocusedDOMWindow();
01301   *aIsFramesetFrameSelected = currentFocusWin != nsnull;
01302   return NS_OK;
01303 }
01304 
01305 //----------------------------------------------------------------------------------
01306 /* readonly attribute long printPreviewNumPages; */
01307 NS_IMETHODIMP
01308 nsPrintEngine::GetPrintPreviewNumPages(PRInt32 *aPrintPreviewNumPages)
01309 {
01310   NS_ENSURE_ARG_POINTER(aPrintPreviewNumPages);
01311 
01312   // Finds the SimplePageSequencer frame
01313   // in PP mPrtPreview->mPrintObject->mSeqFrame is null
01314   nsIFrame* seqFrame  = nsnull;
01315   *aPrintPreviewNumPages = 0;
01316   if (!mPrtPreview ||
01317       NS_FAILED(GetSeqFrameAndCountPagesInternal(mPrtPreview->mPrintObject, seqFrame, *aPrintPreviewNumPages))) {
01318     return NS_ERROR_FAILURE;
01319   }
01320   return NS_OK;
01321 }
01322 
01323 //----------------------------------------------------------------------------------
01324 /* void exitPrintPreview (); */
01325 NS_IMETHODIMP
01326 nsPrintEngine::ExitPrintPreview()
01327 {
01328   return NS_ERROR_FAILURE;
01329 }
01330 
01331 //----------------------------------------------------------------------------------
01332 // Enumerate all the documents for their titles
01333 NS_IMETHODIMP
01334 nsPrintEngine::EnumerateDocumentNames(PRUint32* aCount,
01335                                       PRUnichar*** aResult)
01336 {
01337   NS_ENSURE_ARG(aCount);
01338   NS_ENSURE_ARG_POINTER(aResult);
01339 
01340   *aCount = 0;
01341   *aResult = nsnull;
01342 
01343   PRInt32     numDocs = mPrt->mPrintDocList->Count();
01344   PRUnichar** array   = (PRUnichar**) nsMemory::Alloc(numDocs * sizeof(PRUnichar*));
01345   if (!array)
01346     return NS_ERROR_OUT_OF_MEMORY;
01347 
01348   for (PRInt32 i=0;i<numDocs;i++) {
01349     nsPrintObject* po = (nsPrintObject*)mPrt->mPrintDocList->ElementAt(i);
01350     NS_ASSERTION(po, "nsPrintObject can't be null!");
01351     PRUnichar * docTitleStr;
01352     PRUnichar * docURLStr;
01353     GetDocumentTitleAndURL(po->mDocument, &docTitleStr, &docURLStr);
01354 
01355     // Use the URL if the doc is empty
01356     if (!docTitleStr || !*docTitleStr) {
01357       if (docURLStr && *docURLStr) {
01358         nsMemory::Free(docTitleStr);
01359         docTitleStr = docURLStr;
01360       } else {
01361         nsMemory::Free(docURLStr);
01362       }
01363       docURLStr = nsnull;
01364       if (!docTitleStr || !*docTitleStr) {
01365         CleanupDocTitleArray(array, i);
01366         return NS_ERROR_OUT_OF_MEMORY;
01367       }
01368     }
01369     array[i] = docTitleStr;
01370     if (docURLStr) nsMemory::Free(docURLStr);
01371   }
01372   *aCount  = numDocs;
01373   *aResult = array;
01374 
01375   return NS_OK;
01376 
01377 }
01378 
01379 //----------------------------------------------------------------------------------
01380 /* readonly attribute nsIPrintSettings globalPrintSettings; */
01381 NS_IMETHODIMP
01382 nsPrintEngine::GetGlobalPrintSettings(nsIPrintSettings * *aGlobalPrintSettings)
01383 {
01384   NS_ENSURE_ARG_POINTER(aGlobalPrintSettings);
01385 
01386   nsresult rv = NS_ERROR_FAILURE;
01387   nsCOMPtr<nsIPrintSettingsService> printSettingsService = do_GetService(sPrintSettingsServiceContractID, &rv);
01388   if (NS_SUCCEEDED(rv)) {
01389     rv = printSettingsService->GetGlobalPrintSettings(aGlobalPrintSettings);
01390   }
01391   return rv;
01392 }
01393 
01394 //----------------------------------------------------------------------------------
01395 static void
01396 GetParentWebBrowserPrint(nsISupports *aContainer, nsIWebBrowserPrint **aParent)
01397 {
01398   *aParent = nsnull;
01399 
01400   nsCOMPtr<nsIDocShellTreeItem> item(do_QueryInterface(aContainer));
01401 
01402   if (item) {
01403     nsCOMPtr<nsIDocShellTreeItem> parent;
01404     item->GetParent(getter_AddRefs(parent));
01405 
01406     nsCOMPtr<nsIDocShell> docShell(do_QueryInterface(parent));
01407 
01408     if (docShell) {
01409       nsCOMPtr<nsIContentViewer> viewer;
01410       docShell->GetContentViewer(getter_AddRefs(viewer));
01411 
01412       if (viewer) {
01413         CallQueryInterface(viewer, aParent);
01414       }
01415     }
01416   }
01417 }
01418 
01419 //----------------------------------------------------------------------------------
01420 /* readonly attribute boolean doingPrint; */
01421 NS_IMETHODIMP
01422 nsPrintEngine::GetDoingPrint(PRBool *aDoingPrint)
01423 {
01424   NS_ENSURE_ARG_POINTER(aDoingPrint);
01425   *aDoingPrint = mIsDoingPrinting;
01426 
01427   if (!*aDoingPrint) {
01428     nsCOMPtr<nsIWebBrowserPrint> wbp;
01429     GetParentWebBrowserPrint(mContainer, getter_AddRefs(wbp));
01430 
01431     if (wbp) {
01432       return wbp->GetDoingPrint(aDoingPrint);
01433     }
01434   }
01435 
01436   return NS_OK;
01437 }
01438 
01439 //----------------------------------------------------------------------------------
01440 /* readonly attribute boolean doingPrintPreview; */
01441 NS_IMETHODIMP
01442 nsPrintEngine::GetDoingPrintPreview(PRBool *aDoingPrintPreview)
01443 {
01444   NS_ENSURE_ARG_POINTER(aDoingPrintPreview);
01445   *aDoingPrintPreview = mIsDoingPrintPreview;
01446 
01447   if (!*aDoingPrintPreview) {
01448     nsCOMPtr<nsIWebBrowserPrint> wbp;
01449     GetParentWebBrowserPrint(mContainer, getter_AddRefs(wbp));
01450 
01451     if (wbp) {
01452       return wbp->GetDoingPrintPreview(aDoingPrintPreview);
01453     }
01454   }
01455 
01456   return NS_OK;
01457 }
01458 
01459 //----------------------------------------------------------------------------------
01460 /* readonly attribute nsIPrintSettings currentPrintSettings; */
01461 NS_IMETHODIMP
01462 nsPrintEngine::GetCurrentPrintSettings(nsIPrintSettings * *aCurrentPrintSettings)
01463 {
01464   NS_ENSURE_ARG_POINTER(aCurrentPrintSettings);
01465 
01466   if (mPrt) {
01467     *aCurrentPrintSettings = mPrt->mPrintSettings;
01468 
01469   } else if (mPrtPreview) {
01470     *aCurrentPrintSettings = mPrtPreview->mPrintSettings;
01471 
01472   } else {
01473     *aCurrentPrintSettings = nsnull;
01474   }
01475   NS_IF_ADDREF(*aCurrentPrintSettings);
01476   return NS_OK;
01477 }
01478 
01479 //----------------------------------------------------------------------------------
01480 /* readonly attribute nsIDOMWindow currentChildDOMWindow; */
01481 NS_IMETHODIMP 
01482 nsPrintEngine::GetCurrentChildDOMWindow(nsIDOMWindow * *aCurrentChildDOMWindow)
01483 {
01484   NS_ENSURE_ARG_POINTER(aCurrentChildDOMWindow);
01485   *aCurrentChildDOMWindow = nsnull;
01486   return NS_ERROR_NOT_IMPLEMENTED;
01487 }
01488 
01489 //----------------------------------------------------------------------------------
01490 /* void cancel (); */
01491 NS_IMETHODIMP
01492 nsPrintEngine::Cancel()
01493 {
01494   if (mPrt && mPrt->mPrintSettings) {
01495     return mPrt->mPrintSettings->SetIsCancelled(PR_TRUE);
01496   }
01497   return NS_ERROR_FAILURE;
01498 }
01499 
01500 //-----------------------------------------------------------------
01501 //-- Section: Pre-Reflow Methods
01502 //-----------------------------------------------------------------
01503 
01504 //---------------------------------------------------------------------
01505 // This method checks to see if there is at least one printer defined
01506 // and if so, it sets the first printer in the list as the default name
01507 // in the PrintSettings which is then used for Printer Preview
01508 nsresult
01509 nsPrintEngine::CheckForPrinters(nsIPrintOptions*  aPrintOptions,
01510                                 nsIPrintSettings* aPrintSettings)
01511 {
01512   NS_ENSURE_ARG_POINTER(aPrintOptions);
01513   NS_ENSURE_ARG_POINTER(aPrintSettings);
01514 
01515   nsresult rv;
01516 
01517   nsCOMPtr<nsISimpleEnumerator> simpEnum;
01518   rv = aPrintOptions->AvailablePrinters(getter_AddRefs(simpEnum));
01519   if (simpEnum) {
01520     PRBool fndPrinter = PR_FALSE;
01521     simpEnum->HasMoreElements(&fndPrinter);
01522     if (fndPrinter) {
01523       // For now, it assumes the first item in the list
01524       // is the default printer, but only set the
01525       // printer name if there isn't one
01526       nsCOMPtr<nsISupports> supps;
01527       simpEnum->GetNext(getter_AddRefs(supps));
01528       PRUnichar* defPrinterName;
01529       aPrintSettings->GetPrinterName(&defPrinterName);
01530       if (!defPrinterName || !*defPrinterName) {
01531         if (defPrinterName) nsMemory::Free(defPrinterName);
01532         nsCOMPtr<nsISupportsString> wStr = do_QueryInterface(supps);
01533         if (wStr) {
01534           wStr->ToString(&defPrinterName);
01535           aPrintSettings->SetPrinterName(defPrinterName);
01536           nsMemory::Free(defPrinterName);
01537         }
01538       } else {
01539         nsMemory::Free(defPrinterName);
01540       }
01541       rv = NS_OK;
01542     }
01543   } else {
01544     // this means there were no printers
01545     // XXX the ifdefs are temporary until they correctly implement Available Printers
01546 #if defined(XP_MAC) || defined(XP_MACOSX)
01547     rv = NS_OK;
01548 #endif
01549   }
01550   return rv;
01551 }
01552 
01557 PRBool
01558 nsPrintEngine::CheckDocumentForPPCaching()
01559 {
01560   // Here is where we determine if we need to cache the old presentation
01561   PRBool cacheOldPres = PR_FALSE;
01562 
01563   // Only check if it is the first time into PP
01564   if (!mOldPrtPreview) {
01565     // First check the Pref
01566     cacheOldPres = nsContentUtils::GetBoolPref("print.always_cache_old_pres");
01567 
01568     // Temp fix for FrameSet Print Preview Bugs
01569     if (!cacheOldPres && mPrt->mPrintObject->mFrameType == eFrameSet) {
01570       cacheOldPres = PR_TRUE;
01571     }
01572 
01573     if (!cacheOldPres) {
01574       for (PRInt32 i=0;i<mPrt->mPrintDocList->Count();i++) {
01575         nsPrintObject* po = (nsPrintObject*)mPrt->mPrintDocList->ElementAt(i);
01576         NS_ASSERTION(po, "nsPrintObject can't be null!");
01577 
01578         // Temp fix for FrameSet Print Preview Bugs
01579         if (po->mFrameType == eIFrame) {
01580           cacheOldPres = PR_TRUE;
01581           break;
01582         }
01583 
01584         // If we aren't caching because of prefs check embeds.
01585         nsCOMPtr<nsIDOMNSHTMLDocument> nshtmlDoc = do_QueryInterface(po->mDocument);
01586         if (nshtmlDoc) {
01587           nsCOMPtr<nsIDOMHTMLCollection> applets;
01588           nshtmlDoc->GetEmbeds(getter_AddRefs(applets));
01589           if (applets) {
01590             PRUint32 length = 0;
01591             if (NS_SUCCEEDED(applets->GetLength(&length))) {
01592               if (length > 0) {
01593                 cacheOldPres = PR_TRUE;
01594                 break;
01595               }
01596             }
01597           }
01598         }
01599 
01600         // If we aren't caching because of prefs or embeds check applets.
01601         nsCOMPtr<nsIDOMHTMLDocument> htmldoc = do_QueryInterface(po->mDocument);
01602         if (htmldoc) {
01603           nsCOMPtr<nsIDOMHTMLCollection> embeds;
01604           htmldoc->GetApplets(getter_AddRefs(embeds));
01605           if (embeds) {
01606             PRUint32 length = 0;
01607             if (NS_SUCCEEDED(embeds->GetLength(&length))) {
01608               if (length > 0) {
01609                 cacheOldPres = PR_TRUE;
01610                 break;
01611               }
01612             }
01613           }
01614         }
01615       }
01616     }
01617   }
01618   return cacheOldPres;
01619 }
01620 
01621 //----------------------------------------------------------------------
01622 // Set up to use the "pluggable" Print Progress Dialog
01623 void
01624 nsPrintEngine::ShowPrintProgress(PRBool aIsForPrinting, PRBool& aDoNotify)
01625 {
01626   // default to not notifying, that if something here goes wrong
01627   // or we aren't going to show the progress dialog we can straight into 
01628   // reflowing the doc for printing.
01629   aDoNotify = PR_FALSE;
01630 
01631   // Assume we can't do progress and then see if we can
01632   mPrt->mShowProgressDialog = PR_FALSE;
01633 
01634   // if it is already being shown then don't bother to find out if it should be
01635   // so skip this and leave mShowProgressDialog set to FALSE
01636   if (!mPrt->mProgressDialogIsShown) {
01637     mPrt->mShowProgressDialog =
01638       nsContentUtils::GetBoolPref("print.show_print_progress");
01639   }
01640 
01641   // Turning off the showing of Print Progress in Prefs overrides
01642   // whether the calling PS desire to have it on or off, so only check PS if 
01643   // prefs says it's ok to be on.
01644   if (mPrt->mShowProgressDialog) {
01645     mPrt->mPrintSettings->GetShowPrintProgress(&mPrt->mShowProgressDialog);
01646   }
01647 
01648   // Now open the service to get the progress dialog
01649   // If we don't get a service, that's ok, then just don't show progress
01650   if (mPrt->mShowProgressDialog) {
01651     nsCOMPtr<nsIPrintingPromptService> printPromptService(do_GetService(kPrintingPromptService));
01652     if (printPromptService) {
01653       nsCOMPtr<nsIDOMWindow> domWin = do_QueryInterface(mDocument->GetScriptGlobalObject()); 
01654       if (!domWin) return;
01655 
01656       nsCOMPtr<nsIWebBrowserPrint> wbp(do_QueryInterface(mDocViewerPrint));
01657       nsresult rv = printPromptService->ShowProgress(domWin, wbp, mPrt->mPrintSettings, this, aIsForPrinting,
01658                                                      getter_AddRefs(mPrt->mPrintProgressListener), 
01659                                                      getter_AddRefs(mPrt->mPrintProgressParams), 
01660                                                      &aDoNotify);
01661       if (NS_SUCCEEDED(rv)) {
01662         mPrt->mShowProgressDialog = mPrt->mPrintProgressListener != nsnull && mPrt->mPrintProgressParams != nsnull;
01663 
01664         if (mPrt->mShowProgressDialog) {
01665           mPrt->mPrintProgressListeners.AppendElement((void*)mPrt->mPrintProgressListener);
01666           nsIWebProgressListener* wpl = NS_STATIC_CAST(nsIWebProgressListener*, mPrt->mPrintProgressListener.get());
01667           NS_ASSERTION(wpl, "nsIWebProgressListener is NULL!");
01668           NS_ADDREF(wpl);
01669           SetDocAndURLIntoProgress(mPrt->mPrintObject, mPrt->mPrintProgressParams);
01670         }
01671       }
01672     }
01673   }
01674 }
01675 
01676 //---------------------------------------------------------------------
01677 PRBool
01678 nsPrintEngine::IsThereARangeSelection(nsIDOMWindow* aDOMWin)
01679 {
01680   nsCOMPtr<nsIPresShell> presShell;
01681   if (aDOMWin) {
01682     nsCOMPtr<nsIScriptGlobalObject> scriptObj(do_QueryInterface(aDOMWin));
01683     scriptObj->GetDocShell()->GetPresShell(getter_AddRefs(presShell));
01684   }
01685 
01686   // check here to see if there is a range selection
01687   // so we know whether to turn on the "Selection" radio button
01688   nsCOMPtr<nsISelection> selection;
01689   mDocViewerPrint->GetDocumentSelection(getter_AddRefs(selection), presShell);
01690   if (selection) {
01691     PRInt32 count;
01692     selection->GetRangeCount(&count);
01693     if (count == 1) {
01694       nsCOMPtr<nsIDOMRange> range;
01695       if (NS_SUCCEEDED(selection->GetRangeAt(0, getter_AddRefs(range)))) {
01696         // check to make sure it isn't an insertion selection
01697         PRBool isCollapsed;
01698         selection->GetIsCollapsed(&isCollapsed);
01699         return !isCollapsed;
01700       }
01701     }
01702   }
01703   return PR_FALSE;
01704 }
01705 
01706 //---------------------------------------------------------------------
01707 PRBool
01708 nsPrintEngine::IsParentAFrameSet(nsIDocShell * aParent)
01709 {
01710   NS_ASSERTION(aParent, "Pointer is null!");
01711 
01712   nsCOMPtr<nsIPresShell> shell;
01713   aParent->GetPresShell(getter_AddRefs(shell));
01714   NS_ASSERTION(shell, "shell can't be null");
01715 
01716   // See if if the incoming doc is the root document
01717   nsCOMPtr<nsIDocShellTreeItem> parentAsItem(do_QueryInterface(aParent));
01718   if (!parentAsItem) return PR_FALSE;
01719 
01720   // When it is the top level document we need to check
01721   // to see if it contains a frameset. If it does, then
01722   // we only want to print the doc's children and not the document itself
01723   // For anything else we always print all the children and the document
01724   // for example, if the doc contains an IFRAME we eant to print the child
01725   // document (the IFRAME) and then the rest of the document.
01726   //
01727   // XXX we really need to search the frame tree, and not the content
01728   // but there is no way to distinguish between IFRAMEs and FRAMEs
01729   // with the GetFrameType call.
01730   // Bug 53459 has been files so we can eventually distinguish
01731   // between IFRAME frames and FRAME frames
01732   PRBool isFrameSet = PR_FALSE;
01733   // only check to see if there is a frameset if there is
01734   // NO parent doc for this doc. meaning this parent is the root doc
01735   if (shell) {
01736     nsIDocument *doc = shell->GetDocument();
01737     if (doc) {
01738       nsIContent *rootContent = doc->GetRootContent();
01739       if (rootContent) {
01740         isFrameSet = HasFramesetChild(rootContent);
01741       }
01742     }
01743   }
01744   return isFrameSet;
01745 }
01746 
01747 
01748 //---------------------------------------------------------------------
01749 // Recursively build a list of of sub documents to be printed
01750 // that mirrors the document tree
01751 void
01752 nsPrintEngine::BuildDocTree(nsIDocShellTreeNode * aParentNode,
01753                                  nsVoidArray *         aDocList,
01754                                  nsPrintObject *         aPO)
01755 {
01756   NS_ASSERTION(aParentNode, "Pointer is null!");
01757   NS_ASSERTION(aDocList, "Pointer is null!");
01758   NS_ASSERTION(aPO, "Pointer is null!");
01759 
01760   // Get the Doc and Title String
01761   GetDocumentTitleAndURL(aPO->mDocument, &aPO->mDocTitle, &aPO->mDocURL);
01762 
01763   PRInt32 childWebshellCount;
01764   aParentNode->GetChildCount(&childWebshellCount);
01765   if (childWebshellCount > 0) {
01766     for (PRInt32 i=0;i<childWebshellCount;i++) {
01767       nsCOMPtr<nsIDocShellTreeItem> child;
01768       aParentNode->GetChildAt(i, getter_AddRefs(child));
01769       nsCOMPtr<nsIDocShell> childAsShell(do_QueryInterface(child));
01770 
01771       nsCOMPtr<nsIPresShell> presShell;
01772       childAsShell->GetPresShell(getter_AddRefs(presShell));
01773 
01774       if (!presShell) {
01775         continue;
01776       }
01777 
01778       nsCOMPtr<nsIContentViewer>  viewer;
01779       childAsShell->GetContentViewer(getter_AddRefs(viewer));
01780       if (viewer) {
01781         nsCOMPtr<nsIContentViewerFile> viewerFile(do_QueryInterface(viewer));
01782         if (viewerFile) {
01783           nsCOMPtr<nsIDocShell> childDocShell(do_QueryInterface(child));
01784           nsCOMPtr<nsIDocShellTreeNode> childNode(do_QueryInterface(child));
01785           nsPrintObject * po = new nsPrintObject();
01786           if (NS_FAILED(po->Init(childDocShell))) {
01787             NS_ASSERTION(0, "Failed initializing the Print Object");
01788           }
01789           po->mParent   = aPO;
01790           aPO->mKids.AppendElement(po);
01791           aDocList->AppendElement(po);
01792           BuildDocTree(childNode, aDocList, po);
01793         }
01794       }
01795     }
01796   }
01797 }
01798 
01799 //---------------------------------------------------------------------
01800 void
01801 nsPrintEngine::GetDocumentTitleAndURL(nsIDocument* aDoc,
01802                                       PRUnichar**  aTitle,
01803                                       PRUnichar**  aURLStr)
01804 {
01805   NS_ASSERTION(aDoc,      "Pointer is null!");
01806   NS_ASSERTION(aTitle,    "Pointer is null!");
01807   NS_ASSERTION(aURLStr,   "Pointer is null!");
01808 
01809   *aTitle  = nsnull;
01810   *aURLStr = nsnull;
01811 
01812   const nsAString &docTitle = aDoc->GetDocumentTitle();
01813   if (!docTitle.IsEmpty()) {
01814     *aTitle = ToNewUnicode(docTitle);
01815   }
01816 
01817   nsIURI* url = aDoc->GetDocumentURI();
01818   if (!url) return;
01819 
01820   nsCOMPtr<nsIURIFixup> urifixup(do_GetService(NS_URIFIXUP_CONTRACTID));
01821   if (!urifixup) return;
01822 
01823   nsCOMPtr<nsIURI> exposableURI;
01824   urifixup->CreateExposableURI(url, getter_AddRefs(exposableURI));
01825 
01826   if (!exposableURI) return;
01827 
01828   nsCAutoString urlCStr;
01829   exposableURI->GetSpec(urlCStr);
01830   *aURLStr = UTF8ToNewUnicode(urlCStr);
01831 }
01832 
01833 //---------------------------------------------------------------------
01834 // The walks the PO tree and for each document it walks the content
01835 // tree looking for any content that are sub-shells
01836 //
01837 // It then sets the mContent pointer in the "found" PO object back to the
01838 // the document that contained it.
01839 void
01840 nsPrintEngine::MapContentToWebShells(nsPrintObject* aRootPO,
01841                                           nsPrintObject* aPO)
01842 {
01843   NS_ASSERTION(aRootPO, "Pointer is null!");
01844   NS_ASSERTION(aPO, "Pointer is null!");
01845 
01846   // Recursively walk the content from the root item
01847   nsCOMPtr<nsIPresShell> presShell;
01848   nsCOMPtr<nsIContent> rootContent;
01849   GetPresShellAndRootContent(aPO->mDocShell, getter_AddRefs(presShell), getter_AddRefs(rootContent));
01850   if (presShell && rootContent) {
01851     MapContentForPO(aRootPO, presShell, rootContent);
01852   }
01853 
01854   // Continue recursively walking the chilren of this PO
01855   for (PRInt32 i=0;i<aPO->mKids.Count();i++) {
01856     MapContentToWebShells(aRootPO, (nsPrintObject*)aPO->mKids[i]);
01857   }
01858 
01859 }
01860 
01861 //-------------------------------------------------------
01862 // A Frame's sub-doc may contain content or a FrameSet
01863 // When it contains a FrameSet the mFrameType for the PrintObject
01864 // is always set to an eFrame. Which is fine when printing "AsIs"
01865 // but is incorrect when when printing "Each Frame Separately".
01866 // When printing "Each Frame Separately" the Frame really acts like
01867 // a frameset.
01868 //
01869 // This method walks the PO tree and checks to see if the PrintObject is
01870 // an eFrame and has children that are eFrames (meaning it's a Frame containing a FrameSet)
01871 // If so, then the mFrameType need to be changed to eFrameSet
01872 //
01873 // Also note: We only want to call this we are printing "Each Frame Separately"
01874 //            when printing "As Is" leave it as an eFrame
01875 void
01876 nsPrintEngine::CheckForChildFrameSets(nsPrintObject* aPO)
01877 {
01878   NS_ASSERTION(aPO, "Pointer is null!");
01879 
01880   // Continue recursively walking the chilren of this PO
01881   PRBool hasChildFrames = PR_FALSE;
01882   for (PRInt32 i=0;i<aPO->mKids.Count();i++) {
01883     nsPrintObject* po = (nsPrintObject*)aPO->mKids[i];
01884     CheckForChildFrameSets(po);
01885     if (po->mFrameType == eFrame) {
01886       hasChildFrames = PR_TRUE;
01887     }
01888   }
01889 
01890   if (hasChildFrames && aPO->mFrameType == eFrame) {
01891     aPO->mFrameType = eFrameSet;
01892   }
01893 }
01894 
01895 //---------------------------------------------------------------------
01896 // This method is key to the entire print mechanism.
01897 //
01898 // This "maps" or figures out which sub-doc represents a
01899 // given Frame or IFrame in it's parent sub-doc.
01900 //
01901 // So the Mcontent pointer in the child sub-doc points to the
01902 // content in the it's parent document, that caused it to be printed.
01903 // This is used later to (after reflow) to find the absolute location
01904 // of the sub-doc on it's parent's page frame so it can be
01905 // printed in the correct location.
01906 //
01907 // This method recursvely "walks" the content for a document finding
01908 // all the Frames and IFrames, then sets the "mFrameType" data member
01909 // which tells us what type of PO we have
01910 void
01911 nsPrintEngine::MapContentForPO(nsPrintObject*   aRootObject,
01912                                     nsIPresShell*  aPresShell,
01913                                     nsIContent*    aContent)
01914 {
01915   NS_ASSERTION(aRootObject, "Pointer is null!");
01916   NS_ASSERTION(aPresShell, "Pointer is null!");
01917   NS_ASSERTION(aContent, "Pointer is null!");
01918 
01919   nsIDocument* doc = aContent->GetDocument();
01920 
01921   if (!doc) {
01922     NS_ERROR("No document!");
01923 
01924     return;
01925   }
01926 
01927   nsIDocument* subDoc = doc->GetSubDocumentFor(aContent);
01928 
01929   if (subDoc) {
01930     nsIPresShell *presShell = subDoc->GetShellAt(0);
01931 
01932     nsCOMPtr<nsISupports> container = subDoc->GetContainer();
01933     nsCOMPtr<nsIDocShell> docShell(do_QueryInterface(container));
01934 
01935     if (presShell && docShell) {
01936       nsPrintObject * po = FindPrintObjectByDS(aRootObject, docShell);
01937       NS_ASSERTION(po, "PO can't be null!");
01938 
01939       if (po) {
01940         po->mContent  = aContent;
01941 
01942         // Now, "type" the PO
01943         nsCOMPtr<nsIDOMHTMLFrameSetElement> frameSet =
01944           do_QueryInterface(aContent);
01945 
01946         if (frameSet) {
01947           po->mFrameType = eFrameSet;
01948         } else {
01949           nsCOMPtr<nsIDOMHTMLFrameElement> frame(do_QueryInterface(aContent));
01950           if (frame) {
01951             po->mFrameType = eFrame;
01952           } else {
01953             nsCOMPtr<nsIDOMHTMLObjectElement> objElement =
01954               do_QueryInterface(aContent);
01955             nsCOMPtr<nsIDOMHTMLIFrameElement> iFrame =
01956               do_QueryInterface(aContent);
01957             nsCOMPtr<nsIDOMHTMLEmbedElement> embedElement =
01958               do_QueryInterface(aContent);
01959 
01960             if (iFrame || objElement || embedElement) {
01961               po->mFrameType = eIFrame;
01962               po->mPrintAsIs = PR_TRUE;
01963               if (po->mParent) {
01964                 po->mParent->mPrintAsIs = PR_TRUE;
01965               }
01966             }
01967           }
01968         }
01969       }
01970     }
01971   }
01972 
01973   // walk children content
01974   PRUint32 count = aContent->GetChildCount();
01975   for (PRUint32 i = 0; i < count; ++i) {
01976     nsIContent *child = aContent->GetChildAt(i);
01977     MapContentForPO(aRootObject, aPresShell, child);
01978   }
01979 }
01980 
01981 //---------------------------------------------------------------------
01982 // Recursively finds a nsPrintObject that has the aDocShell
01983 nsPrintObject * nsPrintEngine::FindPrintObjectByDS(nsPrintObject* aPO, nsIDocShell * aDocShell)
01984 {
01985   NS_ASSERTION(aPO, "Pointer is null!");
01986   NS_ASSERTION(aDocShell, "Pointer is null!");
01987 
01988   if (aPO->mDocShell == aDocShell) {
01989     return aPO;
01990   }
01991   PRInt32 cnt = aPO->mKids.Count();
01992   for (PRInt32 i=0;i<cnt;i++) {
01993     nsPrintObject* kid = (nsPrintObject*)aPO->mKids.ElementAt(i);
01994     NS_ASSERTION(kid, "nsPrintObject can't be null!");
01995     nsPrintObject* po = FindPrintObjectByDS(kid, aDocShell);
01996     if (po != nsnull) {
01997       return po;
01998     }
01999   }
02000   return nsnull;
02001 }
02002 
02003 //---------------------------------------------------------------------
02004 PRBool
02005 nsPrintEngine::IsThereAnIFrameSelected(nsIDocShell* aDocShell,
02006                                        nsIDOMWindow* aDOMWin,
02007                                        PRPackedBool& aIsParentFrameSet)
02008 {
02009   aIsParentFrameSet = IsParentAFrameSet(aDocShell);
02010   PRBool iFrameIsSelected = PR_FALSE;
02011   if (mPrt && mPrt->mPrintObject) {
02012     nsPrintObject* po = FindPrintObjectByDOMWin(mPrt->mPrintObject, aDOMWin);
02013     iFrameIsSelected = po && po->mFrameType == eIFrame;
02014   } else {
02015     // First, check to see if we are a frameset
02016     if (!aIsParentFrameSet) {
02017       // Check to see if there is a currenlt focused frame
02018       // if so, it means the selected frame is either the main docshell
02019       // or an IFRAME
02020       if (aDOMWin) {
02021         // Get the main docshell's DOMWin to see if it matches 
02022         // the frame that is selected
02023         nsCOMPtr<nsIDOMWindow> domWin = do_GetInterface(aDocShell);
02024         if (domWin != aDOMWin) {
02025           iFrameIsSelected = PR_TRUE; // we have a selected IFRAME
02026         }
02027       }
02028     }
02029   }
02030 
02031   return iFrameIsSelected;
02032 }
02033 
02034 //---------------------------------------------------------------------
02035 // Recursively sets all the PO items to be printed
02036 // from the given item down into the tree
02037 void
02038 nsPrintEngine::SetPrintPO(nsPrintObject* aPO, PRBool aPrint,
02039                                PRBool aIsHidden, PRUint32 aFlags)
02040 {
02041   NS_ASSERTION(aPO, "Pointer is null!");
02042 
02043   // Set whether to print flag
02044   // If it is hidden dont' allow ANY changes to the mDontPrint
02045   // because mDontPrint has already been turned off
02046   if ((aFlags & eSetPrintFlag) && !aPO->mIsHidden) aPO->mDontPrint = !aPrint;
02047 
02048   // Set hidden flag
02049   if (aFlags & eSetHiddenFlag) aPO->mIsHidden = aIsHidden;
02050 
02051   for (PRInt32 i=0;i<aPO->mKids.Count();i++) {
02052     SetPrintPO((nsPrintObject*)aPO->mKids[i], aPrint, aIsHidden, aFlags);
02053   } 
02054 }
02055 
02056 //---------------------------------------------------------------------
02057 // This will first use a Title and/or URL from the PrintSettings
02058 // if one isn't set then it uses the one from the document
02059 // then if not title is there we will make sure we send something back
02060 // depending on the situation.
02061 void
02062 nsPrintEngine::GetDisplayTitleAndURL(nsPrintObject*      aPO,
02063                                           nsIPrintSettings* aPrintSettings,
02064                                           const PRUnichar*  aBrandName,
02065                                           PRUnichar**       aTitle, 
02066                                           PRUnichar**       aURLStr,
02067                                           eDocTitleDefault  aDefType)
02068 {
02069   NS_ASSERTION(aBrandName, "Pointer is null!");
02070   NS_ASSERTION(aPO, "Pointer is null!");
02071   NS_ASSERTION(aTitle, "Pointer is null!");
02072   NS_ASSERTION(aURLStr, "Pointer is null!");
02073 
02074   *aTitle  = nsnull;
02075   *aURLStr = nsnull;
02076 
02077   // First check to see if the PrintSettings has defined an alternate title
02078   // and use that if it did
02079   PRUnichar * docTitleStrPS = nsnull;
02080   PRUnichar * docURLStrPS   = nsnull;
02081   if (aPrintSettings) {
02082     aPrintSettings->GetTitle(&docTitleStrPS);
02083     aPrintSettings->GetDocURL(&docURLStrPS);
02084 
02085     if (docTitleStrPS && *docTitleStrPS) {
02086       *aTitle  = docTitleStrPS;
02087     }
02088 
02089     if (docURLStrPS && *docURLStrPS) {
02090       *aURLStr  = docURLStrPS;
02091     }
02092 
02093     // short circut
02094     if (docTitleStrPS && docURLStrPS) {
02095       return;
02096     }
02097   }
02098 
02099   if (!docURLStrPS) {
02100     if (aPO->mDocURL) {
02101       *aURLStr = nsCRT::strdup(aPO->mDocURL);
02102     }
02103   }
02104 
02105   if (!docTitleStrPS) {
02106     if (aPO->mDocTitle) {
02107       *aTitle = nsCRT::strdup(aPO->mDocTitle);
02108     } else {
02109       switch (aDefType) {
02110         case eDocTitleDefBlank: *aTitle = ToNewUnicode(EmptyString());
02111           break;
02112 
02113         case eDocTitleDefURLDoc:
02114           if (*aURLStr) {
02115             *aTitle = nsCRT::strdup(*aURLStr);
02116           } else {
02117             if (aBrandName) *aTitle = nsCRT::strdup(aBrandName);
02118           }
02119           break;
02120 
02121         default:
02122           break;
02123       } // switch
02124     }
02125   }
02126 }
02127 
02128 //---------------------------------------------------------------------
02129 nsresult nsPrintEngine::DocumentReadyForPrinting()
02130 {
02131   if (mPrt->mPrintFrameType == nsIPrintSettings::kEachFrameSep) {
02132     CheckForChildFrameSets(mPrt->mPrintObject);
02133   }
02134 
02135   //
02136   // Send the document to the printer...
02137   //
02138   nsresult rv = SetupToPrintContent(mPrt->mPrintDC, mPrt->mCurrentFocusWin);
02139   if (NS_FAILED(rv)) {
02140     // The print job was canceled or there was a problem
02141     // So remove all other documents from the print list
02142     DonePrintingPages(nsnull, rv);
02143   }
02144   return rv;
02145 }
02146 
02150 nsresult nsPrintEngine::CleanupOnFailure(nsresult aResult, PRBool aIsPrinting)
02151 {
02152   PR_PL(("****  Failed %s - rv 0x%X", aIsPrinting?"Printing":"Print Preview", aResult));
02153 
02154   /* cleanup... */
02155   if (mPagePrintTimer) {
02156     mPagePrintTimer->Stop();
02157     NS_RELEASE(mPagePrintTimer);
02158   }
02159   
02160   SetIsPrinting(PR_FALSE);
02161 
02162   /* cleanup done, let's fire-up an error dialog to notify the user
02163    * what went wrong... 
02164    * 
02165    * When rv == NS_ERROR_ABORT, it means we want out of the 
02166    * print job without displaying any error messages
02167    */
02168   if (aResult != NS_ERROR_ABORT) {
02169     ShowPrintErrorDialog(aResult, aIsPrinting);
02170   }
02171 
02172   FirePrintCompletionEvent();
02173 
02174   return aResult;
02175 
02176 }
02177 
02178 //---------------------------------------------------------------------
02179 void
02180 nsPrintEngine::ShowPrintErrorDialog(nsresult aPrintError, PRBool aIsPrinting)
02181 {
02182 
02183   PR_PL(("nsPrintEngine::ShowPrintErrorDialog(nsresult aPrintError=%lx, PRBool aIsPrinting=%d)\n", (long)aPrintError, (int)aIsPrinting));
02184 
02185   nsCAutoString stringName;
02186 
02187   switch(aPrintError)
02188   {
02189 #define NS_ERROR_TO_LOCALIZED_PRINT_ERROR_MSG(nserr) case nserr: stringName.AssignLiteral(#nserr); break;
02190       NS_ERROR_TO_LOCALIZED_PRINT_ERROR_MSG(NS_ERROR_GFX_PRINTER_CMD_NOT_FOUND)
02191       NS_ERROR_TO_LOCALIZED_PRINT_ERROR_MSG(NS_ERROR_GFX_PRINTER_CMD_FAILURE)
02192       NS_ERROR_TO_LOCALIZED_PRINT_ERROR_MSG(NS_ERROR_GFX_PRINTER_NO_PRINTER_AVAILABLE)
02193       NS_ERROR_TO_LOCALIZED_PRINT_ERROR_MSG(NS_ERROR_GFX_PRINTER_NAME_NOT_FOUND)
02194       NS_ERROR_TO_LOCALIZED_PRINT_ERROR_MSG(NS_ERROR_GFX_PRINTER_ACCESS_DENIED)
02195       NS_ERROR_TO_LOCALIZED_PRINT_ERROR_MSG(NS_ERROR_GFX_PRINTER_INVALID_ATTRIBUTE)
02196       NS_ERROR_TO_LOCALIZED_PRINT_ERROR_MSG(NS_ERROR_GFX_PRINTER_PRINTER_NOT_READY)
02197       NS_ERROR_TO_LOCALIZED_PRINT_ERROR_MSG(NS_ERROR_GFX_PRINTER_OUT_OF_PAPER)
02198       NS_ERROR_TO_LOCALIZED_PRINT_ERROR_MSG(NS_ERROR_GFX_PRINTER_PRINTER_IO_ERROR)
02199       NS_ERROR_TO_LOCALIZED_PRINT_ERROR_MSG(NS_ERROR_GFX_PRINTER_COULD_NOT_OPEN_FILE)
02200       NS_ERROR_TO_LOCALIZED_PRINT_ERROR_MSG(NS_ERROR_GFX_PRINTER_FILE_IO_ERROR)
02201       NS_ERROR_TO_LOCALIZED_PRINT_ERROR_MSG(NS_ERROR_GFX_PRINTER_PRINTPREVIEW)
02202       NS_ERROR_TO_LOCALIZED_PRINT_ERROR_MSG(NS_ERROR_UNEXPECTED)
02203       NS_ERROR_TO_LOCALIZED_PRINT_ERROR_MSG(NS_ERROR_OUT_OF_MEMORY)
02204       NS_ERROR_TO_LOCALIZED_PRINT_ERROR_MSG(NS_ERROR_NOT_IMPLEMENTED)
02205       NS_ERROR_TO_LOCALIZED_PRINT_ERROR_MSG(NS_ERROR_NOT_AVAILABLE)
02206       NS_ERROR_TO_LOCALIZED_PRINT_ERROR_MSG(NS_ERROR_ABORT)
02207       NS_ERROR_TO_LOCALIZED_PRINT_ERROR_MSG(NS_ERROR_GFX_PRINTER_STARTDOC)
02208       NS_ERROR_TO_LOCALIZED_PRINT_ERROR_MSG(NS_ERROR_GFX_PRINTER_ENDDOC)
02209       NS_ERROR_TO_LOCALIZED_PRINT_ERROR_MSG(NS_ERROR_GFX_PRINTER_STARTPAGE)
02210       NS_ERROR_TO_LOCALIZED_PRINT_ERROR_MSG(NS_ERROR_GFX_PRINTER_ENDPAGE)
02211       NS_ERROR_TO_LOCALIZED_PRINT_ERROR_MSG(NS_ERROR_GFX_PRINTER_PRINT_WHILE_PREVIEW)
02212       NS_ERROR_TO_LOCALIZED_PRINT_ERROR_MSG(NS_ERROR_GFX_PRINTER_PAPER_SIZE_NOT_SUPPORTED)
02213       NS_ERROR_TO_LOCALIZED_PRINT_ERROR_MSG(NS_ERROR_GFX_PRINTER_ORIENTATION_NOT_SUPPORTED)
02214       NS_ERROR_TO_LOCALIZED_PRINT_ERROR_MSG(NS_ERROR_GFX_PRINTER_COLORSPACE_NOT_SUPPORTED)
02215       NS_ERROR_TO_LOCALIZED_PRINT_ERROR_MSG(NS_ERROR_GFX_PRINTER_TOO_MANY_COPIES)
02216       NS_ERROR_TO_LOCALIZED_PRINT_ERROR_MSG(NS_ERROR_GFX_PRINTER_DRIVER_CONFIGURATION_ERROR)
02217       NS_ERROR_TO_LOCALIZED_PRINT_ERROR_MSG(NS_ERROR_GFX_PRINTER_XPRINT_BROKEN_XPRT)
02218       NS_ERROR_TO_LOCALIZED_PRINT_ERROR_MSG(NS_ERROR_GFX_PRINTER_DOC_IS_BUSY_PP)
02219       NS_ERROR_TO_LOCALIZED_PRINT_ERROR_MSG(NS_ERROR_GFX_PRINTER_DOC_WAS_DESTORYED)
02220       NS_ERROR_TO_LOCALIZED_PRINT_ERROR_MSG(NS_ERROR_GFX_NO_PRINTDIALOG_IN_TOOLKIT)
02221       NS_ERROR_TO_LOCALIZED_PRINT_ERROR_MSG(NS_ERROR_GFX_NO_PRINTROMPTSERVICE)
02222       NS_ERROR_TO_LOCALIZED_PRINT_ERROR_MSG(NS_ERROR_GFX_PRINTER_NO_XUL)   // Temporary code for Bug 136185 / bug 240490
02223       NS_ERROR_TO_LOCALIZED_PRINT_ERROR_MSG(NS_ERROR_GFX_PRINTER_XPRINT_NO_XPRINT_SERVERS_FOUND)
02224       NS_ERROR_TO_LOCALIZED_PRINT_ERROR_MSG(NS_ERROR_GFX_PRINTER_PLEX_NOT_SUPPORTED)
02225       NS_ERROR_TO_LOCALIZED_PRINT_ERROR_MSG(NS_ERROR_GFX_PRINTER_DOC_IS_BUSY)
02226       NS_ERROR_TO_LOCALIZED_PRINT_ERROR_MSG(NS_ERROR_GFX_PRINTING_NOT_IMPLEMENTED)
02227       NS_ERROR_TO_LOCALIZED_PRINT_ERROR_MSG(NS_ERROR_GFX_COULD_NOT_LOAD_PRINT_MODULE)
02228       NS_ERROR_TO_LOCALIZED_PRINT_ERROR_MSG(NS_ERROR_GFX_PRINTER_RESOLUTION_NOT_SUPPORTED)
02229 
02230     default:
02231       NS_ERROR_TO_LOCALIZED_PRINT_ERROR_MSG(NS_ERROR_FAILURE)
02232 #undef NS_ERROR_TO_LOCALIZED_PRINT_ERROR_MSG
02233   }
02234 
02235   PR_PL(("ShowPrintErrorDialog:  stringName='%s'\n", stringName.get()));
02236 
02237   nsXPIDLString msg, title;
02238   nsresult rv =
02239     nsContentUtils::GetLocalizedString(nsContentUtils::ePRINTING_PROPERTIES,
02240                                        stringName.get(), msg);
02241   if (NS_FAILED(rv)) {
02242     PR_PL(("GetLocalizedString failed\n"));
02243     return;
02244   }
02245 
02246   rv = nsContentUtils::GetLocalizedString(nsContentUtils::ePRINTING_PROPERTIES,
02247       aIsPrinting ? "print_error_dialog_title"
02248                   : "printpreview_error_dialog_title",
02249       title);
02250 
02251   nsCOMPtr<nsIWindowWatcher> wwatch = do_GetService(NS_WINDOWWATCHER_CONTRACTID, &rv);
02252   if (NS_FAILED(rv)) {
02253     PR_PL(("ShowPrintErrorDialog(): wwatch==nsnull\n"));
02254     return;
02255   }
02256 
02257   nsCOMPtr<nsIDOMWindow> active;
02258   wwatch->GetActiveWindow(getter_AddRefs(active));
02259 
02260   nsCOMPtr<nsIPrompt> dialog;
02261   /* |GetNewPrompter| allows that |active| is |nsnull| 
02262    * (see bug 234982 ("nsPrintEngine::ShowPrintErrorDialog() fails in many cases")) */
02263   wwatch->GetNewPrompter(active, getter_AddRefs(dialog));
02264   if (!dialog) {
02265     PR_PL(("ShowPrintErrorDialog(): dialog==nsnull\n"));
02266     return;
02267   }
02268 
02269   dialog->Alert(title.get(), msg.get());
02270   PR_PL(("ShowPrintErrorDialog(): alert displayed successfully.\n"));
02271 }
02272 
02273 //-----------------------------------------------------------------
02274 //-- Section: Reflow Methods
02275 //-----------------------------------------------------------------
02276 
02277 //-------------------------------------------------------
02278 nsresult
02279 nsPrintEngine::SetupToPrintContent(nsIDeviceContext* aDContext,
02280                                    nsIDOMWindow* aCurrentFocusedDOMWin)
02281 {
02282 
02283   NS_ENSURE_ARG_POINTER(aDContext);
02284   // NOTE: aCurrentFocusedDOMWin may be null (which is OK)
02285 
02286   mPrt->mPrintDocDC = aDContext;
02287 
02288   // In this step we figure out which documents should be printed
02289   // i.e. if we are printing the selection then only enable that nsPrintObject
02290   // for printing
02291   if (NS_FAILED(EnablePOsForPrinting())) {
02292     return NS_ERROR_FAILURE;
02293   }
02294   DUMP_DOC_LIST("\nAfter Enable------------------------------------------");
02295 
02296   // This is an Optimization
02297   // If we are in PP then we already know all the shrinkage information
02298   // so just transfer it to the PrintData and we will skip the extra shrinkage reflow
02299   //
02300   // doSetPixelScale tells Reflow whether to set the shrinkage value into the DC
02301   // The first tru we do not want to do this, the second time thru we do
02302   PRBool doSetPixelScale = PR_FALSE;
02303   PRBool ppIsShrinkToFit = mPrtPreview && mPrtPreview->mShrinkToFit;
02304   if (ppIsShrinkToFit) {
02305     mPrt->mShrinkRatio = mPrtPreview->mShrinkRatio;
02306     doSetPixelScale = PR_TRUE;
02307   }
02308 
02309   // Here we reflow all the PrintObjects
02310   nsresult rv = ReflowDocList(mPrt->mPrintObject, doSetPixelScale, mPrt->mShrinkToFit);
02311   CHECK_RUNTIME_ERROR_CONDITION(nsIDebugObject::PRT_RUNTIME_REFLOWDOCLIST, rv, NS_ERROR_FAILURE);
02312   if (NS_FAILED(rv)) {
02313     return NS_ERROR_FAILURE;
02314   }
02315 
02316   // Here is where we do the extra reflow for shrinking the content
02317   // But skip this step if we are in PrintPreview
02318   if (mPrt->mShrinkToFit && !ppIsShrinkToFit) {
02319     // Now look for the PO that has the smallest percent for shrink to fit
02320     if (mPrt->mPrintDocList->Count() > 1 && mPrt->mPrintObject->mFrameType == eFrameSet) {
02321       nsPrintObject* smallestPO = FindSmallestSTF();
02322       NS_ASSERTION(smallestPO, "There must always be an XMost PO!");
02323       if (smallestPO) {
02324         // Calc the shrinkage based on the entire content area
02325         mPrt->mShrinkRatio = smallestPO->mShrinkRatio;
02326       }
02327     } else {
02328       // Single document so use the Shrink as calculated for the PO
02329       mPrt->mShrinkRatio = mPrt->mPrintObject->mShrinkRatio;
02330     }
02331 
02332     // Only Shrink if we are smaller
02333     if (mPrt->mShrinkRatio < 0.998f) {
02334       // Clamp Shrink to Fit to 60%
02335       mPrt->mShrinkRatio = PR_MAX(mPrt->mShrinkRatio, 0.60f);
02336 
02337       for (PRInt32 i=0;i<mPrt->mPrintDocList->Count();i++) {
02338         nsPrintObject* po = (nsPrintObject*)mPrt->mPrintDocList->ElementAt(i);
02339         NS_ASSERTION(po, "nsPrintObject can't be null!");
02340         // Wipe out the presentation before we reflow
02341         po->DestroyPresentation();
02342       }
02343 
02344 #if (defined(XP_WIN) || defined(XP_OS2)) && defined(EXTENDED_DEBUG_PRINTING)
02345       // We need to clear all the output files here
02346       // because they will be re-created with second reflow of the docs
02347       if (kPrintingLogMod && kPrintingLogMod->level == DUMP_LAYOUT_LEVEL) {
02348         RemoveFilesInDir(".\\");
02349         gDumpFileNameCnt   = 0;
02350         gDumpLOFileNameCnt = 0;
02351       }
02352 #endif
02353 
02354       // Here we reflow all the PrintObjects a second time
02355       // this time using the shrinkage values
02356       // The last param here tells reflow to NOT calc the shrinkage values
02357       if (NS_FAILED(ReflowDocList(mPrt->mPrintObject, PR_TRUE, PR_FALSE))) {
02358         return NS_ERROR_FAILURE;
02359       }
02360     }
02361 
02362 #ifdef PR_LOGGING
02363     {
02364       float calcRatio = 0.0f;
02365       if (mPrt->mPrintDocList->Count() > 1 && mPrt->mPrintObject->mFrameType == eFrameSet) {
02366         nsPrintObject* smallestPO = FindSmallestSTF();
02367         NS_ASSERTION(smallestPO, "There must always be an XMost PO!");
02368         if (smallestPO) {
02369           // Calc the shrinkage based on the entire content area
02370           calcRatio = smallestPO->mShrinkRatio;
02371         }
02372       } else {
02373         // Single document so use the Shrink as calculated for the PO
02374         calcRatio = mPrt->mPrintObject->mShrinkRatio;
02375       }
02376       PR_PL(("**************************************************************************\n"));
02377       PR_PL(("STF Ratio is: %8.5f Effective Ratio: %8.5f Diff: %8.5f\n", mPrt->mShrinkRatio, calcRatio,  mPrt->mShrinkRatio-calcRatio));
02378       PR_PL(("**************************************************************************\n"));
02379     }
02380 #endif
02381   }
02382 
02383   DUMP_DOC_LIST(("\nAfter Reflow------------------------------------------"));
02384   PR_PL(("\n"));
02385   PR_PL(("-------------------------------------------------------\n"));
02386   PR_PL(("\n"));
02387 
02388   // Set up the clipping rectangle for all documents
02389   // When frames are being printed as part of a frame set and also IFrames,
02390   // they are reflowed with a very large page height. We need to setup the
02391   // clipping so they do not rpint over top of anything else
02392   PR_PL(("SetClipRect-------------------------------------------------------\n"));
02393   nsRect clipRect(-1,-1,-1, -1);
02394   SetClipRect(mPrt->mPrintObject, clipRect, 0, 0, PR_FALSE);
02395 
02396   CalcNumPrintableDocsAndPages(mPrt->mNumPrintableDocs, mPrt->mNumPrintablePages);
02397 
02398   PR_PL(("--- Printing %d docs and %d pages\n", mPrt->mNumPrintableDocs, mPrt->mNumPrintablePages));
02399   DUMP_DOC_TREELAYOUT;
02400 
02401   // Print listener setup...
02402   if (mPrt != nsnull) {
02403     mPrt->OnStartPrinting();    
02404   }
02405 
02406   mPrt->mPrintDocDW = aCurrentFocusedDOMWin;
02407 
02408   PRUnichar* fileName = nsnull;
02409   // check to see if we are printing to a file
02410   PRBool isPrintToFile = PR_FALSE;
02411   mPrt->mPrintSettings->GetPrintToFile(&isPrintToFile);
02412   if (isPrintToFile) {
02413   // On some platforms The BeginDocument needs to know the name of the file
02414   // and it uses the PrintService to get it, so we need to set it into the PrintService here
02415     mPrt->mPrintSettings->GetToFileName(&fileName);
02416   }
02417 
02418   PRUnichar * docTitleStr;
02419   PRUnichar * docURLStr;
02420   GetDisplayTitleAndURL(mPrt->mPrintObject, mPrt->mPrintSettings, mPrt->mBrandName, &docTitleStr, &docURLStr, eDocTitleDefURLDoc); 
02421 
02422   PRInt32 startPage = 1;
02423   PRInt32 endPage   = mPrt->mNumPrintablePages;
02424 
02425   PRInt16 printRangeType = nsIPrintSettings::kRangeAllPages;
02426   mPrt->mPrintSettings->GetPrintRange(&printRangeType);
02427   if (printRangeType == nsIPrintSettings::kRangeSpecifiedPageRange) {
02428     mPrt->mPrintSettings->GetStartPageRange(&startPage);
02429     mPrt->mPrintSettings->GetEndPageRange(&endPage);
02430     if (endPage > mPrt->mNumPrintablePages) {
02431       endPage = mPrt->mNumPrintablePages;
02432     }
02433   }
02434 
02435   rv = NS_OK;
02436   // BeginDocument may pass back a FAILURE code
02437   // i.e. On Windows, if you are printing to a file and hit "Cancel" 
02438   //      to the "File Name" dialog, this comes back as an error
02439   // Don't start printing when regression test are executed  
02440   if (!mPrt->mDebugFilePtr && mIsDoingPrinting) {
02441     rv = mPrt->mPrintDC->BeginDocument(docTitleStr, fileName, startPage, endPage);
02442   }
02443 
02444   PR_PL(("****************** Begin Document ************************\n"));
02445 
02446   if (docTitleStr) nsMemory::Free(docTitleStr);
02447   if (docURLStr) nsMemory::Free(docURLStr);
02448 
02449   CHECK_RUNTIME_ERROR_CONDITION(nsIDebugObject::PRT_RUNTIME_BEGINDOC, rv, NS_ERROR_FAILURE);
02450   NS_ENSURE_SUCCESS(rv, rv);
02451 
02452   // This will print the docshell document
02453   // when it completes asynchronously in the DonePrintingPages method
02454   // it will check to see if there are more docshells to be printed and
02455   // then PrintDocContent will be called again.
02456 
02457   if (mIsDoingPrinting) {
02458     PrintDocContent(mPrt->mPrintObject, rv); // ignore return value
02459   }
02460 
02461   return rv;
02462 }
02463 
02464 //-------------------------------------------------------
02465 // Recursively reflow each sub-doc and then calc
02466 // all the frame locations of the sub-docs
02467 nsresult
02468 nsPrintEngine::ReflowDocList(nsPrintObject* aPO, PRBool aSetPixelScale, PRBool aDoCalcShrink)
02469 {
02470   NS_ASSERTION(aPO, "Pointer is null!");
02471   if (!aPO) return NS_ERROR_FAILURE;
02472 
02473   // Check to see if the subdocument's element has been hidden by the parent document
02474   if (aPO->mParent) {
02475     nsIFrame * frame;
02476     aPO->mParent->mPresShell->GetPrimaryFrameFor(aPO->mContent, &frame);
02477     if (frame) {
02478       if (!frame->GetStyleVisibility()->IsVisible()) {
02479         aPO->mDontPrint = PR_TRUE;
02480         aPO->mInvisible = PR_TRUE;
02481         return NS_OK;
02482       }
02483     }
02484   }
02485 
02486   // Don't reflow hidden POs
02487   if (aPO->mIsHidden) return NS_OK;
02488 
02489   // Here is where we set the shrinkage value into the DC
02490   // and this is what actually makes it shrink
02491   if (aSetPixelScale && aPO->mFrameType != eIFrame) {
02492     float ratio;
02493     if (mPrt->mPrintFrameType == nsIPrintSettings::kFramesAsIs || mPrt->mPrintFrameType == nsIPrintSettings::kNoFrames) {
02494       ratio = mPrt->mShrinkRatio - 0.005f; // round down
02495     } else {
02496       ratio = aPO->mShrinkRatio - 0.005f; // round down
02497     }
02498     mPrt->mPrintDC->SetCanonicalPixelScale(ratio*mPrt->mOrigDCScale);
02499   }
02500 
02501   // Reflow the PO
02502   if (NS_FAILED(ReflowPrintObject(aPO, aDoCalcShrink))) {
02503     return NS_ERROR_FAILURE;
02504   }
02505 
02506   // Calc the absolute poistion of the frames
02507   if (NS_FAILED(MapSubDocFrameLocations(aPO))) {
02508     return NS_ERROR_FAILURE;
02509   }
02510 
02511   PRInt32 cnt = aPO->mKids.Count();
02512   for (PRInt32 i=0;i<cnt;i++) {
02513     if (NS_FAILED(ReflowDocList((nsPrintObject *)aPO->mKids[i], aSetPixelScale, aDoCalcShrink))) {
02514       return NS_ERROR_FAILURE;
02515     }
02516   }
02517   return NS_OK;
02518 }
02519 
02520 //-------------------------------------------------------
02521 // Reflow a nsPrintObject
02522 nsresult
02523 nsPrintEngine::ReflowPrintObject(nsPrintObject * aPO, PRBool aDoCalcShrink)
02524 {
02525   NS_ASSERTION(aPO, "Pointer is null!");
02526   if (!aPO) return NS_ERROR_FAILURE;
02527 
02528   // If it is hidden don't bother reflow it or any of it's children
02529   if (aPO->mIsHidden) return NS_OK;
02530 
02531   // create the PresContext
02532   PRBool containerIsSet = PR_FALSE;
02533   aPO->mPresContext = new nsPresContext(mIsCreatingPrintPreview ?
02534                                          nsPresContext::eContext_PrintPreview:
02535                                          nsPresContext::eContext_Print);
02536   NS_ENSURE_TRUE(aPO->mPresContext, NS_ERROR_OUT_OF_MEMORY);
02537   aPO->mPresContext->SetPrintSettings(mPrt->mPrintSettings);
02538 
02539   // set the presentation context to the value in the print settings
02540   PRBool printBGColors;
02541   mPrt->mPrintSettings->GetPrintBGColors(&printBGColors);
02542   aPO->mPresContext->SetBackgroundColorDraw(printBGColors);
02543   mPrt->mPrintSettings->GetPrintBGImages(&printBGColors);
02544   aPO->mPresContext->SetBackgroundImageDraw(printBGColors);
02545 
02546 
02547   // init it with the DC
02548   nsresult rv = aPO->mPresContext->Init(mPrt->mPrintDocDC);
02549   if (NS_FAILED(rv)) {
02550     aPO->mPresContext = nsnull;
02551     return rv;
02552   }
02553 
02554   rv = mDocViewerPrint->CreateStyleSet(aPO->mDocument, &aPO->mStyleSet);
02555   NS_ENSURE_SUCCESS(rv, rv);
02556 
02557   aPO->mViewManager = do_CreateInstance(kViewManagerCID, &rv);
02558   if (NS_FAILED(rv)) {
02559     delete aPO->mStyleSet;
02560     return rv;
02561   }
02562 
02563   rv = aPO->mViewManager->Init(mPrt->mPrintDocDC);
02564   if (NS_FAILED(rv)) {
02565     delete aPO->mStyleSet;
02566     return rv;
02567   }
02568 
02569   rv = aPO->mDocument->CreateShell(aPO->mPresContext, aPO->mViewManager,
02570                                    aPO->mStyleSet, getter_AddRefs(aPO->mPresShell));
02571   if (NS_FAILED(rv)) {
02572     delete aPO->mStyleSet;
02573     return rv;
02574   }
02575 
02576   // Don't paint selection stuff for images while printing.
02577   // XXXbz should we be painting it for text, even?
02578   aPO->mPresShell->SetSelectionFlags(nsISelectionDisplay::DISPLAY_TEXT);
02579 
02580   aPO->mStyleSet->EndUpdate();
02581   
02582   // The pres shell now owns the style set object.
02583 
02584   PRInt32 pageWidth, pageHeight;
02585   mPrt->mPrintDocDC->GetDeviceSurfaceDimensions(pageWidth, pageHeight);
02586 
02587   PRInt32 width, height;
02588   if (aPO->mContent == nsnull || !aPO->mPrintAsIs ||
02589       (aPO->mPrintAsIs && aPO->mParent && !aPO->mParent->mPrintAsIs) ||
02590       (aPO->mFrameType == eIFrame && aPO == mPrt->mSelectedPO)) {
02591     width  = pageWidth;
02592     height = pageHeight;
02593   } else {
02594     width  = aPO->mRect.width;
02595     height = aPO->mRect.height;
02596   }
02597 
02598   PR_PL(("In DV::ReflowPrintObject PO: %p (%9s) Setting w,h to %d,%d\n", aPO, gFrameTypesStr[aPO->mFrameType], width, height));
02599 
02600   // XXX - Hack Alert
02601   // OK, so ther eis a selection, we will print the entire selection
02602   // on one page and then crop the page.
02603   // This means you can never print any selection that is longer than
02604   // one page put it keeps it from page breaking in the middle of your
02605   // print of the selection (see also nsSimplePageSequence.cpp)
02606   PRInt16 printRangeType = nsIPrintSettings::kRangeAllPages;
02607   if (mPrt->mPrintSettings != nsnull) {
02608     mPrt->mPrintSettings->GetPrintRange(&printRangeType);
02609   }
02610 
02611   if (printRangeType == nsIPrintSettings::kRangeSelection &&
02612       IsThereARangeSelection(mPrt->mPrintDocDW)) {
02613     height = NS_UNCONSTRAINEDSIZE;
02614   }
02615 
02616   nsRect tbounds = nsRect(0, 0, width, height);
02617 
02618   // Create a child window of the parent that is our "root view/window"
02619   aPO->mRootView = aPO->mViewManager->CreateView(tbounds, nsnull);
02620   if (!aPO->mRootView) {
02621     return NS_ERROR_OUT_OF_MEMORY;
02622   }
02623 
02624 #ifdef NS_PRINT_PREVIEW
02625   // Here we decide whether we need scrollbars and
02626   // what the parent will be of the widget
02627   if (mIsCreatingPrintPreview) {
02628     PRBool canCreateScrollbars = PR_FALSE;
02629     nsCOMPtr<nsIWidget> widget = mParentWidget;
02630     // the top nsPrintObject's widget will always have scrollbars
02631     if (aPO->mParent != nsnull && aPO->mContent) {
02632       nsFrameManager *frameMan = aPO->mParent->mPresShell->FrameManager();
02633       nsIFrame* frame = frameMan->GetPrimaryFrameFor(aPO->mContent);
02634 
02635       if (frame) {
02636         nsIView* view = frame->GetView();
02637         NS_ASSERTION(view, "Primary frame for subdoc must have view!");
02638         if (view) {
02639           if (aPO->mFrameType == eIFrame || aPO->mFrameType == eFrame) {
02640             view = view->GetFirstChild();
02641             NS_ASSERTION(view, "innerView not found");
02642           }
02643 
02644           if (view && view->HasWidget()) {
02645             widget = view->GetWidget();
02646             canCreateScrollbars = PR_FALSE;
02647           }
02648         }
02649       }
02650     } else {
02651       canCreateScrollbars = PR_TRUE;
02652     }
02653     rv = aPO->mRootView->CreateWidget(kWidgetCID, nsnull, 
02654                                       widget->GetNativeData(NS_NATIVE_WIDGET),
02655                                       PR_TRUE, PR_TRUE, 
02656                                       eContentTypeContent);
02657     aPO->mWindow = aPO->mRootView->GetWidget();
02658     aPO->mPresContext->SetPaginatedScrolling(canCreateScrollbars);
02659   }
02660 #endif // NS_PRINT_PREVIEW
02661 
02662   // Setup hierarchical relationship in view manager
02663   aPO->mViewManager->SetRootView(aPO->mRootView);
02664   aPO->mPresShell->Init(aPO->mDocument, aPO->mPresContext,
02665                         aPO->mViewManager, aPO->mStyleSet,
02666                         mPresContext->CompatibilityMode());
02667 
02668   if (!containerIsSet) {
02669     nsCOMPtr<nsISupports> supps(do_QueryInterface(aPO->mDocShell));
02670     aPO->mPresContext->SetContainer(supps);
02671   }
02672 
02673   // get the old history
02674   nsCOMPtr<nsIPresShell> presShell;
02675   nsCOMPtr<nsILayoutHistoryState>  layoutState;
02676   rv = mDocViewer->GetPresShell(getter_AddRefs(presShell));
02677   NS_ENSURE_SUCCESS(rv, rv);
02678   presShell->CaptureHistoryState(getter_AddRefs(layoutState), PR_TRUE);
02679 
02680   // set it on the new pres shell
02681   aPO->mDocShell->SetLayoutHistoryState(layoutState);
02682 
02683   // turn off animated GIFs
02684   if (aPO->mPresContext) {
02685     aPO->mImgAnimationMode = aPO->mPresContext->ImageAnimationMode();
02686     aPO->mPresContext->SetImageAnimationMode(imgIContainer::kDontAnimMode);
02687   }
02688 
02689   aPO->mPresShell->BeginObservingDocument();
02690 
02691   nsMargin margin(0,0,0,0);
02692   mPrt->mPrintSettings->GetMarginInTwips(margin);
02693 
02694   // initialize it with the default/generic case
02695   nsRect adjRect(aPO->mRect.x != 0?margin.left:0, aPO->mRect.y != 0?margin.top:0, width, height);
02696 
02697   // XXX This is an arbitray height,
02698   // but reflow somethimes gets upset when using max int
02699   // basically, we want to reflow a single page that is large
02700   // enough to fit any atomic object like an IFrame
02701   const PRInt32 kFivePagesHigh = 5;
02702 
02703   // now, change the value for special cases
02704   if (mPrt->mPrintFrameType == nsIPrintSettings::kEachFrameSep) {
02705     if (aPO->mFrameType == eFrame) {
02706       adjRect.SetRect(0, 0, width, height);
02707     } else if (aPO->mFrameType == eIFrame) {
02708       height = pageHeight*kFivePagesHigh;
02709       adjRect.SetRect(aPO->mRect.x != 0?margin.left:0, aPO->mRect.y != 0?margin.top:0, width, height);
02710     }
02711 
02712   } else if (mPrt->mPrintFrameType == nsIPrintSettings::kSelectedFrame) {
02713     if (aPO->mFrameType == eFrame) {
02714       adjRect.SetRect(0, 0, width, height);
02715     } else if (aPO->mFrameType == eIFrame) {
02716       if (aPO == mPrt->mSelectedPO) {
02717         adjRect.x = 0;
02718         adjRect.y = 0;
02719       } else {
02720         height = pageHeight*kFivePagesHigh;
02721         adjRect.SetRect(aPO->mRect.x != 0?margin.left:0, aPO->mRect.y != 0?margin.top:0, width, height);
02722       }
02723     }
02724   }
02725 
02726   if (!adjRect.width || !adjRect.height || !width || !height) {
02727     aPO->mDontPrint = PR_TRUE;
02728     aPO->mPresShell->EndObservingDocument();
02729     return NS_OK;
02730   }
02731 
02732   aPO->mPresContext->SetPageDim(adjRect);
02733   rv = aPO->mPresShell->InitialReflow(width, height);
02734   if (NS_SUCCEEDED(rv)) {
02735     // Transfer Selection Ranges to the new Print PresShell
02736     nsCOMPtr<nsISelection> selection;
02737     nsCOMPtr<nsISelection> selectionPS;
02738     nsresult rvv = mDocViewerPrint->GetDocumentSelection(getter_AddRefs(selection), aPO->mDisplayPresShell);
02739     if (NS_SUCCEEDED(rvv) && selection) {
02740       rvv = mDocViewerPrint->GetDocumentSelection(getter_AddRefs(selectionPS), aPO->mPresShell);
02741       if (NS_SUCCEEDED(rvv) && selectionPS) {
02742         PRInt32 cnt;
02743         selection->GetRangeCount(&cnt);
02744         PRInt32 inx;
02745         for (inx=0;inx<cnt;inx++) {
02746           nsCOMPtr<nsIDOMRange> range;
02747           if (NS_SUCCEEDED(selection->GetRangeAt(inx, getter_AddRefs(range)))) {
02748             selectionPS->AddRange(range);
02749           }
02750         }
02751       }
02752 
02753       // If we are trying to shrink the contents to fit on the page
02754       // we must first locate the "pageContent" frame
02755       // Then we walk the frame tree and look for the "xmost" frame
02756       // this is the frame where the right-hand side of the frame extends
02757       // the furthest
02758       if (mPrt->mShrinkToFit) {
02759         nsIPageSequenceFrame* pageSequence;
02760         aPO->mPresShell->GetPageSequenceFrame(&pageSequence);
02761         pageSequence->GetSTFPercent(aPO->mShrinkRatio);
02762 #ifdef EXTENDED_DEBUG_PRINTING
02763         printf("PO %p ****** STF Ratio %10.4f\n", aPO, aPO->mShrinkRatio*100.0f);
02764 #endif
02765       }
02766     }
02767 
02768 #ifdef EXTENDED_DEBUG_PRINTING
02769     if (kPrintingLogMod && kPrintingLogMod->level == DUMP_LAYOUT_LEVEL) {
02770       char * docStr;
02771       char * urlStr;
02772       GetDocTitleAndURL(aPO, docStr, urlStr);
02773       char filename[256];
02774       sprintf(filename, "print_dump_%d.txt", gDumpFileNameCnt++);
02775       // Dump all the frames and view to a a file
02776       FILE * fd = fopen(filename, "w");
02777       if (fd) {
02778         nsIFrame *theRootFrame =
02779           aPO->mPresShell->FrameManager()->GetRootFrame();
02780         fprintf(fd, "Title: %s\n", docStr?docStr:"");
02781         fprintf(fd, "URL:   %s\n", urlStr?urlStr:"");
02782         fprintf(fd, "--------------- Frames ----------------\n");
02783         nsCOMPtr<nsIRenderingContext> renderingContext;
02784         mPrt->mPrintDocDC->CreateRenderingContext(*getter_AddRefs(renderingContext));
02785         RootFrameList(aPO->mPresContext, fd, 0);
02786         //DumpFrames(fd, aPO->mPresContext, renderingContext, theRootFrame, 0);
02787         fprintf(fd, "---------------------------------------\n\n");
02788         fprintf(fd, "--------------- Views From Root Frame----------------\n");
02789         nsIView* v = theRootFrame->GetView();
02790         if (v) {
02791           v->List(fd);
02792         } else {
02793           printf("View is null!\n");
02794         }
02795         if (docShell) {
02796           fprintf(fd, "--------------- All Views ----------------\n");
02797           DumpViews(docShell, fd);
02798           fprintf(fd, "---------------------------------------\n\n");
02799         }
02800         fclose(fd);
02801       }
02802       if (docStr) nsMemory::Free(docStr);
02803       if (urlStr) nsMemory::Free(urlStr);
02804     }
02805 #endif
02806   }
02807 
02808   aPO->mPresShell->EndObservingDocument();
02809 
02810   return rv;
02811 }
02812 
02813 //-------------------------------------------------------
02814 // This recusively walks the PO tree calculating the
02815 // the page location and the absolute frame location for
02816 // a sub-doc.
02817 //
02818 // NOTE: This MUST be done after the sub-doc has been laid out
02819 // This is called by "ReflowDocList"
02820 //
02821 nsresult
02822 nsPrintEngine::MapSubDocFrameLocations(nsPrintObject* aPO)
02823 {
02824   NS_ASSERTION(aPO, "Pointer is null!");
02825 
02826   if (aPO->mParent != nsnull && aPO->mParent->mPresShell) {
02827     nsresult rv = CalcPageFrameLocation(aPO->mParent->mPresShell, aPO);
02828     if (NS_FAILED(rv)) return rv;
02829   }
02830 
02831   if (aPO->mPresShell) {
02832     for (PRInt32 i=0;i<aPO->mKids.Count();i++) {
02833       nsresult rv = MapSubDocFrameLocations((nsPrintObject*)aPO->mKids[i]);
02834       if (NS_FAILED(rv)) return rv;
02835     }
02836   }
02837   return NS_OK;
02838 }
02839 
02840 //-------------------------------------------------------
02841 // Finds the Page Frame and the absolute location on the page
02842 // for a Sub document.
02843 //
02844 // NOTE: This MUST be done after the sub-doc has been laid out
02845 // This is called by "MapSubDocFrameLocations"
02846 //
02847 nsresult
02848 nsPrintEngine::CalcPageFrameLocation(nsIPresShell * aPresShell,
02849                                           nsPrintObject*   aPO)
02850 {
02851   NS_ASSERTION(aPresShell, "Pointer is null!");
02852   NS_ASSERTION(aPO, "Pointer is null!");
02853 
02854   if (aPO != nsnull && aPO->mContent != nsnull) {
02855 
02856     // Find that frame for the sub-doc's content element
02857     // in the parent document
02858     // if it comes back null it probably has the style
02859     // set to "display:none"
02860     nsIFrame * frame;
02861     aPresShell->GetPrimaryFrameFor(aPO->mContent, &frame);
02862     if (frame == nsnull) {
02863       aPO->mDontPrint = PR_TRUE;
02864       return NS_OK;
02865     }
02866 
02867     nsMargin borderPadding(0, 0, 0, 0);
02868     frame->CalcBorderPadding(borderPadding);
02869 
02870     // Calc absolute position of the frame all the way up
02871     // to the SimpleSeq frame
02872     nsRect rect = frame->GetRect();
02873     rect.Deflate(borderPadding);
02874 
02875     rect.x = 0;
02876     rect.y = 0;
02877     nsIFrame * parent    = frame;
02878     nsIFrame * pageFrame = nsnull;
02879     nsIFrame * seqFrame  = nsnull;
02880     while (parent) {
02881       nsRect rr = parent->GetRect();
02882       rect.x += rr.x;
02883       rect.y += rr.y;
02884       nsIFrame * temp = parent;
02885       parent = temp->GetParent();
02886       // Keep a pointer to the Seq and Page frames
02887       nsIPageSequenceFrame * sqf = nsnull;
02888       if (parent &&
02889           NS_SUCCEEDED(CallQueryInterface(parent, &sqf)) && sqf) {
02890         pageFrame = temp;
02891         seqFrame  = parent;
02892       }
02893     }
02894     NS_ASSERTION(seqFrame, "The sequencer frame can't be null!");
02895     NS_ASSERTION(pageFrame, "The page frame can't be null!");
02896     if (seqFrame == nsnull || pageFrame == nsnull) return NS_ERROR_FAILURE;
02897 
02898     // Remember the Frame location information for later
02899     aPO->mRect      = rect;
02900     aPO->mSeqFrame  = seqFrame;
02901     aPO->mPageFrame = pageFrame;
02902 
02903     // Calc the Page No it is on
02904     PRInt32 pageNum = 1;
02905     nsIFrame* child = seqFrame->GetFirstChild(nsnull);
02906     while (child != nsnull) {
02907       if (pageFrame == child) {
02908         aPO->mPageNum = pageNum;
02909         break;
02910       }
02911       pageNum++;
02912       child = child->GetNextSibling();
02913     } // while
02914   }
02915   return NS_OK;
02916 }
02917 
02918 //-------------------------------------------------------
02919 // Figure out how many documents and how many total pages we are printing
02920 void
02921 nsPrintEngine::CalcNumPrintableDocsAndPages(PRInt32& aNumDocs, PRInt32& aNumPages)
02922 {
02923   aNumPages = 0;
02924   // Count the number of printable documents
02925   // and printable pages
02926   PRInt32 numOfPrintableDocs = 0;
02927   PRInt32 i;
02928   for (i=0;i<mPrt->mPrintDocList->Count();i++) {
02929     nsPrintObject* po = (nsPrintObject*)mPrt->mPrintDocList->ElementAt(i);
02930     NS_ASSERTION(po, "nsPrintObject can't be null!");
02931     if (po->IsPrintable()) {
02932       if (po->mPresShell &&
02933           po->mFrameType != eIFrame &&
02934           po->mFrameType != eFrameSet) {
02935         nsIPageSequenceFrame* pageSequence;
02936         po->mPresShell->GetPageSequenceFrame(&pageSequence);
02937         nsIFrame * seqFrame;
02938         if (NS_SUCCEEDED(CallQueryInterface(pageSequence, &seqFrame))) {
02939           nsIFrame* frame = seqFrame->GetFirstChild(nsnull);
02940           while (frame) {
02941             aNumPages++;
02942             frame = frame->GetNextSibling();
02943           }
02944         }
02945       }
02946 
02947       numOfPrintableDocs++;
02948     }
02949   }
02950 }
02951 //-----------------------------------------------------------------
02952 //-- Done: Reflow Methods
02953 //-----------------------------------------------------------------
02954 
02955 //-----------------------------------------------------------------
02956 //-- Section: Printing Methods
02957 //-----------------------------------------------------------------
02958 
02959 //-------------------------------------------------------
02960 // Called for each DocShell that needs to be printed
02961 PRBool
02962 nsPrintEngine::PrintDocContent(nsPrintObject* aPO, nsresult& aStatus)
02963 {
02964   NS_ASSERTION(aPO, "Pointer is null!");
02965   aStatus = NS_OK;
02966 
02967   if (!aPO->mHasBeenPrinted && aPO->IsPrintable()) {
02968     PRBool donePrinting = PR_TRUE;
02969     // donePrinting is only valid when when doing synchronous printing
02970     aStatus = DoPrint(aPO, PR_FALSE, donePrinting);
02971     if (donePrinting) {
02972       return PR_TRUE;
02973     }
02974   }
02975 
02976   // If |aPO->mPrintAsIs| and |aPO->mHasBeenPrinted| are true,
02977   // the kids frames are already processed in |PrintPage|.
02978   if (!aPO->mInvisible && !(aPO->mPrintAsIs && aPO->mHasBeenPrinted)) {
02979     for (PRInt32 i=0;i<aPO->mKids.Count();i++) {
02980       nsPrintObject* po = (nsPrintObject*)aPO->mKids[i];
02981       PRBool printed = PrintDocContent(po, aStatus);
02982       if (printed || NS_FAILED(aStatus)) {
02983         return PR_TRUE;
02984       }
02985     }
02986   }
02987   return PR_FALSE;
02988 }
02989 
02990 //-------------------------------------------------------
02991 // helper function - To calculate the correct position of
02992 // an iframe's subdocument
02993 //
02994 // ASSUMPTION: x,y must be initialized before calling!
02995 //
02996 static void GetIFramePosition(nsPrintObject * aPO, nscoord& aX, nscoord& aY)
02997 {
02998   if (aPO->mParent != nsnull) {
02999     // we would not have gotten here if any of these ptrs were null
03000     nsFrameManager *frameMan = aPO->mParent->mPresShell->FrameManager();
03001 
03002     // This gets our HTMLIFrame
03003     nsIFrame* frame = frameMan->GetPrimaryFrameFor(aPO->mContent);
03004     NS_ASSERTION(frame, "no primary frame for IFRAME");
03005     if (!frame)
03006       return;
03007 
03008     // find the offset to the content rect
03009     nsMargin borderPadding(0, 0, 0, 0);
03010     frame->CalcBorderPadding(borderPadding);
03011     aX += borderPadding.left;
03012     aY += borderPadding.top;
03013 
03014     // traverse out to the pageContentFrame
03015     do {
03016       nsPoint pt = frame->GetPosition();
03017       aX += pt.x;
03018       aY += pt.y;
03019       if (nsLayoutAtoms::pageContentFrame == frame->GetType()) {
03020         break;
03021       }
03022       frame = frame->GetParent();
03023     } while (frame);
03024   }
03025 }
03026 
03027 //-------------------------------------------------------
03028 nsresult
03029 nsPrintEngine::DoPrint(nsPrintObject * aPO, PRBool aDoSyncPrinting, PRBool& aDonePrinting)
03030 {
03031   NS_ASSERTION(mPrt->mPrintDocList, "Pointer is null!");
03032 
03033   PR_PL(("\n"));
03034   PR_PL(("**************************** %s ****************************\n", gFrameTypesStr[aPO->mFrameType]));
03035   PR_PL(("****** In DV::DoPrint   PO: %p aDoSyncPrinting: %s \n", aPO, PRT_YESNO(aDoSyncPrinting)));
03036 
03037   nsIDocShell*    docShell      = aPO->mDocShell;
03038   nsIPresShell*   poPresShell   = aPO->mPresShell;
03039   nsPresContext* poPresContext = aPO->mPresContext;
03040   nsIView*        poRootView    = aPO->mRootView;
03041 
03042   NS_ASSERTION(docShell, "The DocShell can't be NULL!");
03043   NS_ASSERTION(poPresContext, "PrintObject has not been reflowed");
03044 
03045   if (mPrt->mPrintProgressParams) {
03046     SetDocAndURLIntoProgress(aPO, mPrt->mPrintProgressParams);
03047   }
03048 
03049   if (docShell) {
03050 
03051     PRInt16 printRangeType = nsIPrintSettings::kRangeAllPages;
03052     nsresult rv;
03053     if (mPrt->mPrintSettings != nsnull) {
03054       mPrt->mPrintSettings->GetPrintRange(&printRangeType);
03055     }
03056 
03057     // Ask the page sequence frame to print all the pages
03058     nsIPageSequenceFrame* pageSequence;
03059     poPresShell->GetPageSequenceFrame(&pageSequence);
03060     NS_ASSERTION(nsnull != pageSequence, "no page sequence frame");
03061 
03062     // Now, depending how we are printing and what type of doc we are printing
03063     // we must configure the sequencer correctly.
03064     // so we are about to be very explicit about the whole process
03065 
03066     PRBool skipPageEjectOnly      = PR_FALSE;
03067     PRBool skipAllPageAdjustments = PR_FALSE;
03068     PRBool doOffsetting           = PR_FALSE;
03069     PRBool doAddInParentsOffset   = PR_TRUE;
03070     PRBool skipSetTitle           = PR_FALSE;
03071 
03072     // NOTE:
03073     // When printing "Each Frame Separately" or "Selected Frame (of a frameset)"
03074     // "doAddInParentsOffset" gets turned off for an iframe,
03075     // which means it won't add in its parent's x,y
03076 
03077     if (aPO->mFrameType == eFrame) {
03078       switch (mPrt->mPrintFrameType) {
03079       case nsIPrintSettings::kFramesAsIs:
03080           skipAllPageAdjustments = PR_TRUE;
03081           doOffsetting           = PR_TRUE;
03082           break;
03083 
03084         case nsIPrintSettings::kSelectedFrame:
03085           if (aPO->mKids.Count() > 0) {
03086             skipPageEjectOnly = PR_TRUE;
03087           }
03088           break;
03089 
03090         case nsIPrintSettings::kEachFrameSep:
03091           if (aPO->mKids.Count() > 0) {
03092             skipPageEjectOnly = PR_TRUE;
03093           }
03094           break;
03095       } // switch
03096 
03097     } else if (aPO->mFrameType == eIFrame) {
03098       switch (mPrt->mPrintFrameType) {
03099         case nsIPrintSettings::kFramesAsIs:
03100           skipAllPageAdjustments = PR_TRUE;
03101           doOffsetting           = PR_TRUE;
03102           skipSetTitle           = PR_TRUE;
03103           break;
03104 
03105         case nsIPrintSettings::kSelectedFrame:
03106           if (aPO != mPrt->mSelectedPO) {
03107             skipAllPageAdjustments = PR_TRUE;
03108             doOffsetting           = PR_TRUE;
03109             doAddInParentsOffset   = aPO->mParent != nsnull && aPO->mParent->mFrameType == eIFrame && aPO->mParent != mPrt->mSelectedPO;
03110             skipSetTitle           = PR_TRUE;
03111           } else {
03112             skipPageEjectOnly = aPO->mKids.Count() > 0;
03113           }
03114           break;
03115 
03116         case nsIPrintSettings::kEachFrameSep:
03117           skipAllPageAdjustments = PR_TRUE;
03118           doOffsetting           = PR_TRUE;
03119           doAddInParentsOffset   = aPO->mParent != nsnull && aPO->mParent->mFrameType == eIFrame;
03120           skipSetTitle           = PR_TRUE;
03121           break;
03122       } // switch
03123     } else {
03124       // FrameSets skip page eject only if printing AsIs
03125       // Also note, that when printing selection is a single document
03126       // we do not want to skip page ejects
03127       skipPageEjectOnly = aPO->mPrintAsIs && printRangeType != nsIPrintSettings::kRangeSelection;
03128     }
03129 
03130     // That we are all configured,
03131     // let's set everything up to print
03132     if (skipPageEjectOnly) {
03133       pageSequence->SkipPageEnd();
03134       aPO->mSkippedPageEject = PR_TRUE;
03135 
03136     } else {
03137 
03138       if (skipAllPageAdjustments) {
03139         pageSequence->SuppressHeadersAndFooters(PR_TRUE);
03140         pageSequence->SkipPageBegin();
03141         pageSequence->SkipPageEnd();
03142         aPO->mSkippedPageEject = PR_TRUE;
03143       } else {
03144         aPO->mSkippedPageEject = PR_FALSE;
03145       }
03146 
03147       if (doOffsetting) {
03148         nscoord x = 0;
03149         nscoord y = 0;
03150         // For IFrames, we locate the subdocument in the Parent document
03151         // then start calculating the location as we walk our way out to the 
03152         // the pageContentFrame
03153         if (aPO->mFrameType == eIFrame) {
03154           GetIFramePosition(aPO, x, y);
03155           if (doAddInParentsOffset) {
03156             x += aPO->mParent->mRect.x;
03157             y += aPO->mParent->mRect.y;
03158           }
03159         } else {
03160           nsPrintObject * po = aPO;
03161           while (po != nsnull) {
03162             x += po->mRect.x;
03163             y += po->mRect.y;
03164             po = po->mParent;
03165           }
03166         }
03167         pageSequence->SetOffset(x, y);
03168         aPO->mRect.x = x;
03169         aPO->mRect.y = y;
03170       }
03171     }
03172 
03173     PR_PL(("*** skipPageEjectOnly: %s  skipAllPageAdjustments: %s  doOffsetting: %s  doAddInParentsOffset: %s\n",
03174                       PRT_YESNO(skipPageEjectOnly), PRT_YESNO(skipAllPageAdjustments),
03175                       PRT_YESNO(doOffsetting), PRT_YESNO(doAddInParentsOffset)));
03176 
03177     // We are done preparing for printing, so we can turn this off
03178     mPrt->mPreparingForPrint = PR_FALSE;
03179 
03180     // mPrt->mDebugFilePtr this is onlu non-null when compiled for debugging
03181     if (nsnull != mPrt->mDebugFilePtr) {
03182 #ifdef NS_DEBUG
03183       // output the regression test
03184       nsIFrameDebug* fdbg;
03185       nsIFrame* root = poPresShell->FrameManager()->GetRootFrame();
03186 
03187       if (NS_SUCCEEDED(CallQueryInterface(root, &fdbg))) {
03188         fdbg->DumpRegressionData(poPresContext, mPrt->mDebugFilePtr, 0, PR_TRUE);
03189       }
03190       fclose(mPrt->mDebugFilePtr);
03191 #endif
03192     } else {
03193       nsIFrame* rootFrame = poPresShell->FrameManager()->GetRootFrame();
03194 
03195 #ifdef EXTENDED_DEBUG_PRINTING
03196       if (aPO->IsPrintable()) {
03197         char * docStr;
03198         char * urlStr;
03199         GetDocTitleAndURL(aPO, docStr, urlStr);
03200         DumpLayoutData(docStr, urlStr, poPresContext, mPrt->mPrintDocDC, rootFrame, docShell, nsnull);
03201         if (docStr) nsMemory::Free(docStr);
03202         if (urlStr) nsMemory::Free(urlStr);
03203       }
03204 #endif
03205 
03206       if (mPrt->mPrintSettings) {
03207         PRUnichar * docTitleStr = nsnull;
03208         PRUnichar * docURLStr   = nsnull;
03209 
03210         if (!skipSetTitle) {
03211           GetDisplayTitleAndURL(aPO, mPrt->mPrintSettings, mPrt->mBrandName, &docTitleStr, &docURLStr, eDocTitleDefBlank); 
03212         }
03213 
03214         if (nsIPrintSettings::kRangeSelection == printRangeType) {
03215           poPresContext->SetIsRenderingOnlySelection(PR_TRUE);
03216           // temporarily creating rendering context
03217           // which is needed to dinf the selection frames
03218           nsCOMPtr<nsIRenderingContext> rc;
03219           mPrt->mPrintDocDC->CreateRenderingContext(*getter_AddRefs(rc));
03220 
03221           // find the starting and ending page numbers
03222           // via the selection
03223           nsIFrame* startFrame;
03224           nsIFrame* endFrame;
03225           PRInt32   startPageNum;
03226           PRInt32   endPageNum;
03227           nsRect    startRect;
03228           nsRect    endRect;
03229 
03230           nsCOMPtr<nsISelection> selectionPS;
03231           nsresult rvv = mDocViewerPrint->GetDocumentSelection(getter_AddRefs(selectionPS), poPresShell);
03232           if (NS_SUCCEEDED(rvv) && selectionPS) {
03233           }
03234 
03235           rv = GetPageRangeForSelection(poPresShell, poPresContext, *rc, selectionPS, pageSequence,
03236                                         &startFrame, startPageNum, startRect,
03237                                         &endFrame, endPageNum, endRect);
03238           if (NS_SUCCEEDED(rv)) {
03239             mPrt->mPrintSettings->SetStartPageRange(startPageNum);
03240             mPrt->mPrintSettings->SetEndPageRange(endPageNum);
03241             nsMargin margin(0,0,0,0);
03242             mPrt->mPrintSettings->GetMarginInTwips(margin);
03243 
03244             if (startPageNum == endPageNum) {
03245               nsIFrame * seqFrame;
03246               if (NS_FAILED(CallQueryInterface(pageSequence, &seqFrame))) {
03247                 SetIsPrinting(PR_FALSE);
03248                 return NS_ERROR_FAILURE;
03249               }
03250               nsRect rect(0,0,0,0);
03251               nsRect areaRect;
03252               nsIFrame * areaFrame = FindFrameByType(poPresContext, startFrame, nsHTMLAtoms::body, rect, areaRect);
03253               if (areaFrame) {
03254                 startRect.y -= margin.top + areaFrame->GetPosition().y;
03255                 endRect.y   -= margin.top;
03256                 // XXX This is temporary fix for printing more than one page of a selection
03257                 pageSequence->SetSelectionHeight(startRect.y, endRect.y+endRect.height-startRect.y);
03258 
03259                 // calc total pages by getting calculating the selection's height
03260                 // and then dividing it by how page content frames will fit.
03261                 nscoord selectionHgt = endRect.y + endRect.height - startRect.y;
03262                 PRInt32 pageWidth, pageHeight;
03263                 mPrt->mPrintDocDC->GetDeviceSurfaceDimensions(pageWidth, pageHeight);
03264                 pageHeight -= margin.top + margin.bottom;
03265                 PRInt32 totalPages = PRInt32((float(selectionHgt) / float(pageHeight))+0.99);
03266                 pageSequence->SetTotalNumPages(totalPages);
03267               }
03268             }
03269           }
03270         }
03271 
03272         nsIFrame * seqFrame;
03273         if (NS_FAILED(CallQueryInterface(pageSequence, &seqFrame))) {
03274           SetIsPrinting(PR_FALSE);
03275           return NS_ERROR_FAILURE;
03276         }
03277 
03278         if (poPresContext->Type() != nsPresContext::eContext_PrintPreview) {
03279           nscoord sheight = seqFrame->GetSize().height;
03280 
03281           nsRect r = poRootView->GetBounds();
03282           r.x = r.y = 0;
03283           r.height = sheight;
03284           aPO->mViewManager->ResizeView(poRootView, r, PR_FALSE);
03285 
03286           r = rootFrame->GetRect();
03287 
03288           r.height = sheight;
03289           rootFrame->SetRect(r);
03290 
03291           mPageSeqFrame = pageSequence;
03292           mPageSeqFrame->StartPrint(poPresContext, mPrt->mPrintSettings, docTitleStr, docURLStr);
03293 
03294           if (!aDoSyncPrinting) {
03295             // Get the delay time in between the printing of each page
03296             // this gives the user more time to press cancel
03297             PRInt32 printPageDelay = 500;
03298             mPrt->mPrintSettings->GetPrintPageDelay(&printPageDelay);
03299 
03300             // Schedule Page to Print
03301             PR_PL(("Scheduling Print of PO: %p (%s) \n", aPO, gFrameTypesStr[aPO->mFrameType]));
03302             StartPagePrintTimer(poPresContext, mPrt->mPrintSettings, aPO, printPageDelay);
03303           } else {
03304             DoProgressForAsIsFrames();
03305             // Print the page synchronously
03306             PR_PL(("Async Print of PO: %p (%s) \n", aPO, gFrameTypesStr[aPO->mFrameType]));
03307             PRBool inRange;
03308             aDonePrinting = PrintPage(poPresContext, mPrt->mPrintSettings, aPO, inRange);
03309           }
03310         } else {
03311           pageSequence->StartPrint(poPresContext, mPrt->mPrintSettings, docTitleStr, docURLStr);
03312         }
03313       } else {
03314         // not sure what to do here!
03315         SetIsPrinting(PR_FALSE);
03316         return NS_ERROR_FAILURE;
03317       }
03318     }
03319   } else {
03320     aPO->mDontPrint = PR_TRUE;
03321     aDonePrinting = PR_FALSE;
03322   }
03323 
03324   return NS_OK;
03325 }
03326 
03327 //---------------------------------------------------------------------
03328 void
03329 nsPrintEngine::SetDocAndURLIntoProgress(nsPrintObject* aPO,
03330                                         nsIPrintProgressParams* aParams)
03331 {
03332   NS_ASSERTION(aPO, "Must have vaild nsPrintObject");
03333   NS_ASSERTION(aParams, "Must have vaild nsIPrintProgressParams");
03334 
03335   if (!aPO || !aPO->mDocShell || !aParams) {
03336     return;
03337   }
03338   const PRUint32 kTitleLength = 64;
03339 
03340   PRUnichar * docTitleStr;
03341   PRUnichar * docURLStr;
03342   GetDisplayTitleAndURL(aPO, mPrt->mPrintSettings, mPrt->mBrandName,
03343                         &docTitleStr, &docURLStr, eDocTitleDefURLDoc);
03344 
03345   // Make sure the Titles & URLS don't get too long for the progress dialog
03346   ElipseLongString(docTitleStr, kTitleLength, PR_FALSE);
03347   ElipseLongString(docURLStr, kTitleLength, PR_TRUE);
03348 
03349   aParams->SetDocTitle((const PRUnichar*) docTitleStr);
03350   aParams->SetDocURL((const PRUnichar*) docURLStr);
03351 
03352   if (docTitleStr != nsnull) nsMemory::Free(docTitleStr);
03353   if (docURLStr != nsnull) nsMemory::Free(docURLStr);
03354 }
03355 
03356 //---------------------------------------------------------------------
03357 void
03358 nsPrintEngine::ElipseLongString(PRUnichar *& aStr, const PRUint32 aLen, PRBool aDoFront)
03359 {
03360   // Make sure the URLS don't get too long for the progress dialog
03361   if (aStr && nsCRT::strlen(aStr) > aLen) {
03362     if (aDoFront) {
03363       PRUnichar * ptr = &aStr[nsCRT::strlen(aStr)-aLen+3];
03364       nsAutoString newStr;
03365       newStr.AppendLiteral("...");
03366       newStr += ptr;
03367       nsMemory::Free(aStr);
03368       aStr = ToNewUnicode(newStr);
03369     } else {
03370       nsAutoString newStr(aStr);
03371       newStr.SetLength(aLen-3);
03372       newStr.AppendLiteral("...");
03373       nsMemory::Free(aStr);
03374       aStr = ToNewUnicode(newStr);
03375     }
03376   }
03377 }
03378 
03379 //-------------------------------------------------------
03380 PRBool
03381 nsPrintEngine::PrintPage(nsPresContext*   aPresContext,
03382                               nsIPrintSettings* aPrintSettings,
03383                               nsPrintObject*      aPO,
03384                               PRBool&           aInRange)
03385 {
03386   NS_ASSERTION(aPresContext,   "aPresContext is null!");
03387   NS_ASSERTION(aPrintSettings, "aPrintSettings is null!");
03388   NS_ASSERTION(aPO,            "aPO is null!");
03389   NS_ASSERTION(mPageSeqFrame,  "mPageSeqFrame is null!");
03390   NS_ASSERTION(mPrt,           "mPrt is null!");
03391 
03392   // Although these should NEVER be NULL
03393   // This is added insurance, to make sure we don't crash in optimized builds
03394   if (!mPrt || !aPresContext || !aPrintSettings || !aPO || !mPageSeqFrame) {
03395     ShowPrintErrorDialog(NS_ERROR_FAILURE);
03396     return PR_TRUE; // means we are done printing
03397   }
03398 
03399   PR_PL(("-----------------------------------\n"));
03400   PR_PL(("------ In DV::PrintPage PO: %p (%s)\n", aPO, gFrameTypesStr[aPO->mFrameType]));
03401 
03402   PRBool isCancelled = PR_FALSE;
03403 
03404   // Check setting to see if someone request it be cancelled (programatically)
03405   aPrintSettings->GetIsCancelled(&isCancelled);
03406   if (!isCancelled) {
03407     // If not, see if the user has cancelled it
03408     if (mPrt->mPrintProgress) {
03409       mPrt->mPrintProgress->GetProcessCanceledByUser(&isCancelled);
03410     }
03411   }
03412 
03413   // DO NOT allow the print job to be cancelled if it is Print FrameAsIs
03414   // because it is only printing one page.
03415   if (isCancelled) {
03416     if (mPrt->mPrintFrameType == nsIPrintSettings::kFramesAsIs) {
03417       aPrintSettings->SetIsCancelled(PR_FALSE);
03418     } else {
03419       aPrintSettings->SetIsCancelled(PR_TRUE);
03420       return PR_TRUE;
03421     }
03422   }
03423 
03424   PRInt32 pageNum;
03425   PRInt32 curPage;
03426   PRInt32 endPage;
03427   mPageSeqFrame->GetCurrentPageNum(&pageNum);
03428 
03429   PRBool donePrinting = PR_FALSE;
03430   PRBool isDoingPrintRange;
03431   mPageSeqFrame->IsDoingPrintRange(&isDoingPrintRange);
03432   if (isDoingPrintRange) {
03433     PRInt32 fromPage;
03434     PRInt32 toPage;
03435     PRInt32 numPages;
03436     mPageSeqFrame->GetPrintRange(&fromPage, &toPage);
03437     mPageSeqFrame->GetNumPages(&numPages);
03438     if (fromPage > numPages) {
03439       return PR_TRUE;
03440     }
03441     if (toPage > numPages) {
03442       toPage = numPages;
03443     }
03444 
03445     PR_PL(("****** Printing Page %d printing from %d to page %d\n", pageNum, fromPage, toPage));
03446 
03447     donePrinting = pageNum >= toPage;
03448     aInRange = pageNum >= fromPage && pageNum <= toPage;
03449     PRInt32 pageInc = pageNum - fromPage + 1;
03450     curPage = pageInc >= 0?pageInc+1:0;
03451     endPage = (toPage - fromPage)+1;
03452   } else {
03453     PRInt32 numPages;
03454     mPageSeqFrame->GetNumPages(&numPages);
03455 
03456     PR_PL(("****** Printing Page %d of %d page(s)\n", pageNum, numPages));
03457 
03458     donePrinting = pageNum >= numPages;
03459     curPage = pageNum+1;
03460     endPage = numPages;
03461     aInRange = PR_TRUE;
03462   }
03463 
03464   // NOTE: mPrt->mPrintFrameType gets set to  "kFramesAsIs" when a
03465   // plain document contains IFrames, so we need to override that case here
03466   if (mPrt->mPrintFrameType == nsIPrintSettings::kEachFrameSep) {
03467     DoProgressForSeparateFrames();
03468 
03469   } else if (mPrt->mPrintFrameType != nsIPrintSettings::kFramesAsIs ||
03470              mPrt->mPrintObject->mFrameType == eDoc && aPO == mPrt->mPrintObject) {
03471     nsPrintData::DoOnProgressChange(mPrt->mPrintProgressListeners, curPage, endPage);
03472   }
03473 
03474   // Set Clip when Printing "AsIs" or
03475   // when printing an IFrame for SelectedFrame or EachFrame
03476   PRBool setClip = PR_FALSE;
03477   switch (mPrt->mPrintFrameType) {
03478 
03479     case nsIPrintSettings::kFramesAsIs:
03480       setClip = PR_TRUE;
03481       break;
03482 
03483     case nsIPrintSettings::kSelectedFrame:
03484       if (aPO->mPrintAsIs) {
03485         if (aPO->mFrameType == eIFrame) {
03486           setClip = aPO != mPrt->mSelectedPO;
03487         }
03488       }
03489       break;
03490 
03491     case nsIPrintSettings::kEachFrameSep:
03492       if (aPO->mPrintAsIs) {
03493         if (aPO->mFrameType == eIFrame) {
03494           setClip = PR_TRUE;
03495         }
03496       }
03497       break;
03498 
03499   } //switch
03500 
03501   if (setClip) {
03502     // Always set the clip x,y to zero because it isn't going to have any margins
03503     aPO->mClipRect.x = 0;
03504     aPO->mClipRect.y = 0;
03505     mPageSeqFrame->SetClipRect(aPO->mPresContext, &aPO->mClipRect);
03506   }
03507 
03508   // Print the Page
03509   // if a print job was cancelled externally, an EndPage or BeginPage may
03510   // fail and the failure is passed back here.
03511   // Returning PR_TRUE means we are done printing.
03512   //
03513   // When rv == NS_ERROR_ABORT, it means we want out of the
03514   // print job without displaying any error messages
03515   nsresult rv = mPageSeqFrame->PrintNextPage(aPresContext);
03516   CHECK_RUNTIME_ERROR_CONDITION(nsIDebugObject::PRT_RUNTIME_NEXTPAGE, rv, NS_ERROR_FAILURE);
03517   if (NS_FAILED(rv)) {
03518     if (rv != NS_ERROR_ABORT) {
03519       ShowPrintErrorDialog(rv);
03520       mPrt->mIsAborted = PR_TRUE;
03521     }
03522     return PR_TRUE;
03523   }
03524 
03525   // Now see if any of the SubDocs are on this page
03526   if (aPO->mPrintAsIs) {
03527     nsIPageSequenceFrame * curPageSeq = mPageSeqFrame;
03528     aPO->mHasBeenPrinted = PR_TRUE;
03529     PRInt32 cnt = aPO->mKids.Count();
03530     for (PRInt32 i=0;i<cnt;i++) {
03531       nsPrintObject* po = (nsPrintObject*)aPO->mKids[i];
03532       NS_ASSERTION(po, "nsPrintObject can't be null!");
03533       if (po->IsPrintable()) {
03534         // Now verify that SubDoc's PageNum matches the
03535         // page num of it's parent doc
03536         curPageSeq->GetCurrentPageNum(&pageNum);
03537         nsIFrame* fr;
03538         CallQueryInterface(curPageSeq, &fr);
03539 
03540         if (fr == po->mSeqFrame && pageNum == po->mPageNum) {
03541           PRBool donePrintingSubDoc;
03542           DoPrint(po, PR_TRUE, donePrintingSubDoc); // synchronous printing, it changes the value mPageSeqFrame
03543           po->mHasBeenPrinted = PR_TRUE;
03544         }
03545       }
03546     } // while
03547     mPageSeqFrame = curPageSeq;
03548 
03549     if (aPO->mParent == nsnull ||
03550         (aPO->mParent != nsnull && !aPO->mParent->mPrintAsIs && aPO->mPrintAsIs)) {
03551       mPageSeqFrame->DoPageEnd(aPresContext);
03552     }
03553 
03554     // XXX this is because PrintAsIs for FrameSets reflows to two pages
03555     // not sure why, but this needs to be fixed.
03556     if (aPO->mFrameType == eFrameSet && mPrt->mPrintFrameType == nsIPrintSettings::kFramesAsIs) {
03557       return PR_TRUE;
03558     }
03559   }
03560 
03561   return donePrinting;
03562 }
03563 
03564 //-------------------------------------------------------
03565 void
03566 nsPrintEngine::DoProgressForAsIsFrames()
03567 {
03568   // mPrintFrameType is set to kFramesAsIs event though the Doc Type maybe eDoc
03569   // this is done to make the printing of embedded IFrames easier
03570   // NOTE: we don't want to advance the progress in that case, it is down elsewhere
03571   if (mPrt->mPrintFrameType == nsIPrintSettings::kFramesAsIs && mPrt->mPrintObject->mFrameType != eDoc) {
03572     mPrt->mNumDocsPrinted++;
03573     nsPrintData::DoOnProgressChange(mPrt->mPrintProgressListeners, mPrt->mNumDocsPrinted, mPrt->mNumPrintableDocs);
03574   }
03575 }
03576 
03577 //-------------------------------------------------------
03578 void
03579 nsPrintEngine::DoProgressForSeparateFrames()
03580 {
03581   if (mPrt->mPrintFrameType == nsIPrintSettings::kEachFrameSep) {
03582     mPrt->mNumPagesPrinted++;
03583     // notify the listener of printed docs
03584     nsPrintData::DoOnProgressChange(mPrt->mPrintProgressListeners, mPrt->mNumPagesPrinted+1, mPrt->mNumPrintablePages);
03585   }
03586 }
03587 
03591 nsIFrame * 
03592 nsPrintEngine::FindFrameByType(nsPresContext* aPresContext,
03593                                nsIFrame *      aParentFrame,
03594                                nsIAtom *       aType,
03595                                nsRect&         aRect,
03596                                nsRect&         aChildRect)
03597 {
03598   NS_ASSERTION(aPresContext, "Pointer is null!");
03599   NS_ASSERTION(aParentFrame, "Pointer is null!");
03600   NS_ASSERTION(aType, "Pointer is null!");
03601 
03602   aRect += aParentFrame->GetPosition();
03603   nsIFrame* child = aParentFrame->GetFirstChild(nsnull);
03604   while (child) {
03605     nsIContent* content = child->GetContent();
03606     if (content && content->Tag() == aType) {
03607       nsRect r = child->GetRect();
03608       aChildRect.SetRect(aRect.x + r.x, aRect.y + r.y, r.width, r.height);
03609       aRect -= aParentFrame->GetPosition();
03610       return child;
03611     }
03612     nsIFrame * fndFrame = FindFrameByType(aPresContext, child, aType, aRect, aChildRect);
03613     if (fndFrame != nsnull) {
03614       return fndFrame;
03615     }
03616     child = child->GetNextSibling();
03617   }
03618   aRect -= aParentFrame->GetPosition();
03619   return nsnull;
03620 }
03621 
03625 nsresult 
03626 nsPrintEngine::FindSelectionBoundsWithList(nsPresContext* aPresContext,
03627                                            nsIRenderingContext& aRC,
03628                                            nsIAtom*        aList,
03629                                            nsIFrame *      aParentFrame,
03630                                            nsRect&         aRect,
03631                                            nsIFrame *&     aStartFrame,
03632                                            nsRect&         aStartRect,
03633                                            nsIFrame *&     aEndFrame,
03634                                            nsRect&         aEndRect)
03635 {
03636   NS_ASSERTION(aPresContext, "Pointer is null!");
03637   NS_ASSERTION(aParentFrame, "Pointer is null!");
03638 
03639   nsIFrame* child = aParentFrame->GetFirstChild(aList);
03640   aRect += aParentFrame->GetPosition();
03641   while (child) {
03642     // only leaf frames have this bit flipped
03643     // then check the hard way
03644     PRBool isSelected = (child->GetStateBits() & NS_FRAME_SELECTED_CONTENT)
03645       == NS_FRAME_SELECTED_CONTENT;
03646     if (isSelected) {
03647       if (NS_FAILED(child->IsVisibleForPainting(aPresContext, aRC, PR_TRUE, &isSelected))) {
03648         return NS_ERROR_FAILURE;
03649       }
03650     }
03651 
03652     if (isSelected) {
03653       nsRect r = child->GetRect();
03654       if (aStartFrame == nsnull) {
03655         aStartFrame = child;
03656         aStartRect.SetRect(aRect.x + r.x, aRect.y + r.y, r.width, r.height);
03657       } else {
03658         aEndFrame = child;
03659         aEndRect.SetRect(aRect.x + r.x, aRect.y + r.y, r.width, r.height);
03660       }
03661     }
03662     FindSelectionBounds(aPresContext, aRC, child, aRect, aStartFrame, aStartRect, aEndFrame, aEndRect);
03663     child = child->GetNextSibling();
03664   }
03665   aRect -= aParentFrame->GetPosition();
03666   return NS_OK;
03667 }
03668 
03669 //-------------------------------------------------------
03670 // Find the Frame that is XMost
03671 nsresult 
03672 nsPrintEngine::FindSelectionBounds(nsPresContext* aPresContext,
03673                                    nsIRenderingContext& aRC,
03674                                    nsIFrame *      aParentFrame,
03675                                    nsRect&         aRect,
03676                                    nsIFrame *&     aStartFrame,
03677                                    nsRect&         aStartRect,
03678                                    nsIFrame *&     aEndFrame,
03679                                    nsRect&         aEndRect)
03680 {
03681   NS_ASSERTION(aPresContext, "Pointer is null!");
03682   NS_ASSERTION(aParentFrame, "Pointer is null!");
03683 
03684   // loop thru named child lists
03685   nsIAtom* childListName = nsnull;
03686   PRInt32  childListIndex = 0;
03687   do {
03688     nsresult rv = FindSelectionBoundsWithList(aPresContext, aRC, childListName, aParentFrame, aRect, aStartFrame, aStartRect, aEndFrame, aEndRect);
03689     NS_ENSURE_SUCCESS(rv, rv);
03690     childListName = aParentFrame->GetAdditionalChildListName(childListIndex++);
03691   } while (childListName);
03692   return NS_OK;
03693 }
03694 
03701 nsresult 
03702 nsPrintEngine::GetPageRangeForSelection(nsIPresShell *        aPresShell,
03703                                         nsPresContext*       aPresContext,
03704                                         nsIRenderingContext&  aRC,
03705                                         nsISelection*         aSelection,
03706                                         nsIPageSequenceFrame* aPageSeqFrame,
03707                                         nsIFrame**            aStartFrame,
03708                                         PRInt32&              aStartPageNum,
03709                                         nsRect&               aStartRect,
03710                                         nsIFrame**            aEndFrame,
03711                                         PRInt32&              aEndPageNum,
03712                                         nsRect&               aEndRect)
03713 {
03714   NS_ASSERTION(aPresShell, "Pointer is null!");
03715   NS_ASSERTION(aPresContext, "Pointer is null!");
03716   NS_ASSERTION(aSelection, "Pointer is null!");
03717   NS_ASSERTION(aPageSeqFrame, "Pointer is null!");
03718   NS_ASSERTION(aStartFrame, "Pointer is null!");
03719   NS_ASSERTION(aEndFrame, "Pointer is null!");
03720 
03721   nsIFrame * seqFrame;
03722   if (NS_FAILED(CallQueryInterface(aPageSeqFrame, &seqFrame))) {
03723     return NS_ERROR_FAILURE;
03724   }
03725 
03726   nsIFrame * startFrame = nsnull;
03727   nsIFrame * endFrame   = nsnull;
03728 
03729   // start out with the sequence frame and search the entire frame tree
03730   // capturing the the starting and ending child frames of the selection
03731   // and their rects
03732   nsRect r = seqFrame->GetRect();
03733   FindSelectionBounds(aPresContext, aRC, seqFrame, r,
03734                       startFrame, aStartRect, endFrame, aEndRect);
03735 
03736 #ifdef DEBUG_rodsX
03737   printf("Start Frame: %p\n", startFrame);
03738   printf("End Frame:   %p\n", endFrame);
03739 #endif
03740 
03741   // initial the page numbers here
03742   // in case we don't find and frames
03743   aStartPageNum = -1;
03744   aEndPageNum   = -1;
03745 
03746   nsIFrame * startPageFrame;
03747   nsIFrame * endPageFrame;
03748 
03749   // check to make sure we found a starting frame
03750   if (startFrame != nsnull) {
03751     // Now search up the tree to find what page the
03752     // start/ending selections frames are on
03753     //
03754     // Check to see if start should be same as end if
03755     // the end frame comes back null
03756     if (endFrame == nsnull) {
03757       // XXX the "GetPageFrame" step could be integrated into
03758       // the FindSelectionBounds step, but walking up to find
03759       // the parent of a child frame isn't expensive and it makes
03760       // FindSelectionBounds a little easier to understand
03761       startPageFrame = nsLayoutUtils::GetPageFrame(startFrame);
03762       endPageFrame   = startPageFrame;
03763       aEndRect       = aStartRect;
03764     } else {
03765       startPageFrame = nsLayoutUtils::GetPageFrame(startFrame);
03766       endPageFrame   = nsLayoutUtils::GetPageFrame(endFrame);
03767     }
03768   } else {
03769     return NS_ERROR_FAILURE;
03770   }
03771 
03772 #ifdef DEBUG_rodsX
03773   printf("Start Page: %p\n", startPageFrame);
03774   printf("End Page:   %p\n", endPageFrame);
03775 
03776   // dump all the pages and their pointers
03777   {
03778   PRInt32 pageNum = 1;
03779   nsIFrame* child = seqFrame->GetFirstChild(nsnull);
03780   while (child != nsnull) {
03781     printf("Page: %d - %p\n", pageNum, child);
03782     pageNum++;
03783     child = child->GetNextSibling();
03784   }
03785   }
03786 #endif
03787 
03788   // Now that we have the page frames
03789   // find out what the page numbers are for each frame
03790   PRInt32 pageNum = 1;
03791   nsIFrame* page = seqFrame->GetFirstChild(nsnull);
03792   while (page != nsnull) {
03793     if (page == startPageFrame) {
03794       aStartPageNum = pageNum;
03795     }
03796     if (page == endPageFrame) {
03797       aEndPageNum = pageNum;
03798     }
03799     pageNum++;
03800     page = page->GetNextSibling();
03801   }
03802 
03803 #ifdef DEBUG_rodsX
03804   printf("Start Page No: %d\n", aStartPageNum);
03805   printf("End Page No:   %d\n", aEndPageNum);
03806 #endif
03807 
03808   *aStartFrame = startPageFrame;
03809   *aEndFrame   = endPageFrame;
03810 
03811   return NS_OK;
03812 }
03813 
03814 //-----------------------------------------------------------------
03815 //-- Done: Printing Methods
03816 //-----------------------------------------------------------------
03817 
03818 
03819 //-----------------------------------------------------------------
03820 //-- Section: Misc Support Methods
03821 //-----------------------------------------------------------------
03822 
03823 //---------------------------------------------------------------------
03824 void nsPrintEngine::SetIsPrinting(PRBool aIsPrinting)
03825 { 
03826   mIsDoingPrinting = aIsPrinting;
03827   if (mDocViewerPrint) {
03828     mDocViewerPrint->SetIsPrinting(aIsPrinting);
03829   }
03830 }
03831 
03832 //---------------------------------------------------------------------
03833 void nsPrintEngine::SetIsPrintPreview(PRBool aIsPrintPreview) 
03834 { 
03835   mIsDoingPrintPreview = aIsPrintPreview; 
03836 
03837   if (mDocViewerPrint) {
03838     mDocViewerPrint->SetIsPrintPreview(aIsPrintPreview);
03839   }
03840 }
03841 
03842 //---------------------------------------------------------------------
03843 void
03844 nsPrintEngine::CleanupDocTitleArray(PRUnichar**& aArray, PRInt32& aCount)
03845 {
03846   for (PRInt32 i = aCount - 1; i >= 0; i--) {
03847     nsMemory::Free(aArray[i]);
03848   }
03849   nsMemory::Free(aArray);
03850   aArray = NULL;
03851   aCount = 0;
03852 }
03853 //---------------------------------------------------------------------
03854 // This gets ref counted copies of the PresShell and Root Content
03855 // for a given docshell
03856 // static
03857 void
03858 nsPrintEngine::GetPresShellAndRootContent(nsIDocShell *  aDocShell,
03859                                           nsIPresShell** aPresShell,
03860                                           nsIContent**   aContent)
03861 {
03862   NS_ASSERTION(aDocShell, "Pointer is null!");
03863   NS_ASSERTION(aPresShell, "Pointer is null!");
03864   NS_ASSERTION(aContent, "Pointer is null!");
03865 
03866   *aContent   = nsnull;
03867   *aPresShell = nsnull;
03868 
03869   nsCOMPtr<nsIDOMDocument> domDoc(do_GetInterface(aDocShell));
03870 
03871   nsCOMPtr<nsIDocument> doc(do_QueryInterface(domDoc));
03872   if (!doc)
03873     return;
03874 
03875   nsIPresShell *presShell = doc->GetShellAt(0);
03876   if (!presShell)
03877     return;
03878 
03879   NS_IF_ADDREF(*aContent = doc->GetRootContent());
03880   NS_ADDREF(*aPresShell = presShell);
03881 }
03882 
03883 //---------------------------------------------------------------------
03884 // static
03885 PRBool nsPrintEngine::HasFramesetChild(nsIContent* aContent)
03886 {
03887   if (!aContent) {
03888     return PR_FALSE;
03889   }
03890 
03891   PRUint32 numChildren = aContent->GetChildCount();
03892 
03893   // do a breadth search across all siblings
03894   for (PRUint32 i = 0; i < numChildren; ++i) {
03895     nsIContent *child = aContent->GetChildAt(i);
03896     if (child->Tag() == nsHTMLAtoms::frameset &&
03897         child->IsContentOfType(nsIContent::eHTML)) {
03898       return PR_TRUE;
03899     }
03900   }
03901 
03902   return PR_FALSE;
03903 }
03904  
03905 
03906 
03910 already_AddRefed<nsIDOMWindow>
03911 nsPrintEngine::FindFocusedDOMWindow()
03912 {
03913   nsCOMPtr<nsIDocument>           theDoc;
03914   nsIDOMWindow *                  domWin = nsnull;
03915 
03916   mDocViewer->GetDocument(getter_AddRefs(theDoc));
03917   if(theDoc){
03918     nsIScriptGlobalObject* theSGO = theDoc->GetScriptGlobalObject();
03919     nsCOMPtr<nsPIDOMWindow> theDOMWindow = do_QueryInterface(theSGO);
03920     if(theDOMWindow){
03921       nsIFocusController *focusController =
03922         theDOMWindow->GetRootFocusController();
03923       if (focusController) {
03924         nsCOMPtr<nsIDOMWindowInternal> theDOMWin;
03925         focusController->GetFocusedWindow(getter_AddRefs(theDOMWin));
03926         if(theDOMWin && IsWindowsInOurSubTree(theDOMWin)){
03927           NS_ADDREF(domWin = theDOMWin);
03928         }
03929       }
03930     }
03931   }
03932 
03933   return domWin;
03934 }
03935 
03936 //---------------------------------------------------------------------
03937 PRBool
03938 nsPrintEngine::IsWindowsInOurSubTree(nsIDOMWindow * aDOMWindow)
03939 {
03940   PRBool found = PR_FALSE;
03941 
03942   // now check to make sure it is in "our" tree of docshells
03943   nsCOMPtr<nsIScriptGlobalObject> scriptObj(do_QueryInterface(aDOMWindow));
03944   if (scriptObj) {
03945     nsCOMPtr<nsIDocShellTreeItem> docShellAsItem =
03946       do_QueryInterface(scriptObj->GetDocShell());
03947 
03948     if (docShellAsItem) {
03949       // get this DocViewer docshell
03950       nsCOMPtr<nsIDocShell> thisDVDocShell(do_QueryInterface(mContainer));
03951       while (!found) {
03952         nsCOMPtr<nsIDocShellTreeItem> docShellParent;
03953         docShellAsItem->GetSameTypeParent(getter_AddRefs(docShellParent));
03954 
03955         nsCOMPtr<nsIDocShell> parentDocshell(do_QueryInterface(docShellParent));
03956         if (parentDocshell) {
03957           if (parentDocshell == thisDVDocShell) {
03958             found = PR_TRUE;
03959             break;
03960           }
03961         } else {
03962           break; // at top of tree
03963         }
03964         docShellAsItem = docShellParent;
03965       } // while
03966     }
03967   } // scriptobj
03968 
03969   return found;
03970 }
03971 
03972 //-------------------------------------------------------
03973 PRBool
03974 nsPrintEngine::DonePrintingPages(nsPrintObject* aPO, nsresult aResult)
03975 {
03976   //NS_ASSERTION(aPO, "Pointer is null!");
03977   PR_PL(("****** In DV::DonePrintingPages PO: %p (%s)\n", aPO, aPO?gFrameTypesStr[aPO->mFrameType]:""));
03978 
03979   if (aPO != nsnull) {
03980     aPO->mHasBeenPrinted = PR_TRUE;
03981     nsresult rv;
03982     PRBool didPrint = PrintDocContent(mPrt->mPrintObject, rv);
03983     if (NS_SUCCEEDED(rv) && didPrint) {
03984       PR_PL(("****** In DV::DonePrintingPages PO: %p (%s) didPrint:%s (Not Done Printing)\n", aPO, gFrameTypesStr[aPO->mFrameType], PRT_YESNO(didPrint)));
03985       return PR_FALSE;
03986     }
03987   }
03988 
03989   DoProgressForAsIsFrames();
03990   DoProgressForSeparateFrames();
03991 
03992   if (NS_SUCCEEDED(aResult)) {
03993     FirePrintCompletionEvent();
03994   }
03995 
03996   SetIsPrinting(PR_FALSE);
03997 
03998   NS_IF_RELEASE(mPagePrintTimer);
03999 
04000   return PR_TRUE;
04001 }
04002 
04003 //-------------------------------------------------------
04004 // Recursively sets the PO items to be printed "As Is"
04005 // from the given item down into the tree
04006 void
04007 nsPrintEngine::SetPrintAsIs(nsPrintObject* aPO, PRBool aAsIs)
04008 {
04009   NS_ASSERTION(aPO, "Pointer is null!");
04010 
04011   aPO->mPrintAsIs = aAsIs;
04012   for (PRInt32 i=0;i<aPO->mKids.Count();i++) {
04013     SetPrintAsIs((nsPrintObject*)aPO->mKids[i], aAsIs);
04014   }
04015 }
04016 
04017 
04018 //-------------------------------------------------------
04019 // Recursively sets the clip rect on all thchildren
04020 void
04021 nsPrintEngine::SetClipRect(nsPrintObject*  aPO,
04022                                 const nsRect& aClipRect,
04023                                 nscoord       aOffsetX,
04024                                 nscoord       aOffsetY,
04025                                 PRBool        aDoingSetClip)
04026 {
04027   NS_ASSERTION(aPO, "Pointer is null!");
04028 
04029   nsRect clipRect = aClipRect;
04030   if (aDoingSetClip) {
04031     nscoord width  = (aPO->mRect.x+aPO->mRect.width) > aClipRect.width?aClipRect.width-aPO->mRect.x:aPO->mRect.width;
04032     nscoord height = (aPO->mRect.y+aPO->mRect.height) > aClipRect.height?aClipRect.height-aPO->mRect.y:aPO->mRect.height;
04033     aPO->mClipRect.SetRect(aPO->mRect.x, aPO->mRect.y, width, height);
04034 
04035   }
04036 
04037   PRBool doClip = aDoingSetClip;
04038 
04039   if (aPO->mFrameType == eFrame) {
04040     if (aDoingSetClip) {
04041       aPO->mClipRect.SetRect(aOffsetX, aOffsetY, aPO->mClipRect.width, aPO->mClipRect.height);
04042       clipRect = aPO->mClipRect;
04043     } else if (mPrt->mPrintFrameType == nsIPrintSettings::kFramesAsIs) {
04044       aPO->mClipRect.SetRect(aOffsetX, aOffsetY, aPO->mRect.width, aPO->mRect.height);
04045       clipRect = aPO->mClipRect;
04046       doClip = PR_TRUE;
04047     }
04048 
04049   } else if (aPO->mFrameType == eIFrame) {
04050 
04051     if (aDoingSetClip) {
04052       aPO->mClipRect.SetRect(aOffsetX, aOffsetY, aPO->mClipRect.width, aPO->mClipRect.height);
04053       clipRect = aPO->mClipRect;
04054     } else {
04055 
04056       if (mPrt->mPrintFrameType == nsIPrintSettings::kSelectedFrame) {
04057         if (aPO->mParent && aPO->mParent == mPrt->mSelectedPO) {
04058           aPO->mClipRect.SetRect(aOffsetX, aOffsetY, aPO->mRect.width, aPO->mRect.height);
04059           clipRect = aPO->mClipRect;
04060           doClip = PR_TRUE;
04061         }
04062       } else {
04063         aPO->mClipRect.SetRect(aOffsetX, aOffsetY, aPO->mRect.width, aPO->mRect.height);
04064         clipRect = aPO->mClipRect;
04065         doClip = PR_TRUE;
04066       }
04067     }
04068 
04069   }
04070 
04071 
04072   PR_PL(("In DV::SetClipRect PO: %p (%9s) ", aPO, gFrameTypesStr[aPO->mFrameType]));
04073   PR_PL(("%5d,%5d,%5d,%5d\n", aPO->mClipRect.x, aPO->mClipRect.y,aPO->mClipRect.width, aPO->mClipRect.height));
04074 
04075   PRInt32 cnt = aPO->mKids.Count();
04076   for (PRInt32 i=0;i<cnt;i++) {
04077     SetClipRect((nsPrintObject *)aPO->mKids[i], clipRect,
04078                 aOffsetX+aPO->mRect.x, aOffsetY+aPO->mRect.y, doClip);
04079   }
04080 }
04081 
04082 
04083 //-------------------------------------------------------
04084 // Given a DOMWindow it recursively finds the PO object that matches
04085 nsPrintObject*
04086 nsPrintEngine::FindPrintObjectByDOMWin(nsPrintObject* aPO,
04087                                        nsIDOMWindow* aDOMWin)
04088 {
04089   NS_ASSERTION(aPO, "Pointer is null!");
04090 
04091   // Often the CurFocused DOMWindow is passed in
04092   // andit is valid for it to be null, so short circut
04093   if (!aDOMWin) {
04094     return nsnull;
04095   }
04096 
04097   nsCOMPtr<nsIDOMWindow> domWin(do_GetInterface(aPO->mDocShell));
04098   if (domWin && domWin == aDOMWin) {
04099     return aPO;
04100   }
04101 
04102   PRInt32 cnt = aPO->mKids.Count();
04103   for (PRInt32 i = 0; i < cnt; ++i) {
04104     nsPrintObject* po = FindPrintObjectByDOMWin((nsPrintObject*)aPO->mKids[i],
04105                                                 aDOMWin);
04106     if (po) {
04107       return po;
04108     }
04109   }
04110 
04111   return nsnull;
04112 }
04113 
04114 //-------------------------------------------------------
04115 nsresult
04116 nsPrintEngine::EnablePOsForPrinting()
04117 {
04118   // NOTE: All POs have been "turned off" for printing
04119   // this is where we decided which POs get printed.
04120   mPrt->mSelectedPO = nsnull;
04121 
04122   if (mPrt->mPrintSettings == nsnull) {
04123     return NS_ERROR_FAILURE;
04124   }
04125 
04126   mPrt->mPrintFrameType = nsIPrintSettings::kNoFrames;
04127   mPrt->mPrintSettings->GetPrintFrameType(&mPrt->mPrintFrameType);
04128 
04129   PRInt16 printHowEnable = nsIPrintSettings::kFrameEnableNone;
04130   mPrt->mPrintSettings->GetHowToEnableFrameUI(&printHowEnable);
04131 
04132   PRInt16 printRangeType = nsIPrintSettings::kRangeAllPages;
04133   mPrt->mPrintSettings->GetPrintRange(&printRangeType);
04134 
04135   PR_PL(("\n"));
04136   PR_PL(("********* nsPrintEngine::EnablePOsForPrinting *********\n"));
04137   PR_PL(("PrintFrameType:     %s \n", gPrintFrameTypeStr[mPrt->mPrintFrameType]));
04138   PR_PL(("HowToEnableFrameUI: %s \n", gFrameHowToEnableStr[printHowEnable]));
04139   PR_PL(("PrintRange:         %s \n", gPrintRangeStr[printRangeType]));
04140   PR_PL(("----\n"));
04141 
04142   // ***** This is the ultimate override *****
04143   // if we are printing the selection (either an IFrame or selection range)
04144   // then set the mPrintFrameType as if it were the selected frame
04145   if (printRangeType == nsIPrintSettings::kRangeSelection) {
04146     mPrt->mPrintFrameType = nsIPrintSettings::kSelectedFrame;
04147     printHowEnable        = nsIPrintSettings::kFrameEnableNone;
04148   }
04149 
04150   // This tells us that the "Frame" UI has turned off,
04151   // so therefore there are no FrameSets/Frames/IFrames to be printed
04152   //
04153   // This means there are not FrameSets,
04154   // but the document could contain an IFrame
04155   if (printHowEnable == nsIPrintSettings::kFrameEnableNone) {
04156 
04157     // Print all the pages or a sub range of pages
04158     if (printRangeType == nsIPrintSettings::kRangeAllPages ||
04159         printRangeType == nsIPrintSettings::kRangeSpecifiedPageRange) {
04160       SetPrintPO(mPrt->mPrintObject, PR_TRUE);
04161 
04162       // Set the children so they are PrinAsIs
04163       // In this case, the children are probably IFrames
04164       if (mPrt->mPrintObject->mKids.Count() > 0) {
04165         for (PRInt32 i=0;i<mPrt->mPrintObject->mKids.Count();i++) {
04166           nsPrintObject* po = (nsPrintObject*)mPrt->mPrintObject->mKids[i];
04167           NS_ASSERTION(po, "nsPrintObject can't be null!");
04168           SetPrintAsIs(po);
04169         }
04170 
04171         // ***** Another override *****
04172         mPrt->mPrintFrameType = nsIPrintSettings::kFramesAsIs;
04173       }
04174       PR_PL(("PrintFrameType:     %s \n", gPrintFrameTypeStr[mPrt->mPrintFrameType]));
04175       PR_PL(("HowToEnableFrameUI: %s \n", gFrameHowToEnableStr[printHowEnable]));
04176       PR_PL(("PrintRange:         %s \n", gPrintRangeStr[printRangeType]));
04177       return NS_OK;
04178     }
04179 
04180     // This means we are either printed a selected IFrame or
04181     // we are printing the current selection
04182     if (printRangeType == nsIPrintSettings::kRangeSelection) {
04183 
04184       // If the currentFocusDOMWin can'r be null if something is selected
04185       if (mPrt->mCurrentFocusWin) {
04186         // Find the selected IFrame
04187         nsPrintObject * po = FindPrintObjectByDOMWin(mPrt->mPrintObject, mPrt->mCurrentFocusWin);
04188         if (po != nsnull) {
04189           mPrt->mSelectedPO = po;
04190           // Makes sure all of its children are be printed "AsIs"
04191           SetPrintAsIs(po);
04192 
04193           // Now, only enable this POs (the selected PO) and all of its children
04194           SetPrintPO(po, PR_TRUE);
04195 
04196           // check to see if we have a range selection,
04197           // as oppose to a insert selection
04198           // this means if the user just clicked on the IFrame then
04199           // there will not be a selection so we want the entire page to print
04200           //
04201           // XXX this is sort of a hack right here to make the page
04202           // not try to reposition itself when printing selection
04203           nsCOMPtr<nsIDOMWindow> domWin = do_GetInterface(po->mDocShell);
04204           if (!IsThereARangeSelection(domWin)) {
04205             printRangeType = nsIPrintSettings::kRangeAllPages;
04206             mPrt->mPrintSettings->SetPrintRange(printRangeType);
04207           }
04208           PR_PL(("PrintFrameType:     %s \n", gPrintFrameTypeStr[mPrt->mPrintFrameType]));
04209           PR_PL(("HowToEnableFrameUI: %s \n", gFrameHowToEnableStr[printHowEnable]));
04210           PR_PL(("PrintRange:         %s \n", gPrintRangeStr[printRangeType]));
04211           return NS_OK;
04212         }
04213       } else {
04214         for (PRInt32 i=0;i<mPrt->mPrintDocList->Count();i++) {
04215           nsPrintObject* po = (nsPrintObject*)mPrt->mPrintDocList->ElementAt(i);
04216           NS_ASSERTION(po, "nsPrintObject can't be null!");
04217           nsCOMPtr<nsIDOMWindow> domWin = do_GetInterface(po->mDocShell);
04218           if (IsThereARangeSelection(domWin)) {
04219             mPrt->mCurrentFocusWin = domWin;
04220             SetPrintPO(po, PR_TRUE);
04221             break;
04222           }
04223         }
04224         return NS_OK;
04225       }
04226     }
04227   }
04228 
04229   // check to see if there is a selection when a FrameSet is present
04230   if (printRangeType == nsIPrintSettings::kRangeSelection) {
04231     // If the currentFocusDOMWin can'r be null if something is selected
04232     if (mPrt->mCurrentFocusWin) {
04233       // Find the selected IFrame
04234       nsPrintObject * po = FindPrintObjectByDOMWin(mPrt->mPrintObject, mPrt->mCurrentFocusWin);
04235       if (po != nsnull) {
04236         mPrt->mSelectedPO = po;
04237         // Makes sure all of its children are be printed "AsIs"
04238         SetPrintAsIs(po);
04239 
04240         // Now, only enable this POs (the selected PO) and all of its children
04241         SetPrintPO(po, PR_TRUE);
04242 
04243         // check to see if we have a range selection,
04244         // as oppose to a insert selection
04245         // this means if the user just clicked on the IFrame then
04246         // there will not be a selection so we want the entire page to print
04247         //
04248         // XXX this is sort of a hack right here to make the page
04249         // not try to reposition itself when printing selection
04250         nsCOMPtr<nsIDOMWindow> domWin = do_GetInterface(po->mDocShell);
04251         if (!IsThereARangeSelection(domWin)) {
04252           printRangeType = nsIPrintSettings::kRangeAllPages;
04253           mPrt->mPrintSettings->SetPrintRange(printRangeType);
04254         }
04255         PR_PL(("PrintFrameType:     %s \n", gPrintFrameTypeStr[mPrt->mPrintFrameType]));
04256         PR_PL(("HowToEnableFrameUI: %s \n", gFrameHowToEnableStr[printHowEnable]));
04257         PR_PL(("PrintRange:         %s \n", gPrintRangeStr[printRangeType]));
04258         return NS_OK;
04259       }
04260     }
04261   }
04262 
04263   // If we are printing "AsIs" then sets all the POs to be printed as is
04264   if (mPrt->mPrintFrameType == nsIPrintSettings::kFramesAsIs) {
04265     SetPrintAsIs(mPrt->mPrintObject);
04266     SetPrintPO(mPrt->mPrintObject, PR_TRUE);
04267     return NS_OK;
04268   }
04269 
04270   // If we are printing the selected Frame then
04271   // find that PO for that selected DOMWin and set it all of its
04272   // children to be printed
04273   if (mPrt->mPrintFrameType == nsIPrintSettings::kSelectedFrame) {
04274 
04275     if ((mPrt->mIsParentAFrameSet && mPrt->mCurrentFocusWin) || mPrt->mIsIFrameSelected) {
04276       nsPrintObject * po = FindPrintObjectByDOMWin(mPrt->mPrintObject, mPrt->mCurrentFocusWin);
04277       if (po != nsnull) {
04278         mPrt->mSelectedPO = po;
04279         // NOTE: Calling this sets the "po" and
04280         // we don't want to do this for documents that have no children,
04281         // because then the "DoEndPage" gets called and it shouldn't
04282         if (po->mKids.Count() > 0) {
04283           // Makes sure that itself, and all of its children are printed "AsIs"
04284           SetPrintAsIs(po);
04285         }
04286 
04287         // Now, only enable this POs (the selected PO) and all of its children
04288         SetPrintPO(po, PR_TRUE);
04289       }
04290     }
04291     return NS_OK;
04292   }
04293 
04294   // If we are print each subdoc separately,
04295   // then don't print any of the FraneSet Docs
04296   if (mPrt->mPrintFrameType == nsIPrintSettings::kEachFrameSep) {
04297     SetPrintPO(mPrt->mPrintObject, PR_TRUE);
04298     PRInt32 cnt = mPrt->mPrintDocList->Count();
04299     for (PRInt32 i=0;i<cnt;i++) {
04300       nsPrintObject* po = (nsPrintObject*)mPrt->mPrintDocList->ElementAt(i);
04301       NS_ASSERTION(po, "nsPrintObject can't be null!");
04302       if (po->mFrameType == eFrameSet) {
04303         po->mDontPrint = PR_TRUE;
04304       }
04305     }
04306   }
04307 
04308   return NS_OK;
04309 }
04310 
04311 //-------------------------------------------------------
04312 // Return the nsPrintObject with that is XMost (The widest frameset frame) AND
04313 // contains the XMost (widest) layout frame
04314 nsPrintObject*
04315 nsPrintEngine::FindSmallestSTF()
04316 {
04317   float smallestRatio = 1.0f;
04318   nsPrintObject* smallestPO = nsnull;
04319 
04320   for (PRInt32 i=0;i<mPrt->mPrintDocList->Count();i++) {
04321     nsPrintObject* po = (nsPrintObject*)mPrt->mPrintDocList->ElementAt(i);
04322     NS_ASSERTION(po, "nsPrintObject can't be null!");
04323     if (po->mFrameType != eFrameSet && po->mFrameType != eIFrame) {
04324       if (po->mShrinkRatio < smallestRatio) {
04325         smallestRatio = po->mShrinkRatio;
04326         smallestPO    = po;
04327       }
04328     }
04329   }
04330 
04331 #ifdef EXTENDED_DEBUG_PRINTING
04332   if (smallestPO) printf("*PO: %p  Type: %d  %10.3f\n", smallestPO, smallestPO->mFrameType, smallestPO->mShrinkRatio);
04333 #endif
04334   return smallestPO;
04335 }
04336 
04337 //-------------------------------------------------------
04338 // Recursively walks the nsPrintObject tree and installs the DocViewer
04339 // as an event processor and it shows the window
04340 nsresult
04341 nsPrintEngine::ShowDocListInternal(nsPrintObject* aPO, PRBool aShow)
04342 {
04343   NS_ASSERTION(aPO, "Pointer is null!");
04344 
04345   if (aPO->IsPrintable()) {
04346     PRBool donePrinting;
04347     DoPrint(aPO, PR_FALSE, donePrinting);
04348 
04349     // mWindow will be null for POs that are hidden, so they don't get
04350     // shown
04351     if (aPO->mWindow) {
04352       aPO->mWindow->Show(aShow);
04353     }
04354   }
04355 
04356   if (!aPO->mInvisible) {
04357     PRInt32 cnt = aPO->mKids.Count();
04358     for (PRInt32 i=0;i<cnt;i++) {
04359       if (NS_FAILED(ShowDocListInternal((nsPrintObject *)aPO->mKids[i], aShow))) {
04360         return NS_ERROR_FAILURE;
04361       }
04362     }
04363   }
04364 
04365   return NS_OK;
04366 }
04367 
04368 //-------------------------------------------------------
04369 nsresult
04370 nsPrintEngine::ShowDocList(PRBool aShow)
04371 {
04372   return ShowDocListInternal(mPrt->mPrintObject, aShow);
04373 }
04374 
04375 //-------------------------------------------------------
04376 void
04377 nsPrintEngine::TurnScriptingOn(PRBool aDoTurnOn)
04378 {
04379   nsPrintData* prt = mPrt;
04380 #ifdef NS_PRINT_PREVIEW
04381   if (!prt) {
04382     prt = mPrtPreview;
04383   }
04384 #endif
04385   if (!prt) {
04386     return;
04387   }
04388 
04389   NS_ASSERTION(mDocument, "We MUST have a document.");
04390   // First, get the script global object from the document...
04391 
04392   for (PRInt32 i=0;i<prt->mPrintDocList->Count();i++) {
04393     nsPrintObject* po = (nsPrintObject*)prt->mPrintDocList->ElementAt(i);
04394     NS_ASSERTION(po, "nsPrintObject can't be null!");
04395 
04396     nsIDocument* doc = po->mDocument;
04397     
04398     // get the script global object
04399     nsIScriptGlobalObject *scriptGlobalObj = doc->GetScriptGlobalObject();
04400     if (scriptGlobalObj) {
04401       nsIScriptContext *scx = scriptGlobalObj->GetContext();
04402       NS_ASSERTION(scx, "Can't get nsIScriptContext");
04403       if (aDoTurnOn) {
04404         doc->DeleteProperty(nsLayoutAtoms::scriptEnabledBeforePrintPreview);
04405       } else {
04406         // Have to be careful, because people call us over and over again with
04407         // aDoTurnOn == PR_FALSE.  So don't set the property if it's already
04408         // set, since in that case we'd set it to the wrong value.
04409         nsresult propThere;
04410         doc->GetProperty(nsLayoutAtoms::scriptEnabledBeforePrintPreview,
04411                          &propThere);
04412         if (propThere == NS_PROPTABLE_PROP_NOT_THERE) {
04413           // Stash the current value of IsScriptEnabled on the document, so
04414           // that layout code running in print preview doesn't get confused.
04415           doc->SetProperty(nsLayoutAtoms::scriptEnabledBeforePrintPreview,
04416                            NS_INT32_TO_PTR(doc->IsScriptEnabled()));
04417         }
04418       }
04419       scx->SetScriptsEnabled(aDoTurnOn, PR_TRUE);
04420     }
04421   }
04422 }
04423 
04424 //-----------------------------------------------------------------
04425 //-- Done: Misc Support Methods
04426 //-----------------------------------------------------------------
04427 
04428 
04429 //-----------------------------------------------------------------
04430 //-- Section: Finishing up or Cleaning up
04431 //-----------------------------------------------------------------
04432 
04433 //-----------------------------------------------------------------
04434 void
04435 nsPrintEngine::CloseProgressDialog(nsIWebProgressListener* aWebProgressListener)
04436 {
04437   if (aWebProgressListener) {
04438     aWebProgressListener->OnStateChange(nsnull, nsnull, nsIWebProgressListener::STATE_STOP|nsIWebProgressListener::STATE_IS_DOCUMENT, nsnull);
04439   }
04440 }
04441 
04442 //-----------------------------------------------------------------
04443 nsresult
04444 nsPrintEngine::FinishPrintPreview()
04445 {
04446   nsresult rv = NS_OK;
04447 
04448 #ifdef NS_PRINT_PREVIEW
04449 
04450   rv = DocumentReadyForPrinting();
04451 
04452   SetIsCreatingPrintPreview(PR_FALSE);
04453 
04454   /* cleaup on failure + notify user */
04455   if (NS_FAILED(rv)) {
04456     /* cleanup done, let's fire-up an error dialog to notify the user
04457      * what went wrong...
04458      */
04459     SetIsPrintPreview(PR_FALSE);
04460     mPrt->OnEndPrinting();
04461     TurnScriptingOn(PR_TRUE);
04462 
04463     FirePrintCompletionEvent();
04464 
04465     return CleanupOnFailure(rv, PR_FALSE); // ignore return value here
04466   }
04467 
04468   // At this point we are done preparing everything
04469   // before it is to be created
04470 
04471   // Noew create the new Presentation and display it
04472   mDocViewerPrint->InstallNewPresentation();
04473 
04474   mPrt->OnEndPrinting();
04475   // PrintPreview was built using the mPrt (code reuse)
04476   // then we assign it over
04477   mPrtPreview = mPrt;
04478   mPrt        = nsnull;
04479 
04480   // Turning off the scaling of twips so any of the UI scrollbars
04481   // will not get scaled
04482   if (mPresContext->Type() == nsPresContext::eContext_PrintPreview) {
04483     mPresContext->SetScalingOfTwips(PR_FALSE);
04484     mDeviceContext->SetCanonicalPixelScale(mPrtPreview->mOrigDCScale);
04485   }
04486 
04487 #endif // NS_PRINT_PREVIEW
04488 
04489   return NS_OK;
04490 }
04491 
04492 //-----------------------------------------------------------------
04493 //-- Done: Finishing up or Cleaning up
04494 //-----------------------------------------------------------------
04495 
04496 
04497 /*=============== Timer Related Code ======================*/
04498 nsresult
04499 nsPrintEngine::StartPagePrintTimer(nsPresContext * aPresContext,
04500                                         nsIPrintSettings* aPrintSettings,
04501                                         nsPrintObject*     aPOect,
04502                                         PRUint32         aDelay)
04503 {
04504   nsresult result;
04505 
04506   if (!mPagePrintTimer) {
04507     result = NS_NewPagePrintTimer(&mPagePrintTimer);
04508 
04509     if (NS_FAILED(result))
04510       return result;
04511 
04512     mDocViewerPrint->IncrementDestroyRefCount();
04513   }
04514 
04515   return mPagePrintTimer->Start(this, mDocViewerPrint, aPresContext, aPrintSettings, aPOect, aDelay);
04516 }
04517 
04518 /*=============== nsIObserver Interface ======================*/
04519 NS_IMETHODIMP 
04520 nsPrintEngine::Observe(nsISupports *aSubject, const char *aTopic, const PRUnichar *aData)
04521 {
04522   nsresult rv = NS_ERROR_FAILURE;
04523 
04524   if (mIsDoingPrinting) {
04525     rv = DocumentReadyForPrinting();
04526  
04527     /* cleaup on failure + notify user */
04528     if (NS_FAILED(rv)) {
04529       CleanupOnFailure(rv, PR_TRUE);
04530     }
04531   } else {
04532     rv = FinishPrintPreview();
04533     if (mPrtPreview) {
04534       mPrtPreview->OnEndPrinting();
04535     }
04536     rv = NS_OK;
04537   }
04538 
04539   return rv;
04540 
04541 }
04542 
04543 //---------------------------------------------------------------
04544 //-- PLEvent Notification
04545 //---------------------------------------------------------------
04546 void PR_CALLBACK HandlePLEvent(PLEvent* aEvent)
04547 {
04548   nsIDocumentViewerPrint *docViewerPrint = (nsIDocumentViewerPrint*)PL_GetEventOwner(aEvent);
04549 
04550   NS_ASSERTION(docViewerPrint, "The event owner is null.");
04551   if (docViewerPrint) {
04552     docViewerPrint->OnDonePrinting();
04553   }
04554 }
04555 
04556 //------------------------------------------------------------------------
04557 void PR_CALLBACK DestroyPLEvent(PLEvent* aEvent)
04558 {
04559   nsIDocumentViewerPrint *docViewerPrint = (nsIDocumentViewerPrint*)PL_GetEventOwner(aEvent);
04560   NS_IF_RELEASE(docViewerPrint);
04561 
04562   delete aEvent;
04563 }
04564 //-----------------------------------------------------------
04565 void
04566 nsPrintEngine::FirePrintCompletionEvent()
04567 {
04568   static NS_DEFINE_CID(kEventQueueServiceCID, NS_EVENTQUEUESERVICE_CID);
04569 
04570   nsCOMPtr<nsIEventQueueService> event_service = do_GetService(kEventQueueServiceCID);
04571 
04572   if (!event_service) 
04573   {
04574     NS_WARNING("Failed to get event queue service");
04575     return;
04576   }
04577 
04578   nsCOMPtr<nsIEventQueue> event_queue;
04579 
04580   event_service->GetThreadEventQueue(NS_CURRENT_THREAD,
04581                                      getter_AddRefs(event_queue));
04582 
04583   if (!event_queue) 
04584   {
04585     NS_WARNING("Failed to get event queue from service");
04586     return;
04587   }
04588 
04589   PLEvent *event = new PLEvent;
04590 
04591   if (!event) 
04592   {
04593     NS_WARNING("Out of memory?");
04594     return;
04595   }
04596 
04597   PL_InitEvent(event, mDocViewerPrint, (PLHandleEventProc)::HandlePLEvent, (PLDestroyEventProc)::DestroyPLEvent);
04598 
04599   // The event owns the docviewer pointer now.
04600   NS_ADDREF(mDocViewerPrint);
04601 
04602   event_queue->PostEvent(event);
04603   return;
04604 }
04605 
04606 //---------------------------------------------------------------
04607 //---------------------------------------------------------------
04608 //-- Debug helper routines
04609 //---------------------------------------------------------------
04610 //---------------------------------------------------------------
04611 #if (defined(XP_WIN) || defined(XP_OS2)) && defined(EXTENDED_DEBUG_PRINTING)
04612 #include "windows.h"
04613 #include "process.h"
04614 #include "direct.h"
04615 
04616 #define MY_FINDFIRST(a,b) FindFirstFile(a,b)
04617 #define MY_FINDNEXT(a,b) FindNextFile(a,b)
04618 #define ISDIR(a) (a.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
04619 #define MY_FINDCLOSE(a) FindClose(a)
04620 #define MY_FILENAME(a) a.cFileName
04621 #define MY_FILESIZE(a) (a.nFileSizeHigh * MAXDWORD) + a.nFileSizeLow
04622 
04623 int RemoveFilesInDir(const char * aDir)
04624 {
04625        WIN32_FIND_DATA data_ptr;
04626        HANDLE find_handle;
04627 
04628   char path[MAX_PATH];
04629 
04630   strcpy(path, aDir);
04631 
04632        // Append slash to the end of the directory names if not there
04633        if (path[strlen(path)-1] != '\\')
04634     strcat(path, "\\");
04635 
04636   char findPath[MAX_PATH];
04637   strcpy(findPath, path);
04638   strcat(findPath, "*.*");
04639 
04640        find_handle = MY_FINDFIRST(findPath, &data_ptr);
04641 
04642        if (find_handle != INVALID_HANDLE_VALUE) {
04643               do  {
04644                      if (ISDIR(data_ptr)
04645                             && (stricmp(MY_FILENAME(data_ptr),"."))
04646                             && (stricmp(MY_FILENAME(data_ptr),".."))) {
04647                                    // skip
04648                      }
04649                      else if (!ISDIR(data_ptr)) {
04650         if (!strncmp(MY_FILENAME(data_ptr), "print_dump", 10)) {
04651           char fileName[MAX_PATH];
04652           strcpy(fileName, aDir);
04653           strcat(fileName, "\\");
04654           strcat(fileName, MY_FILENAME(data_ptr));
04655                               printf("Removing %s\n", fileName);
04656           remove(fileName);
04657         }
04658                      }
04659               } while(MY_FINDNEXT(find_handle,&data_ptr));
04660               MY_FINDCLOSE(find_handle);
04661        }
04662        return TRUE;
04663 }
04664 #endif
04665 
04666 #ifdef EXTENDED_DEBUG_PRINTING
04667 
04671 static void RootFrameList(nsPresContext* aPresContext, FILE* out, PRInt32 aIndent)
04672 {
04673   if (!aPresContext || !out)
04674     return;
04675 
04676   nsIPresShell *shell = aPresContext->GetPresShell();
04677   if (shell) {
04678     nsIFrame* frame = shell->FrameManager()->GetRootFrame();
04679     if (frame) {
04680       nsIFrameDebug* debugFrame;
04681       nsresult rv = CallQueryInterface(frame, &debugFrame);
04682       if (NS_SUCCEEDED(rv))
04683         debugFrame->List(aPresContext, out, aIndent);
04684     }
04685   }
04686 }
04687 
04691 static void DumpFrames(FILE*                 out,
04692                        nsPresContext*       aPresContext,
04693                        nsIRenderingContext * aRendContext,
04694                        nsIFrame *            aFrame,
04695                        PRInt32               aLevel)
04696 {
04697   NS_ASSERTION(out, "Pointer is null!");
04698   NS_ASSERTION(aPresContext, "Pointer is null!");
04699   NS_ASSERTION(aRendContext, "Pointer is null!");
04700   NS_ASSERTION(aFrame, "Pointer is null!");
04701 
04702   nsIFrame* child = aFrame->GetFirstChild(nsnull);
04703   while (child != nsnull) {
04704     for (PRInt32 i=0;i<aLevel;i++) {
04705      fprintf(out, "  ");
04706     }
04707     nsAutoString tmp;
04708     nsIFrameDebug*  frameDebug;
04709 
04710     if (NS_SUCCEEDED(CallQueryInterface(child, &frameDebug))) {
04711       frameDebug->GetFrameName(tmp);
04712     }
04713     fputs(NS_LossyConvertUCS2toASCII(tmp).get(), out);
04714     PRBool isSelected;
04715     if (NS_SUCCEEDED(child->IsVisibleForPainting(aPresContext, *aRendContext, PR_TRUE, &isSelected))) {
04716       fprintf(out, " %p %s", child, isSelected?"VIS":"UVS");
04717       nsRect rect = child->GetRect();
04718       fprintf(out, "[%d,%d,%d,%d] ", rect.x, rect.y, rect.width, rect.height);
04719       fprintf(out, "v: %p ", (void*)child->GetView());
04720       fprintf(out, "\n");
04721       DumpFrames(out, aPresContext, aRendContext, child, aLevel+1);
04722       child = child->GetNextSibling();
04723     }
04724   }
04725 }
04726 
04727 
04731 static void
04732 DumpViews(nsIDocShell* aDocShell, FILE* out)
04733 {
04734   NS_ASSERTION(aDocShell, "Pointer is null!");
04735   NS_ASSERTION(out, "Pointer is null!");
04736 
04737   if (nsnull != aDocShell) {
04738     fprintf(out, "docshell=%p \n", aDocShell);
04739     nsIPresShell* shell = nsPrintEngine::GetPresShellFor(aDocShell);
04740     if (shell) {
04741       nsIViewManager* vm = shell->GetViewManager();
04742       if (vm) {
04743         nsIView* root;
04744         vm->GetRootView(root);
04745         if (nsnull != root) {
04746           root->List(out);
04747         }
04748       }
04749     }
04750     else {
04751       fputs("null pres shell\n", out);
04752     }
04753 
04754     // dump the views of the sub documents
04755     PRInt32 i, n;
04756     nsCOMPtr<nsIDocShellTreeNode> docShellAsNode(do_QueryInterface(aDocShell));
04757     docShellAsNode->GetChildCount(&n);
04758     for (i = 0; i < n; i++) {
04759       nsCOMPtr<nsIDocShellTreeItem> child;
04760       docShellAsNode->GetChildAt(i, getter_AddRefs(child));
04761       nsCOMPtr<nsIDocShell> childAsShell(do_QueryInterface(child));
04762       if (childAsShell) {
04763         DumpViews(childAsShell, out);
04764       }
04765     }
04766   }
04767 }
04768 
04772 void DumpLayoutData(char*              aTitleStr,
04773                     char*              aURLStr,
04774                     nsPresContext*    aPresContext,
04775                     nsIDeviceContext * aDC,
04776                     nsIFrame *         aRootFrame,
04777                     nsIDocShekk *      aDocShell,
04778                     FILE*              aFD = nsnull)
04779 {
04780   if (!kPrintingLogMod || kPrintingLogMod->level != DUMP_LAYOUT_LEVEL) return;
04781 
04782   if (aPresContext == nsnull || aDC == nsnull) {
04783     return;
04784   }
04785 
04786 #ifdef NS_PRINT_PREVIEW
04787   if (aPresContext->Type() == nsPresContext::eContext_PrintPreview) {
04788     return;
04789   }
04790 #endif
04791 
04792   NS_ASSERTION(aRootFrame, "Pointer is null!");
04793   NS_ASSERTION(aDocShell, "Pointer is null!");
04794 
04795   // Dump all the frames and view to a a file
04796   char filename[256];
04797   sprintf(filename, "print_dump_layout_%d.txt", gDumpLOFileNameCnt++);
04798   FILE * fd = aFD?aFD:fopen(filename, "w");
04799   if (fd) {
04800     fprintf(fd, "Title: %s\n", aTitleStr?aTitleStr:"");
04801     fprintf(fd, "URL:   %s\n", aURLStr?aURLStr:"");
04802     fprintf(fd, "--------------- Frames ----------------\n");
04803     fprintf(fd, "--------------- Frames ----------------\n");
04804     nsCOMPtr<nsIRenderingContext> renderingContext;
04805     aDC->CreateRenderingContext(*getter_AddRefs(renderingContext));
04806     RootFrameList(aPresContext, fd, 0);
04807     //DumpFrames(fd, aPresContext, renderingContext, aRootFrame, 0);
04808     fprintf(fd, "---------------------------------------\n\n");
04809     fprintf(fd, "--------------- Views From Root Frame----------------\n");
04810     nsIView* v = aRootFrame->GetView();
04811     if (v) {
04812       v->List(fd);
04813     } else {
04814       printf("View is null!\n");
04815     }
04816     if (aDocShell) {
04817       fprintf(fd, "--------------- All Views ----------------\n");
04818       DumpViews(aDocShell, fd);
04819       fprintf(fd, "---------------------------------------\n\n");
04820     }
04821     if (aFD == nsnull) {
04822       fclose(fd);
04823     }
04824   }
04825 }
04826 
04827 //-------------------------------------------------------------
04828 static void DumpPrintObjectsList(nsVoidArray * aDocList)
04829 {
04830   if (!kPrintingLogMod || kPrintingLogMod->level != DUMP_LAYOUT_LEVEL) return;
04831 
04832   NS_ASSERTION(aDocList, "Pointer is null!");
04833 
04834   const char types[][3] = {"DC", "FR", "IF", "FS"};
04835   PR_PL(("Doc List\n***************************************************\n"));
04836   PR_PL(("T  P A H    PO    DocShell   Seq     Page      Root     Page#    Rect\n"));
04837   PRInt32 cnt = aDocList->Count();
04838   for (PRInt32 i=0;i<cnt;i++) {
04839     nsPrintObject* po = (nsPrintObject*)aDocList->ElementAt(i);
04840     NS_ASSERTION(po, "nsPrintObject can't be null!");
04841     nsIFrame* rootFrame = nsnull;
04842     if (po->mPresShell) {
04843       rootFrame = po->mPresShell->FrameManager()->GetRootFrame();
04844       while (rootFrame != nsnull) {
04845         nsIPageSequenceFrame * sqf = nsnull;
04846         if (NS_SUCCEEDED(CallQueryInterface(rootFrame, &sqf))) {
04847           break;
04848         }
04849         rootFrame = rootFrame->GetFirstChild(nsnull);
04850       }
04851     }
04852 
04853     PR_PL(("%s %d %d %d %p %p %p %p %p   %d   %d,%d,%d,%d\n", types[po->mFrameType],
04854             po->IsPrintable(), po->mPrintAsIs, po->mHasBeenPrinted, po, po->mDocShell.get(), po->mSeqFrame,
04855             po->mPageFrame, rootFrame, po->mPageNum, po->mRect.x, po->mRect.y, po->mRect.width, po->mRect.height));
04856   }
04857 }
04858 
04859 //-------------------------------------------------------------
04860 static void DumpPrintObjectsTree(nsPrintObject * aPO, int aLevel, FILE* aFD)
04861 {
04862   if (!kPrintingLogMod || kPrintingLogMod->level != DUMP_LAYOUT_LEVEL) return;
04863 
04864   NS_ASSERTION(aPO, "Pointer is null!");
04865 
04866   FILE * fd = aFD?aFD:stdout;
04867   const char types[][3] = {"DC", "FR", "IF", "FS"};
04868   if (aLevel == 0) {
04869     fprintf(fd, "DocTree\n***************************************************\n");
04870     fprintf(fd, "T     PO    DocShell   Seq      Page     Page#    Rect\n");
04871   }
04872   PRInt32 cnt = aPO->mKids.Count();
04873   for (PRInt32 i=0;i<cnt;i++) {
04874     nsPrintObject* po = (nsPrintObject*)aPO->mKids.ElementAt(i);
04875     NS_ASSERTION(po, "nsPrintObject can't be null!");
04876     for (PRInt32 k=0;k<aLevel;k++) fprintf(fd, "  ");
04877     fprintf(fd, "%s %p %p %p %p %d %d,%d,%d,%d\n", types[po->mFrameType], po, po->mDocShell.get(), po->mSeqFrame,
04878            po->mPageFrame, po->mPageNum, po->mRect.x, po->mRect.y, po->mRect.width, po->mRect.height);
04879   }
04880 }
04881 
04882 //-------------------------------------------------------------
04883 static void GetDocTitleAndURL(nsPrintObject* aPO, char *& aDocStr, char *& aURLStr)
04884 {
04885   aDocStr = nsnull;
04886   aURLStr = nsnull;
04887 
04888   PRUnichar * mozillaDoc = ToNewUnicode(NS_LITERAL_STRING("Mozilla Document"));
04889   PRUnichar * docTitleStr;
04890   PRUnichar * docURLStr;
04891   nsPrintEngine::GetDisplayTitleAndURL(aPO, nsnull, mozillaDoc,
04892                                             &docTitleStr, &docURLStr,
04893                                             nsPrintEngine::eDocTitleDefURLDoc); 
04894 
04895   if (docTitleStr) {
04896     nsAutoString strDocTitle(docTitleStr);
04897     aDocStr = ToNewCString(strDocTitle);
04898     nsMemory::Free(docTitleStr);
04899   }
04900 
04901   if (docURLStr) {
04902     nsAutoString strURL(docURLStr);
04903     aURLStr = ToNewCString(strURL);
04904     nsMemory::Free(docURLStr);
04905   }
04906 
04907   if (mozillaDoc) {
04908     nsMemory::Free(mozillaDoc);
04909   }
04910 }
04911 
04912 //-------------------------------------------------------------
04913 static void DumpPrintObjectsTreeLayout(nsPrintObject * aPO,
04914                                        nsIDeviceContext * aDC,
04915                                        int aLevel, FILE * aFD)
04916 {
04917   if (!kPrintingLogMod || kPrintingLogMod->level != DUMP_LAYOUT_LEVEL) return;
04918 
04919   NS_ASSERTION(aPO, "Pointer is null!");
04920   NS_ASSERTION(aDC, "Pointer is null!");
04921 
04922   const char types[][3] = {"DC", "FR", "IF", "FS"};
04923   FILE * fd = nsnull;
04924   if (aLevel == 0) {
04925     fd = fopen("tree_layout.txt", "w");
04926     fprintf(fd, "DocTree\n***************************************************\n");
04927     fprintf(fd, "***************************************************\n");
04928     fprintf(fd, "T     PO    DocShell   Seq      Page     Page#    Rect\n");
04929   } else {
04930     fd = aFD;
04931   }
04932   if (fd) {
04933     nsIFrame* rootFrame = nsnull;
04934     if (aPO->mPresShell) {
04935       rootFrame = aPO->mPresShell->FrameManager()->GetRootFrame();
04936     }
04937     for (PRInt32 k=0;k<aLevel;k++) fprintf(fd, "  ");
04938     fprintf(fd, "%s %p %p %p %p %d %d,%d,%d,%d\n", types[aPO->mFrameType], aPO, aPO->mDocShell.get(), aPO->mSeqFrame,
04939            aPO->mPageFrame, aPO->mPageNum, aPO->mRect.x, aPO->mRect.y, aPO->mRect.width, aPO->mRect.height);
04940     if (aPO->IsPrintable()) {
04941       char * docStr;
04942       char * urlStr;
04943       GetDocTitleAndURL(aPO, docStr, urlStr);
04944       DumpLayoutData(docStr, urlStr, aPO->mPresContext, aDC, rootFrame, aPO->mDocShell, fd);
04945       if (docStr) nsMemory::Free(docStr);
04946       if (urlStr) nsMemory::Free(urlStr);
04947     }
04948     fprintf(fd, "<***************************************************>\n");
04949 
04950     PRInt32 cnt = aPO->mKids.Count();
04951     for (PRInt32 i=0;i<cnt;i++) {
04952       nsPrintObject* po = (nsPrintObject*)aPO->mKids.ElementAt(i);
04953       NS_ASSERTION(po, "nsPrintObject can't be null!");
04954       DumpPrintObjectsTreeLayout(po, aDC, aLevel+1, fd);
04955     }
04956   }
04957   if (aLevel == 0 && fd) {
04958     fclose(fd);
04959   }
04960 }
04961 
04962 //-------------------------------------------------------------
04963 static void DumpPrintObjectsListStart(const char * aStr, nsVoidArray * aDocList)
04964 {
04965   if (!kPrintingLogMod || kPrintingLogMod->level != DUMP_LAYOUT_LEVEL) return;
04966 
04967   NS_ASSERTION(aStr, "Pointer is null!");
04968   NS_ASSERTION(aDocList, "Pointer is null!");
04969 
04970   PR_PL(("%s\n", aStr));
04971   DumpPrintObjectsList(aDocList);
04972 }
04973 
04974 #define DUMP_DOC_LIST(_title) DumpPrintObjectsListStart((_title), mPrt->mPrintDocList);
04975 #define DUMP_DOC_TREE DumpPrintObjectsTree(mPrt->mPrintObject);
04976 #define DUMP_DOC_TREELAYOUT DumpPrintObjectsTreeLayout(mPrt->mPrintObject, mPrt->mPrintDC);
04977 
04978 #else
04979 #define DUMP_DOC_LIST(_title)
04980 #define DUMP_DOC_TREE
04981 #define DUMP_DOC_TREELAYOUT
04982 #endif
04983 
04984 #ifdef MOZ_LAYOUTDEBUG
04985 nsCOMPtr<nsIDebugObject> nsPrintEngine::mLayoutDebugObj;
04986 
04987 PRBool nsPrintEngine::mIsDoingRuntimeTesting = PR_FALSE;
04988 
04989 void 
04990 nsPrintEngine::InitializeTestRuntimeError()
04991 {
04992   mIsDoingRuntimeTesting =
04993     nsContentUtils::GetBoolPref("print.doing_runtime_error_checking");
04994 
04995   mLayoutDebugObj = do_GetService("@mozilla.org/debug/debugobject;1");
04996 }
04997 
04998 PRBool 
04999 nsPrintEngine::IsDoingRuntimeTesting() 
05000 { 
05001   PRBool isDoingTests = PR_FALSE;
05002   if (mLayoutDebugObj) {
05003     mLayoutDebugObj->GetDoRuntimeTests(&isDoingTests);
05004   }
05005   return isDoingTests;
05006 }
05007 
05008 nsresult 
05009 nsPrintEngine::TestRuntimeErrorCondition(PRInt16  aRuntimeID, 
05010                                          nsresult aCurrentErrorCode, 
05011                                          nsresult aNewErrorCode)
05012 {
05013   PRInt16 id;
05014   if (mLayoutDebugObj) {
05015     if (NS_SUCCEEDED(mLayoutDebugObj->GetTestId(&id))) {
05016       if (id == aRuntimeID) {
05017         return aNewErrorCode;
05018       }
05019     }
05020   }
05021   return aCurrentErrorCode;
05022 }
05023 #endif
05024 
05025 //---------------------------------------------------------------
05026 //---------------------------------------------------------------
05027 //-- End of debug helper routines
05028 //---------------------------------------------------------------