michael@0: /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ michael@0: /* This Source Code Form is subject to the terms of the Mozilla Public michael@0: * License, v. 2.0. If a copy of the MPL was not distributed with this michael@0: * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ michael@0: michael@0: #include "nsPrintEngine.h" michael@0: michael@0: #include "nsIStringBundle.h" michael@0: #include "nsReadableUtils.h" michael@0: #include "nsCRT.h" michael@0: michael@0: #include "mozilla/AsyncEventDispatcher.h" michael@0: #include "mozilla/dom/Selection.h" michael@0: #include "nsIScriptGlobalObject.h" michael@0: #include "nsPIDOMWindow.h" michael@0: #include "nsIDocShell.h" michael@0: #include "nsIFrame.h" michael@0: #include "nsIURI.h" michael@0: #include "nsITextToSubURI.h" michael@0: #include "nsError.h" michael@0: michael@0: #include "nsView.h" michael@0: #include michael@0: michael@0: // Print Options michael@0: #include "nsIPrintSettings.h" michael@0: #include "nsIPrintSettingsService.h" michael@0: #include "nsIPrintOptions.h" michael@0: #include "nsIPrintSession.h" michael@0: #include "nsGfxCIID.h" michael@0: #include "nsIServiceManager.h" michael@0: #include "nsGkAtoms.h" michael@0: #include "nsXPCOM.h" michael@0: #include "nsISupportsPrimitives.h" michael@0: michael@0: static const char sPrintSettingsServiceContractID[] = "@mozilla.org/gfx/printsettings-service;1"; michael@0: michael@0: // Printing Events michael@0: #include "nsPrintPreviewListener.h" michael@0: #include "nsThreadUtils.h" michael@0: michael@0: // Printing michael@0: #include "nsIWebBrowserPrint.h" michael@0: #include "nsIDOMHTMLFrameElement.h" michael@0: #include "nsIDOMHTMLFrameSetElement.h" michael@0: #include "nsIDOMHTMLIFrameElement.h" michael@0: #include "nsIDOMHTMLObjectElement.h" michael@0: #include "nsIDOMHTMLEmbedElement.h" michael@0: michael@0: // Print Preview michael@0: #include "imgIContainer.h" // image animation mode constants michael@0: #include "nsIWebBrowserPrint.h" // needed for PrintPreview Navigation constants michael@0: michael@0: // Print Progress michael@0: #include "nsIPrintProgress.h" michael@0: #include "nsIPrintProgressParams.h" michael@0: #include "nsIObserver.h" michael@0: michael@0: // Print error dialog michael@0: #include "nsIPrompt.h" michael@0: #include "nsIWindowWatcher.h" michael@0: michael@0: // Printing Prompts michael@0: #include "nsIPrintingPromptService.h" michael@0: static const char kPrintingPromptService[] = "@mozilla.org/embedcomp/printingprompt-service;1"; michael@0: michael@0: // Printing Timer michael@0: #include "nsPagePrintTimer.h" michael@0: michael@0: // FrameSet michael@0: #include "nsIDocument.h" michael@0: michael@0: // Focus michael@0: #include "nsISelectionController.h" michael@0: michael@0: // Misc michael@0: #include "nsISupportsUtils.h" michael@0: #include "nsIScriptContext.h" michael@0: #include "nsIDOMDocument.h" michael@0: #include "nsISelectionListener.h" michael@0: #include "nsISelectionPrivate.h" michael@0: #include "nsIDOMRange.h" michael@0: #include "nsContentCID.h" michael@0: #include "nsLayoutCID.h" michael@0: #include "nsContentUtils.h" michael@0: #include "nsIPresShell.h" michael@0: #include "nsLayoutUtils.h" michael@0: #include "mozilla/Preferences.h" michael@0: michael@0: #include "nsWidgetsCID.h" michael@0: #include "nsIDeviceContextSpec.h" michael@0: #include "nsViewManager.h" michael@0: #include "nsView.h" michael@0: #include "nsRenderingContext.h" michael@0: michael@0: #include "nsIPageSequenceFrame.h" michael@0: #include "nsIURL.h" michael@0: #include "nsIContentViewerEdit.h" michael@0: #include "nsIContentViewerFile.h" michael@0: #include "nsIMarkupDocumentViewer.h" michael@0: #include "nsIInterfaceRequestor.h" michael@0: #include "nsIInterfaceRequestorUtils.h" michael@0: #include "nsIDocShellTreeOwner.h" michael@0: #include "nsIWebBrowserChrome.h" michael@0: #include "nsIBaseWindow.h" michael@0: #include "nsILayoutHistoryState.h" michael@0: #include "nsFrameManager.h" michael@0: #include "nsHTMLReflowState.h" michael@0: #include "nsIDOMHTMLAnchorElement.h" michael@0: #include "nsIDOMHTMLAreaElement.h" michael@0: #include "nsIDOMHTMLLinkElement.h" michael@0: #include "nsIDOMHTMLImageElement.h" michael@0: #include "nsIContentViewerContainer.h" michael@0: #include "nsIContentViewer.h" michael@0: #include "nsIDocumentViewerPrint.h" michael@0: michael@0: #include "nsFocusManager.h" michael@0: #include "nsRange.h" michael@0: #include "nsCDefaultURIFixup.h" michael@0: #include "nsIURIFixup.h" michael@0: #include "mozilla/dom/Element.h" michael@0: #include "nsContentList.h" michael@0: #include "nsIChannel.h" michael@0: #include "xpcpublic.h" michael@0: michael@0: using namespace mozilla; michael@0: using namespace mozilla::dom; michael@0: michael@0: //----------------------------------------------------- michael@0: // PR LOGGING michael@0: #ifdef MOZ_LOGGING michael@0: #define FORCE_PR_LOG /* Allow logging in the release build */ michael@0: #endif michael@0: michael@0: #include "prlog.h" michael@0: michael@0: #ifdef PR_LOGGING michael@0: michael@0: #ifdef DEBUG michael@0: // PR_LOGGING is force to always be on (even in release builds) michael@0: // but we only want some of it on, michael@0: //#define EXTENDED_DEBUG_PRINTING michael@0: #endif michael@0: michael@0: #define DUMP_LAYOUT_LEVEL 9 // this turns on the dumping of each doucment's layout info michael@0: michael@0: #ifndef PR_PL michael@0: static PRLogModuleInfo * michael@0: GetPrintingLog() michael@0: { michael@0: static PRLogModuleInfo *sLog; michael@0: if (!sLog) michael@0: sLog = PR_NewLogModule("printing"); michael@0: return sLog; michael@0: } michael@0: #define PR_PL(_p1) PR_LOG(GetPrintingLog(), PR_LOG_DEBUG, _p1); michael@0: #endif michael@0: michael@0: #ifdef EXTENDED_DEBUG_PRINTING michael@0: static uint32_t gDumpFileNameCnt = 0; michael@0: static uint32_t gDumpLOFileNameCnt = 0; michael@0: #endif michael@0: michael@0: #define PRT_YESNO(_p) ((_p)?"YES":"NO") michael@0: static const char * gFrameTypesStr[] = {"eDoc", "eFrame", "eIFrame", "eFrameSet"}; michael@0: static const char * gPrintFrameTypeStr[] = {"kNoFrames", "kFramesAsIs", "kSelectedFrame", "kEachFrameSep"}; michael@0: static const char * gFrameHowToEnableStr[] = {"kFrameEnableNone", "kFrameEnableAll", "kFrameEnableAsIsAndEach"}; michael@0: static const char * gPrintRangeStr[] = {"kRangeAllPages", "kRangeSpecifiedPageRange", "kRangeSelection", "kRangeFocusFrame"}; michael@0: #else michael@0: #define PRT_YESNO(_p) michael@0: #define PR_PL(_p1) michael@0: #endif michael@0: michael@0: #ifdef EXTENDED_DEBUG_PRINTING michael@0: // Forward Declarations michael@0: static void DumpPrintObjectsListStart(const char * aStr, nsTArray * aDocList); michael@0: static void DumpPrintObjectsTree(nsPrintObject * aPO, int aLevel= 0, FILE* aFD = nullptr); michael@0: static void DumpPrintObjectsTreeLayout(nsPrintObject * aPO,nsDeviceContext * aDC, int aLevel= 0, FILE * aFD = nullptr); michael@0: michael@0: #define DUMP_DOC_LIST(_title) DumpPrintObjectsListStart((_title), mPrt->mPrintDocList); michael@0: #define DUMP_DOC_TREE DumpPrintObjectsTree(mPrt->mPrintObject); michael@0: #define DUMP_DOC_TREELAYOUT DumpPrintObjectsTreeLayout(mPrt->mPrintObject, mPrt->mPrintDC); michael@0: #else michael@0: #define DUMP_DOC_LIST(_title) michael@0: #define DUMP_DOC_TREE michael@0: #define DUMP_DOC_TREELAYOUT michael@0: #endif michael@0: michael@0: class nsScriptSuppressor michael@0: { michael@0: public: michael@0: nsScriptSuppressor(nsPrintEngine* aPrintEngine) michael@0: : mPrintEngine(aPrintEngine), mSuppressed(false) {} michael@0: michael@0: ~nsScriptSuppressor() { Unsuppress(); } michael@0: michael@0: void Suppress() michael@0: { michael@0: if (mPrintEngine) { michael@0: mSuppressed = true; michael@0: mPrintEngine->TurnScriptingOn(false); michael@0: } michael@0: } michael@0: michael@0: void Unsuppress() michael@0: { michael@0: if (mPrintEngine && mSuppressed) { michael@0: mPrintEngine->TurnScriptingOn(true); michael@0: } michael@0: mSuppressed = false; michael@0: } michael@0: michael@0: void Disconnect() { mPrintEngine = nullptr; } michael@0: protected: michael@0: nsRefPtr mPrintEngine; michael@0: bool mSuppressed; michael@0: }; michael@0: michael@0: NS_IMPL_ISUPPORTS(nsPrintEngine, nsIWebProgressListener, michael@0: nsISupportsWeakReference, nsIObserver) michael@0: michael@0: //--------------------------------------------------- michael@0: //-- nsPrintEngine Class Impl michael@0: //--------------------------------------------------- michael@0: nsPrintEngine::nsPrintEngine() : michael@0: mIsCreatingPrintPreview(false), michael@0: mIsDoingPrinting(false), michael@0: mIsDoingPrintPreview(false), michael@0: mProgressDialogIsShown(false), michael@0: mScreenDPI(115.0f), michael@0: mPrt(nullptr), michael@0: mPagePrintTimer(nullptr), michael@0: mPageSeqFrame(nullptr), michael@0: mPrtPreview(nullptr), michael@0: mOldPrtPreview(nullptr), michael@0: mDebugFile(nullptr), michael@0: mLoadCounter(0), michael@0: mDidLoadDataForPrinting(false), michael@0: mIsDestroying(false), michael@0: mDisallowSelectionPrint(false), michael@0: mNoMarginBoxes(false) michael@0: { michael@0: } michael@0: michael@0: //------------------------------------------------------- michael@0: nsPrintEngine::~nsPrintEngine() michael@0: { michael@0: Destroy(); // for insurance michael@0: } michael@0: michael@0: //------------------------------------------------------- michael@0: void nsPrintEngine::Destroy() michael@0: { michael@0: if (mIsDestroying) { michael@0: return; michael@0: } michael@0: mIsDestroying = true; michael@0: michael@0: if (mPrt) { michael@0: delete mPrt; michael@0: mPrt = nullptr; michael@0: } michael@0: michael@0: #ifdef NS_PRINT_PREVIEW michael@0: if (mPrtPreview) { michael@0: delete mPrtPreview; michael@0: mPrtPreview = nullptr; michael@0: } michael@0: michael@0: // This is insruance michael@0: if (mOldPrtPreview) { michael@0: delete mOldPrtPreview; michael@0: mOldPrtPreview = nullptr; michael@0: } michael@0: michael@0: #endif michael@0: mDocViewerPrint = nullptr; michael@0: } michael@0: michael@0: //------------------------------------------------------- michael@0: void nsPrintEngine::DestroyPrintingData() michael@0: { michael@0: if (mPrt) { michael@0: nsPrintData* data = mPrt; michael@0: mPrt = nullptr; michael@0: delete data; michael@0: } michael@0: } michael@0: michael@0: //--------------------------------------------------------------------------------- michael@0: //-- Section: Methods needed by the DocViewer michael@0: //--------------------------------------------------------------------------------- michael@0: michael@0: //-------------------------------------------------------- michael@0: nsresult nsPrintEngine::Initialize(nsIDocumentViewerPrint* aDocViewerPrint, michael@0: nsIDocShell* aContainer, michael@0: nsIDocument* aDocument, michael@0: float aScreenDPI, michael@0: FILE* aDebugFile) michael@0: { michael@0: NS_ENSURE_ARG_POINTER(aDocViewerPrint); michael@0: NS_ENSURE_ARG_POINTER(aContainer); michael@0: NS_ENSURE_ARG_POINTER(aDocument); michael@0: michael@0: mDocViewerPrint = aDocViewerPrint; michael@0: mContainer = do_GetWeakReference(aContainer); michael@0: mDocument = aDocument; michael@0: mScreenDPI = aScreenDPI; michael@0: michael@0: mDebugFile = aDebugFile; // ok to be nullptr michael@0: michael@0: return NS_OK; michael@0: } michael@0: michael@0: //------------------------------------------------------- michael@0: bool michael@0: nsPrintEngine::CheckBeforeDestroy() michael@0: { michael@0: if (mPrt && mPrt->mPreparingForPrint) { michael@0: mPrt->mDocWasToBeDestroyed = true; michael@0: return true; michael@0: } michael@0: return false; michael@0: } michael@0: michael@0: //------------------------------------------------------- michael@0: nsresult michael@0: nsPrintEngine::Cancelled() michael@0: { michael@0: if (mPrt && mPrt->mPrintSettings) { michael@0: return mPrt->mPrintSettings->SetIsCancelled(true); michael@0: } michael@0: return NS_ERROR_FAILURE; michael@0: } michael@0: michael@0: //------------------------------------------------------- michael@0: // Install our event listeners on the document to prevent michael@0: // some events from being processed while in PrintPreview michael@0: // michael@0: // No return code - if this fails, there isn't much we can do michael@0: void michael@0: nsPrintEngine::InstallPrintPreviewListener() michael@0: { michael@0: if (!mPrt->mPPEventListeners) { michael@0: nsCOMPtr docShell = do_QueryReferent(mContainer); michael@0: nsCOMPtr win(do_GetInterface(docShell)); michael@0: if (win) { michael@0: nsCOMPtr target = do_QueryInterface(win->GetFrameElementInternal()); michael@0: mPrt->mPPEventListeners = new nsPrintPreviewListener(target); michael@0: mPrt->mPPEventListeners->AddListeners(); michael@0: } michael@0: } michael@0: } michael@0: michael@0: //---------------------------------------------------------------------- michael@0: nsresult michael@0: nsPrintEngine::GetSeqFrameAndCountPagesInternal(nsPrintObject* aPO, michael@0: nsIFrame*& aSeqFrame, michael@0: int32_t& aCount) michael@0: { michael@0: NS_ENSURE_ARG_POINTER(aPO); michael@0: michael@0: // Finds the SimplePageSequencer frame michael@0: nsIPageSequenceFrame* seqFrame = aPO->mPresShell->GetPageSequenceFrame(); michael@0: aSeqFrame = do_QueryFrame(seqFrame); michael@0: if (!aSeqFrame) { michael@0: return NS_ERROR_FAILURE; michael@0: } michael@0: michael@0: // first count the total number of pages michael@0: aCount = 0; michael@0: nsIFrame* pageFrame = aSeqFrame->GetFirstPrincipalChild(); michael@0: while (pageFrame != nullptr) { michael@0: aCount++; michael@0: pageFrame = pageFrame->GetNextSibling(); michael@0: } michael@0: michael@0: return NS_OK; michael@0: michael@0: } michael@0: michael@0: //----------------------------------------------------------------- michael@0: nsresult nsPrintEngine::GetSeqFrameAndCountPages(nsIFrame*& aSeqFrame, int32_t& aCount) michael@0: { michael@0: NS_ASSERTION(mPrtPreview, "mPrtPreview can't be null!"); michael@0: return GetSeqFrameAndCountPagesInternal(mPrtPreview->mPrintObject, aSeqFrame, aCount); michael@0: } michael@0: //--------------------------------------------------------------------------------- michael@0: //-- Done: Methods needed by the DocViewer michael@0: //--------------------------------------------------------------------------------- michael@0: michael@0: michael@0: //--------------------------------------------------------------------------------- michael@0: //-- Section: nsIWebBrowserPrint michael@0: //--------------------------------------------------------------------------------- michael@0: michael@0: // Foward decl for Debug Helper Functions michael@0: #ifdef EXTENDED_DEBUG_PRINTING michael@0: static int RemoveFilesInDir(const char * aDir); michael@0: static void GetDocTitleAndURL(nsPrintObject* aPO, char *& aDocStr, char *& aURLStr); michael@0: static void DumpPrintObjectsTree(nsPrintObject * aPO, int aLevel, FILE* aFD); michael@0: static void DumpPrintObjectsList(nsTArray * aDocList); michael@0: static void RootFrameList(nsPresContext* aPresContext, FILE* out, int32_t aIndent); michael@0: static void DumpViews(nsIDocShell* aDocShell, FILE* out); michael@0: static void DumpLayoutData(char* aTitleStr, char* aURLStr, michael@0: nsPresContext* aPresContext, michael@0: nsDeviceContext * aDC, nsIFrame * aRootFrame, michael@0: nsIDocShell * aDocShell, FILE* aFD); michael@0: #endif michael@0: michael@0: //-------------------------------------------------------------------------------- michael@0: michael@0: nsresult michael@0: nsPrintEngine::CommonPrint(bool aIsPrintPreview, michael@0: nsIPrintSettings* aPrintSettings, michael@0: nsIWebProgressListener* aWebProgressListener, michael@0: nsIDOMDocument* aDoc) { michael@0: nsRefPtr kungfuDeathGrip = this; michael@0: nsresult rv = DoCommonPrint(aIsPrintPreview, aPrintSettings, michael@0: aWebProgressListener, aDoc); michael@0: if (NS_FAILED(rv)) { michael@0: if (aIsPrintPreview) { michael@0: SetIsCreatingPrintPreview(false); michael@0: SetIsPrintPreview(false); michael@0: } else { michael@0: SetIsPrinting(false); michael@0: } michael@0: if (mProgressDialogIsShown) michael@0: CloseProgressDialog(aWebProgressListener); michael@0: if (rv != NS_ERROR_ABORT && rv != NS_ERROR_OUT_OF_MEMORY) michael@0: ShowPrintErrorDialog(rv, !aIsPrintPreview); michael@0: delete mPrt; michael@0: mPrt = nullptr; michael@0: } michael@0: michael@0: return rv; michael@0: } michael@0: michael@0: nsresult michael@0: nsPrintEngine::DoCommonPrint(bool aIsPrintPreview, michael@0: nsIPrintSettings* aPrintSettings, michael@0: nsIWebProgressListener* aWebProgressListener, michael@0: nsIDOMDocument* aDoc) michael@0: { michael@0: nsresult rv; michael@0: michael@0: if (aIsPrintPreview) { michael@0: // The WebProgressListener can be QI'ed to nsIPrintingPromptService michael@0: // then that means the progress dialog is already being shown. michael@0: nsCOMPtr pps(do_QueryInterface(aWebProgressListener)); michael@0: mProgressDialogIsShown = pps != nullptr; michael@0: michael@0: if (mIsDoingPrintPreview) { michael@0: mOldPrtPreview = mPrtPreview; michael@0: mPrtPreview = nullptr; michael@0: } michael@0: } else { michael@0: mProgressDialogIsShown = false; michael@0: } michael@0: michael@0: mPrt = new nsPrintData(aIsPrintPreview ? nsPrintData::eIsPrintPreview : michael@0: nsPrintData::eIsPrinting); michael@0: NS_ENSURE_TRUE(mPrt, NS_ERROR_OUT_OF_MEMORY); michael@0: michael@0: // if they don't pass in a PrintSettings, then get the Global PS michael@0: mPrt->mPrintSettings = aPrintSettings; michael@0: if (!mPrt->mPrintSettings) { michael@0: rv = GetGlobalPrintSettings(getter_AddRefs(mPrt->mPrintSettings)); michael@0: NS_ENSURE_SUCCESS(rv, rv); michael@0: } michael@0: michael@0: rv = CheckForPrinters(mPrt->mPrintSettings); michael@0: NS_ENSURE_SUCCESS(rv, rv); michael@0: michael@0: mPrt->mPrintSettings->SetIsCancelled(false); michael@0: mPrt->mPrintSettings->GetShrinkToFit(&mPrt->mShrinkToFit); michael@0: michael@0: // In the case the margin boxes are not printed store the print settings for michael@0: // the footer/header to be used as default print setting for follow up prints. michael@0: mPrt->mPrintSettings->SetPersistMarginBoxSettings(!mNoMarginBoxes); michael@0: michael@0: if (mNoMarginBoxes) { michael@0: // Set the footer/header to blank. michael@0: const char16_t* emptyString = EmptyString().get(); michael@0: mPrt->mPrintSettings->SetHeaderStrLeft(emptyString); michael@0: mPrt->mPrintSettings->SetHeaderStrCenter(emptyString); michael@0: mPrt->mPrintSettings->SetHeaderStrRight(emptyString); michael@0: mPrt->mPrintSettings->SetFooterStrLeft(emptyString); michael@0: mPrt->mPrintSettings->SetFooterStrCenter(emptyString); michael@0: mPrt->mPrintSettings->SetFooterStrRight(emptyString); michael@0: } michael@0: michael@0: if (aIsPrintPreview) { michael@0: SetIsCreatingPrintPreview(true); michael@0: SetIsPrintPreview(true); michael@0: nsCOMPtr viewer = michael@0: do_QueryInterface(mDocViewerPrint); michael@0: if (viewer) { michael@0: viewer->SetTextZoom(1.0f); michael@0: viewer->SetFullZoom(1.0f); michael@0: viewer->SetMinFontSize(0); michael@0: } michael@0: } michael@0: michael@0: // Create a print session and let the print settings know about it. michael@0: // The print settings hold an nsWeakPtr to the session so it does not michael@0: // need to be cleared from the settings at the end of the job. michael@0: // XXX What lifetime does the printSession need to have? michael@0: nsCOMPtr printSession; michael@0: if (!aIsPrintPreview) { michael@0: printSession = do_CreateInstance("@mozilla.org/gfx/printsession;1", &rv); michael@0: NS_ENSURE_SUCCESS(rv, rv); michael@0: mPrt->mPrintSettings->SetPrintSession(printSession); michael@0: } michael@0: michael@0: if (aWebProgressListener != nullptr) { michael@0: mPrt->mPrintProgressListeners.AppendObject(aWebProgressListener); michael@0: } michael@0: michael@0: // Get the currently focused window and cache it michael@0: // because the Print Dialog will "steal" focus and later when you try michael@0: // to get the currently focused windows it will be nullptr michael@0: mPrt->mCurrentFocusWin = FindFocusedDOMWindow(); michael@0: michael@0: // Check to see if there is a "regular" selection michael@0: bool isSelection = IsThereARangeSelection(mPrt->mCurrentFocusWin); michael@0: michael@0: // Get the docshell for this documentviewer michael@0: nsCOMPtr webContainer(do_QueryReferent(mContainer, &rv)); michael@0: NS_ENSURE_SUCCESS(rv, rv); michael@0: michael@0: { michael@0: if (aIsPrintPreview) { michael@0: nsCOMPtr viewer; michael@0: webContainer->GetContentViewer(getter_AddRefs(viewer)); michael@0: if (viewer && viewer->GetDocument() && viewer->GetDocument()->IsShowing()) { michael@0: viewer->GetDocument()->OnPageHide(false, nullptr); michael@0: } michael@0: } michael@0: michael@0: nsAutoScriptBlocker scriptBlocker; michael@0: mPrt->mPrintObject = new nsPrintObject(); michael@0: NS_ENSURE_TRUE(mPrt->mPrintObject, NS_ERROR_OUT_OF_MEMORY); michael@0: rv = mPrt->mPrintObject->Init(webContainer, aDoc, aIsPrintPreview); michael@0: NS_ENSURE_SUCCESS(rv, rv); michael@0: michael@0: NS_ENSURE_TRUE(mPrt->mPrintDocList.AppendElement(mPrt->mPrintObject), michael@0: NS_ERROR_OUT_OF_MEMORY); michael@0: michael@0: mPrt->mIsParentAFrameSet = IsParentAFrameSet(webContainer); michael@0: mPrt->mPrintObject->mFrameType = mPrt->mIsParentAFrameSet ? eFrameSet : eDoc; michael@0: michael@0: // Build the "tree" of PrintObjects michael@0: BuildDocTree(mPrt->mPrintObject->mDocShell, &mPrt->mPrintDocList, michael@0: mPrt->mPrintObject); michael@0: } michael@0: michael@0: if (!aIsPrintPreview) { michael@0: SetIsPrinting(true); michael@0: } michael@0: michael@0: // XXX This isn't really correct... michael@0: if (!mPrt->mPrintObject->mDocument || michael@0: !mPrt->mPrintObject->mDocument->GetRootElement()) michael@0: return NS_ERROR_GFX_PRINTER_STARTDOC; michael@0: michael@0: // Create the linkage from the sub-docs back to the content element michael@0: // in the parent document michael@0: MapContentToWebShells(mPrt->mPrintObject, mPrt->mPrintObject); michael@0: michael@0: mPrt->mIsIFrameSelected = IsThereAnIFrameSelected(webContainer, mPrt->mCurrentFocusWin, mPrt->mIsParentAFrameSet); michael@0: michael@0: // Setup print options for UI michael@0: if (mPrt->mIsParentAFrameSet) { michael@0: if (mPrt->mCurrentFocusWin) { michael@0: mPrt->mPrintSettings->SetHowToEnableFrameUI(nsIPrintSettings::kFrameEnableAll); michael@0: } else { michael@0: mPrt->mPrintSettings->SetHowToEnableFrameUI(nsIPrintSettings::kFrameEnableAsIsAndEach); michael@0: } michael@0: } else { michael@0: mPrt->mPrintSettings->SetHowToEnableFrameUI(nsIPrintSettings::kFrameEnableNone); michael@0: } michael@0: // Now determine how to set up the Frame print UI michael@0: mPrt->mPrintSettings->SetPrintOptions(nsIPrintSettings::kEnableSelectionRB, michael@0: isSelection || mPrt->mIsIFrameSelected); michael@0: michael@0: nsCOMPtr devspec michael@0: (do_CreateInstance("@mozilla.org/gfx/devicecontextspec;1", &rv)); michael@0: NS_ENSURE_SUCCESS(rv, rv); michael@0: michael@0: nsScriptSuppressor scriptSuppressor(this); michael@0: if (!aIsPrintPreview) { michael@0: #ifdef DEBUG michael@0: mPrt->mDebugFilePtr = mDebugFile; michael@0: #endif michael@0: michael@0: scriptSuppressor.Suppress(); michael@0: bool printSilently; michael@0: mPrt->mPrintSettings->GetPrintSilent(&printSilently); michael@0: michael@0: // Check prefs for a default setting as to whether we should print silently michael@0: printSilently = michael@0: Preferences::GetBool("print.always_print_silent", printSilently); michael@0: michael@0: // Ask dialog to be Print Shown via the Plugable Printing Dialog Service michael@0: // This service is for the Print Dialog and the Print Progress Dialog michael@0: // If printing silently or you can't get the service continue on michael@0: if (!printSilently) { michael@0: nsCOMPtr printPromptService(do_GetService(kPrintingPromptService)); michael@0: if (printPromptService) { michael@0: nsIDOMWindow *domWin = mDocument->GetWindow(); michael@0: NS_ENSURE_TRUE(domWin, NS_ERROR_FAILURE); michael@0: michael@0: // Platforms not implementing a given dialog for the service may michael@0: // return NS_ERROR_NOT_IMPLEMENTED or an error code. michael@0: // michael@0: // NS_ERROR_NOT_IMPLEMENTED indicates they want default behavior michael@0: // Any other error code means we must bail out michael@0: // michael@0: nsCOMPtr wbp(do_QueryInterface(mDocViewerPrint)); michael@0: rv = printPromptService->ShowPrintDialog(domWin, wbp, michael@0: mPrt->mPrintSettings); michael@0: // michael@0: // ShowPrintDialog triggers an event loop which means we can't assume michael@0: // that the state of this->{anything} matches the state we've checked michael@0: // above. Including that a given {thing} is non null. michael@0: if (!mPrt) { michael@0: return NS_ERROR_FAILURE; michael@0: } michael@0: michael@0: if (NS_SUCCEEDED(rv)) { michael@0: // since we got the dialog and it worked then make sure we michael@0: // are telling GFX we want to print silent michael@0: printSilently = true; michael@0: michael@0: if (mPrt->mPrintSettings) { michael@0: // The user might have changed shrink-to-fit in the print dialog, so update our copy of its state michael@0: mPrt->mPrintSettings->GetShrinkToFit(&mPrt->mShrinkToFit); michael@0: } michael@0: } else if (rv == NS_ERROR_NOT_IMPLEMENTED) { michael@0: // This means the Dialog service was there, michael@0: // but they choose not to implement this dialog and michael@0: // are looking for default behavior from the toolkit michael@0: rv = NS_OK; michael@0: } michael@0: } else { michael@0: // No dialog service available michael@0: rv = NS_ERROR_NOT_IMPLEMENTED; michael@0: } michael@0: } else { michael@0: // Call any code that requires a run of the event loop. michael@0: rv = mPrt->mPrintSettings->SetupSilentPrinting(); michael@0: } michael@0: // Check explicitly for abort because it's expected michael@0: if (rv == NS_ERROR_ABORT) michael@0: return rv; michael@0: NS_ENSURE_SUCCESS(rv, rv); michael@0: } michael@0: michael@0: rv = devspec->Init(nullptr, mPrt->mPrintSettings, aIsPrintPreview); michael@0: NS_ENSURE_SUCCESS(rv, rv); michael@0: michael@0: mPrt->mPrintDC = new nsDeviceContext(); michael@0: rv = mPrt->mPrintDC->InitForPrinting(devspec); michael@0: NS_ENSURE_SUCCESS(rv, rv); michael@0: michael@0: if (aIsPrintPreview) { michael@0: mPrt->mPrintSettings->SetPrintFrameType(nsIPrintSettings::kFramesAsIs); michael@0: michael@0: // override any UI that wants to PrintPreview any selection or page range michael@0: // we want to view every page in PrintPreview each time michael@0: mPrt->mPrintSettings->SetPrintRange(nsIPrintSettings::kRangeAllPages); michael@0: } else { michael@0: // Always check and set the print settings first and then fall back michael@0: // onto the PrintService if there isn't a PrintSettings michael@0: // michael@0: // Posiible Usage values: michael@0: // nsIPrintSettings::kUseInternalDefault michael@0: // nsIPrintSettings::kUseSettingWhenPossible michael@0: // michael@0: // NOTE: The consts are the same for PrintSettings and PrintSettings michael@0: int16_t printFrameTypeUsage = nsIPrintSettings::kUseSettingWhenPossible; michael@0: mPrt->mPrintSettings->GetPrintFrameTypeUsage(&printFrameTypeUsage); michael@0: michael@0: // Ok, see if we are going to use our value and override the default michael@0: if (printFrameTypeUsage == nsIPrintSettings::kUseSettingWhenPossible) { michael@0: // Get the Print Options/Settings PrintFrameType to see what is preferred michael@0: int16_t printFrameType = nsIPrintSettings::kEachFrameSep; michael@0: mPrt->mPrintSettings->GetPrintFrameType(&printFrameType); michael@0: michael@0: // Don't let anybody do something stupid like try to set it to michael@0: // kNoFrames when we are printing a FrameSet michael@0: if (printFrameType == nsIPrintSettings::kNoFrames) { michael@0: mPrt->mPrintFrameType = nsIPrintSettings::kEachFrameSep; michael@0: mPrt->mPrintSettings->SetPrintFrameType(mPrt->mPrintFrameType); michael@0: } else { michael@0: // First find out from the PrinService what options are available michael@0: // to us for Printing FrameSets michael@0: int16_t howToEnableFrameUI; michael@0: mPrt->mPrintSettings->GetHowToEnableFrameUI(&howToEnableFrameUI); michael@0: if (howToEnableFrameUI != nsIPrintSettings::kFrameEnableNone) { michael@0: switch (howToEnableFrameUI) { michael@0: case nsIPrintSettings::kFrameEnableAll: michael@0: mPrt->mPrintFrameType = printFrameType; michael@0: break; michael@0: michael@0: case nsIPrintSettings::kFrameEnableAsIsAndEach: michael@0: if (printFrameType != nsIPrintSettings::kSelectedFrame) { michael@0: mPrt->mPrintFrameType = printFrameType; michael@0: } else { // revert back to a good value michael@0: mPrt->mPrintFrameType = nsIPrintSettings::kEachFrameSep; michael@0: } michael@0: break; michael@0: } // switch michael@0: mPrt->mPrintSettings->SetPrintFrameType(mPrt->mPrintFrameType); michael@0: } michael@0: } michael@0: } else { michael@0: mPrt->mPrintSettings->GetPrintFrameType(&mPrt->mPrintFrameType); michael@0: } michael@0: } michael@0: michael@0: if (mPrt->mPrintFrameType == nsIPrintSettings::kEachFrameSep) { michael@0: CheckForChildFrameSets(mPrt->mPrintObject); michael@0: } michael@0: michael@0: if (NS_FAILED(EnablePOsForPrinting())) { michael@0: return NS_ERROR_FAILURE; michael@0: } michael@0: michael@0: // Attach progressListener to catch network requests. michael@0: nsCOMPtr webProgress = do_QueryInterface(mPrt->mPrintObject->mDocShell); michael@0: webProgress->AddProgressListener( michael@0: static_cast(this), michael@0: nsIWebProgress::NOTIFY_STATE_REQUEST); michael@0: michael@0: mLoadCounter = 0; michael@0: mDidLoadDataForPrinting = false; michael@0: michael@0: if (aIsPrintPreview) { michael@0: bool notifyOnInit = false; michael@0: ShowPrintProgress(false, notifyOnInit); michael@0: michael@0: // Very important! Turn Off scripting michael@0: TurnScriptingOn(false); michael@0: michael@0: if (!notifyOnInit) { michael@0: InstallPrintPreviewListener(); michael@0: rv = InitPrintDocConstruction(false); michael@0: } else { michael@0: rv = NS_OK; michael@0: } michael@0: } else { michael@0: bool doNotify; michael@0: ShowPrintProgress(true, doNotify); michael@0: if (!doNotify) { michael@0: // Print listener setup... michael@0: mPrt->OnStartPrinting(); michael@0: michael@0: rv = InitPrintDocConstruction(false); michael@0: } michael@0: } michael@0: michael@0: // We will enable scripting later after printing has finished. michael@0: scriptSuppressor.Disconnect(); michael@0: michael@0: return NS_OK; michael@0: } michael@0: michael@0: //--------------------------------------------------------------------------------- michael@0: NS_IMETHODIMP michael@0: nsPrintEngine::Print(nsIPrintSettings* aPrintSettings, michael@0: nsIWebProgressListener* aWebProgressListener) michael@0: { michael@0: // If we have a print preview document, use that instead of the original michael@0: // mDocument. That way animated images etc. get printed using the same state michael@0: // as in print preview. michael@0: nsCOMPtr doc = michael@0: do_QueryInterface(mPrtPreview && mPrtPreview->mPrintObject ? michael@0: mPrtPreview->mPrintObject->mDocument : mDocument); michael@0: michael@0: return CommonPrint(false, aPrintSettings, aWebProgressListener, doc); michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsPrintEngine::PrintPreview(nsIPrintSettings* aPrintSettings, michael@0: nsIDOMWindow *aChildDOMWin, michael@0: nsIWebProgressListener* aWebProgressListener) michael@0: { michael@0: // Get the DocShell and see if it is busy michael@0: // (We can't Print Preview this document if it is still busy) michael@0: nsCOMPtr docShell(do_QueryReferent(mContainer)); michael@0: NS_ENSURE_STATE(docShell); michael@0: michael@0: uint32_t busyFlags = nsIDocShell::BUSY_FLAGS_NONE; michael@0: if (NS_FAILED(docShell->GetBusyFlags(&busyFlags)) || michael@0: busyFlags != nsIDocShell::BUSY_FLAGS_NONE) { michael@0: CloseProgressDialog(aWebProgressListener); michael@0: ShowPrintErrorDialog(NS_ERROR_GFX_PRINTER_DOC_IS_BUSY, false); michael@0: return NS_ERROR_FAILURE; michael@0: } michael@0: michael@0: NS_ENSURE_STATE(aChildDOMWin); michael@0: nsCOMPtr doc; michael@0: aChildDOMWin->GetDocument(getter_AddRefs(doc)); michael@0: NS_ENSURE_STATE(doc); michael@0: michael@0: // Document is not busy -- go ahead with the Print Preview michael@0: return CommonPrint(true, aPrintSettings, aWebProgressListener, doc); michael@0: } michael@0: michael@0: //---------------------------------------------------------------------------------- michael@0: /* readonly attribute boolean isFramesetDocument; */ michael@0: NS_IMETHODIMP michael@0: nsPrintEngine::GetIsFramesetDocument(bool *aIsFramesetDocument) michael@0: { michael@0: nsCOMPtr webContainer(do_QueryReferent(mContainer)); michael@0: *aIsFramesetDocument = IsParentAFrameSet(webContainer); michael@0: return NS_OK; michael@0: } michael@0: michael@0: //---------------------------------------------------------------------------------- michael@0: /* readonly attribute boolean isIFrameSelected; */ michael@0: NS_IMETHODIMP michael@0: nsPrintEngine::GetIsIFrameSelected(bool *aIsIFrameSelected) michael@0: { michael@0: *aIsIFrameSelected = false; michael@0: michael@0: // Get the docshell for this documentviewer michael@0: nsCOMPtr webContainer(do_QueryReferent(mContainer)); michael@0: // Get the currently focused window michael@0: nsCOMPtr currentFocusWin = FindFocusedDOMWindow(); michael@0: if (currentFocusWin && webContainer) { michael@0: // Get whether the doc contains a frameset michael@0: // Also, check to see if the currently focus docshell michael@0: // is a child of this docshell michael@0: bool isParentFrameSet; michael@0: *aIsIFrameSelected = IsThereAnIFrameSelected(webContainer, currentFocusWin, isParentFrameSet); michael@0: } michael@0: return NS_OK; michael@0: } michael@0: michael@0: //---------------------------------------------------------------------------------- michael@0: /* readonly attribute boolean isRangeSelection; */ michael@0: NS_IMETHODIMP michael@0: nsPrintEngine::GetIsRangeSelection(bool *aIsRangeSelection) michael@0: { michael@0: // Get the currently focused window michael@0: nsCOMPtr currentFocusWin = FindFocusedDOMWindow(); michael@0: *aIsRangeSelection = IsThereARangeSelection(currentFocusWin); michael@0: return NS_OK; michael@0: } michael@0: michael@0: //---------------------------------------------------------------------------------- michael@0: /* readonly attribute boolean isFramesetFrameSelected; */ michael@0: NS_IMETHODIMP michael@0: nsPrintEngine::GetIsFramesetFrameSelected(bool *aIsFramesetFrameSelected) michael@0: { michael@0: // Get the currently focused window michael@0: nsCOMPtr currentFocusWin = FindFocusedDOMWindow(); michael@0: *aIsFramesetFrameSelected = currentFocusWin != nullptr; michael@0: return NS_OK; michael@0: } michael@0: michael@0: //---------------------------------------------------------------------------------- michael@0: /* readonly attribute long printPreviewNumPages; */ michael@0: NS_IMETHODIMP michael@0: nsPrintEngine::GetPrintPreviewNumPages(int32_t *aPrintPreviewNumPages) michael@0: { michael@0: NS_ENSURE_ARG_POINTER(aPrintPreviewNumPages); michael@0: michael@0: nsPrintData* prt = nullptr; michael@0: nsIFrame* seqFrame = nullptr; michael@0: *aPrintPreviewNumPages = 0; michael@0: michael@0: // When calling this function, the FinishPrintPreview() function might not michael@0: // been called as there are still some michael@0: if (mPrtPreview) { michael@0: prt = mPrtPreview; michael@0: } else { michael@0: prt = mPrt; michael@0: } michael@0: if ((!prt) || michael@0: NS_FAILED(GetSeqFrameAndCountPagesInternal(prt->mPrintObject, seqFrame, *aPrintPreviewNumPages))) { michael@0: return NS_ERROR_FAILURE; michael@0: } michael@0: return NS_OK; michael@0: } michael@0: michael@0: //---------------------------------------------------------------------------------- michael@0: // Enumerate all the documents for their titles michael@0: NS_IMETHODIMP michael@0: nsPrintEngine::EnumerateDocumentNames(uint32_t* aCount, michael@0: char16_t*** aResult) michael@0: { michael@0: NS_ENSURE_ARG(aCount); michael@0: NS_ENSURE_ARG_POINTER(aResult); michael@0: michael@0: *aCount = 0; michael@0: *aResult = nullptr; michael@0: michael@0: int32_t numDocs = mPrt->mPrintDocList.Length(); michael@0: char16_t** array = (char16_t**) nsMemory::Alloc(numDocs * sizeof(char16_t*)); michael@0: if (!array) michael@0: return NS_ERROR_OUT_OF_MEMORY; michael@0: michael@0: for (int32_t i=0;imPrintDocList.ElementAt(i); michael@0: NS_ASSERTION(po, "nsPrintObject can't be null!"); michael@0: nsAutoString docTitleStr; michael@0: nsAutoString docURLStr; michael@0: GetDocumentTitleAndURL(po->mDocument, docTitleStr, docURLStr); michael@0: michael@0: // Use the URL if the doc is empty michael@0: if (docTitleStr.IsEmpty() && !docURLStr.IsEmpty()) { michael@0: docTitleStr = docURLStr; michael@0: } michael@0: array[i] = ToNewUnicode(docTitleStr); michael@0: } michael@0: *aCount = numDocs; michael@0: *aResult = array; michael@0: michael@0: return NS_OK; michael@0: michael@0: } michael@0: michael@0: //---------------------------------------------------------------------------------- michael@0: /* readonly attribute nsIPrintSettings globalPrintSettings; */ michael@0: nsresult michael@0: nsPrintEngine::GetGlobalPrintSettings(nsIPrintSettings **aGlobalPrintSettings) michael@0: { michael@0: NS_ENSURE_ARG_POINTER(aGlobalPrintSettings); michael@0: michael@0: nsresult rv = NS_ERROR_FAILURE; michael@0: nsCOMPtr printSettingsService = michael@0: do_GetService(sPrintSettingsServiceContractID, &rv); michael@0: if (NS_SUCCEEDED(rv)) { michael@0: rv = printSettingsService->GetGlobalPrintSettings(aGlobalPrintSettings); michael@0: } michael@0: return rv; michael@0: } michael@0: michael@0: //---------------------------------------------------------------------------------- michael@0: /* readonly attribute boolean doingPrint; */ michael@0: NS_IMETHODIMP michael@0: nsPrintEngine::GetDoingPrint(bool *aDoingPrint) michael@0: { michael@0: NS_ENSURE_ARG_POINTER(aDoingPrint); michael@0: *aDoingPrint = mIsDoingPrinting; michael@0: return NS_OK; michael@0: } michael@0: michael@0: //---------------------------------------------------------------------------------- michael@0: /* readonly attribute boolean doingPrintPreview; */ michael@0: NS_IMETHODIMP michael@0: nsPrintEngine::GetDoingPrintPreview(bool *aDoingPrintPreview) michael@0: { michael@0: NS_ENSURE_ARG_POINTER(aDoingPrintPreview); michael@0: *aDoingPrintPreview = mIsDoingPrintPreview; michael@0: return NS_OK; michael@0: } michael@0: michael@0: //---------------------------------------------------------------------------------- michael@0: /* readonly attribute nsIPrintSettings currentPrintSettings; */ michael@0: NS_IMETHODIMP michael@0: nsPrintEngine::GetCurrentPrintSettings(nsIPrintSettings * *aCurrentPrintSettings) michael@0: { michael@0: NS_ENSURE_ARG_POINTER(aCurrentPrintSettings); michael@0: michael@0: if (mPrt) { michael@0: *aCurrentPrintSettings = mPrt->mPrintSettings; michael@0: michael@0: } else if (mPrtPreview) { michael@0: *aCurrentPrintSettings = mPrtPreview->mPrintSettings; michael@0: michael@0: } else { michael@0: *aCurrentPrintSettings = nullptr; michael@0: } michael@0: NS_IF_ADDREF(*aCurrentPrintSettings); michael@0: return NS_OK; michael@0: } michael@0: michael@0: //----------------------------------------------------------------- michael@0: //-- Section: Pre-Reflow Methods michael@0: //----------------------------------------------------------------- michael@0: michael@0: //--------------------------------------------------------------------- michael@0: // This method checks to see if there is at least one printer defined michael@0: // and if so, it sets the first printer in the list as the default name michael@0: // in the PrintSettings which is then used for Printer Preview michael@0: nsresult michael@0: nsPrintEngine::CheckForPrinters(nsIPrintSettings* aPrintSettings) michael@0: { michael@0: #if defined(XP_MACOSX) || defined(ANDROID) michael@0: // Mac doesn't support retrieving a printer list. michael@0: return NS_OK; michael@0: #else michael@0: NS_ENSURE_ARG_POINTER(aPrintSettings); michael@0: michael@0: // See if aPrintSettings already has a printer michael@0: nsXPIDLString printerName; michael@0: nsresult rv = aPrintSettings->GetPrinterName(getter_Copies(printerName)); michael@0: if (NS_SUCCEEDED(rv) && !printerName.IsEmpty()) { michael@0: return NS_OK; michael@0: } michael@0: michael@0: // aPrintSettings doesn't have a printer set. Try to fetch the default. michael@0: nsCOMPtr printSettingsService = michael@0: do_GetService(sPrintSettingsServiceContractID, &rv); michael@0: NS_ENSURE_SUCCESS(rv, rv); michael@0: michael@0: rv = printSettingsService->GetDefaultPrinterName(getter_Copies(printerName)); michael@0: if (NS_SUCCEEDED(rv) && !printerName.IsEmpty()) { michael@0: rv = aPrintSettings->SetPrinterName(printerName.get()); michael@0: } michael@0: return rv; michael@0: #endif michael@0: } michael@0: michael@0: //---------------------------------------------------------------------- michael@0: // Set up to use the "pluggable" Print Progress Dialog michael@0: void michael@0: nsPrintEngine::ShowPrintProgress(bool aIsForPrinting, bool& aDoNotify) michael@0: { michael@0: // default to not notifying, that if something here goes wrong michael@0: // or we aren't going to show the progress dialog we can straight into michael@0: // reflowing the doc for printing. michael@0: aDoNotify = false; michael@0: michael@0: // Assume we can't do progress and then see if we can michael@0: bool showProgresssDialog = false; michael@0: michael@0: // if it is already being shown then don't bother to find out if it should be michael@0: // so skip this and leave mShowProgressDialog set to FALSE michael@0: if (!mProgressDialogIsShown) { michael@0: showProgresssDialog = Preferences::GetBool("print.show_print_progress"); michael@0: } michael@0: michael@0: // Turning off the showing of Print Progress in Prefs overrides michael@0: // whether the calling PS desire to have it on or off, so only check PS if michael@0: // prefs says it's ok to be on. michael@0: if (showProgresssDialog) { michael@0: mPrt->mPrintSettings->GetShowPrintProgress(&showProgresssDialog); michael@0: } michael@0: michael@0: // Now open the service to get the progress dialog michael@0: // If we don't get a service, that's ok, then just don't show progress michael@0: if (showProgresssDialog) { michael@0: nsCOMPtr printPromptService(do_GetService(kPrintingPromptService)); michael@0: if (printPromptService) { michael@0: nsPIDOMWindow *domWin = mDocument->GetWindow(); michael@0: if (!domWin) return; michael@0: michael@0: nsCOMPtr docShell = domWin->GetDocShell(); michael@0: if (!docShell) return; michael@0: nsCOMPtr owner; michael@0: docShell->GetTreeOwner(getter_AddRefs(owner)); michael@0: nsCOMPtr browserChrome = do_GetInterface(owner); michael@0: if (!browserChrome) return; michael@0: bool isModal = true; michael@0: browserChrome->IsWindowModal(&isModal); michael@0: if (isModal) { michael@0: // Showing a print progress dialog when printing a modal window michael@0: // isn't supported. See bug 301560. michael@0: return; michael@0: } michael@0: michael@0: nsCOMPtr printProgressListener; michael@0: michael@0: nsCOMPtr wbp(do_QueryInterface(mDocViewerPrint)); michael@0: nsresult rv = printPromptService->ShowProgress(domWin, wbp, mPrt->mPrintSettings, this, aIsForPrinting, michael@0: getter_AddRefs(printProgressListener), michael@0: getter_AddRefs(mPrt->mPrintProgressParams), michael@0: &aDoNotify); michael@0: if (NS_SUCCEEDED(rv)) { michael@0: if (printProgressListener && mPrt->mPrintProgressParams) { michael@0: mPrt->mPrintProgressListeners.AppendObject(printProgressListener); michael@0: SetDocAndURLIntoProgress(mPrt->mPrintObject, mPrt->mPrintProgressParams); michael@0: } michael@0: } michael@0: } michael@0: } michael@0: } michael@0: michael@0: //--------------------------------------------------------------------- michael@0: bool michael@0: nsPrintEngine::IsThereARangeSelection(nsIDOMWindow* aDOMWin) michael@0: { michael@0: if (mDisallowSelectionPrint) michael@0: return false; michael@0: michael@0: nsCOMPtr presShell; michael@0: if (aDOMWin) { michael@0: nsCOMPtr window(do_QueryInterface(aDOMWin)); michael@0: presShell = window->GetDocShell()->GetPresShell(); michael@0: } michael@0: michael@0: if (!presShell) michael@0: return false; michael@0: michael@0: // check here to see if there is a range selection michael@0: // so we know whether to turn on the "Selection" radio button michael@0: Selection* selection = michael@0: presShell->GetCurrentSelection(nsISelectionController::SELECTION_NORMAL); michael@0: if (!selection) { michael@0: return false; michael@0: } michael@0: michael@0: int32_t rangeCount = selection->GetRangeCount(); michael@0: if (!rangeCount) { michael@0: return false; michael@0: } michael@0: michael@0: if (rangeCount > 1) { michael@0: return true; michael@0: } michael@0: michael@0: // check to make sure it isn't an insertion selection michael@0: return selection->GetRangeAt(0) && !selection->IsCollapsed(); michael@0: } michael@0: michael@0: //--------------------------------------------------------------------- michael@0: bool michael@0: nsPrintEngine::IsParentAFrameSet(nsIDocShell * aParent) michael@0: { michael@0: // See if the incoming doc is the root document michael@0: if (!aParent) return false; michael@0: michael@0: // When it is the top level document we need to check michael@0: // to see if it contains a frameset. If it does, then michael@0: // we only want to print the doc's children and not the document itself michael@0: // For anything else we always print all the children and the document michael@0: // for example, if the doc contains an IFRAME we eant to print the child michael@0: // document (the IFRAME) and then the rest of the document. michael@0: // michael@0: // XXX we really need to search the frame tree, and not the content michael@0: // but there is no way to distinguish between IFRAMEs and FRAMEs michael@0: // with the GetFrameType call. michael@0: // Bug 53459 has been files so we can eventually distinguish michael@0: // between IFRAME frames and FRAME frames michael@0: bool isFrameSet = false; michael@0: // only check to see if there is a frameset if there is michael@0: // NO parent doc for this doc. meaning this parent is the root doc michael@0: nsCOMPtr domDoc = do_GetInterface(aParent); michael@0: nsCOMPtr doc = do_QueryInterface(domDoc); michael@0: if (doc) { michael@0: nsIContent *rootElement = doc->GetRootElement(); michael@0: if (rootElement) { michael@0: isFrameSet = HasFramesetChild(rootElement); michael@0: } michael@0: } michael@0: return isFrameSet; michael@0: } michael@0: michael@0: michael@0: //--------------------------------------------------------------------- michael@0: // Recursively build a list of sub documents to be printed michael@0: // that mirrors the document tree michael@0: void michael@0: nsPrintEngine::BuildDocTree(nsIDocShell * aParentNode, michael@0: nsTArray * aDocList, michael@0: nsPrintObject * aPO) michael@0: { michael@0: NS_ASSERTION(aParentNode, "Pointer is null!"); michael@0: NS_ASSERTION(aDocList, "Pointer is null!"); michael@0: NS_ASSERTION(aPO, "Pointer is null!"); michael@0: michael@0: int32_t childWebshellCount; michael@0: aParentNode->GetChildCount(&childWebshellCount); michael@0: if (childWebshellCount > 0) { michael@0: for (int32_t i=0;i child; michael@0: aParentNode->GetChildAt(i, getter_AddRefs(child)); michael@0: nsCOMPtr childAsShell(do_QueryInterface(child)); michael@0: michael@0: nsCOMPtr viewer; michael@0: childAsShell->GetContentViewer(getter_AddRefs(viewer)); michael@0: if (viewer) { michael@0: nsCOMPtr viewerFile(do_QueryInterface(viewer)); michael@0: if (viewerFile) { michael@0: nsCOMPtr doc = do_GetInterface(childAsShell); michael@0: nsPrintObject * po = new nsPrintObject(); michael@0: po->mParent = aPO; michael@0: nsresult rv = po->Init(childAsShell, doc, aPO->mPrintPreview); michael@0: if (NS_FAILED(rv)) michael@0: NS_NOTREACHED("Init failed?"); michael@0: aPO->mKids.AppendElement(po); michael@0: aDocList->AppendElement(po); michael@0: BuildDocTree(childAsShell, aDocList, po); michael@0: } michael@0: } michael@0: } michael@0: } michael@0: } michael@0: michael@0: //--------------------------------------------------------------------- michael@0: void michael@0: nsPrintEngine::GetDocumentTitleAndURL(nsIDocument* aDoc, michael@0: nsAString& aTitle, michael@0: nsAString& aURLStr) michael@0: { michael@0: NS_ASSERTION(aDoc, "Pointer is null!"); michael@0: michael@0: aTitle.Truncate(); michael@0: aURLStr.Truncate(); michael@0: michael@0: nsCOMPtr doc = do_QueryInterface(aDoc); michael@0: doc->GetTitle(aTitle); michael@0: michael@0: nsIURI* url = aDoc->GetDocumentURI(); michael@0: if (!url) return; michael@0: michael@0: nsCOMPtr urifixup(do_GetService(NS_URIFIXUP_CONTRACTID)); michael@0: if (!urifixup) return; michael@0: michael@0: nsCOMPtr exposableURI; michael@0: urifixup->CreateExposableURI(url, getter_AddRefs(exposableURI)); michael@0: michael@0: if (!exposableURI) return; michael@0: michael@0: nsAutoCString urlCStr; michael@0: exposableURI->GetSpec(urlCStr); michael@0: michael@0: nsresult rv; michael@0: nsCOMPtr textToSubURI = michael@0: do_GetService(NS_ITEXTTOSUBURI_CONTRACTID, &rv); michael@0: if (NS_FAILED(rv)) return; michael@0: michael@0: textToSubURI->UnEscapeURIForUI(NS_LITERAL_CSTRING("UTF-8"), michael@0: urlCStr, aURLStr); michael@0: } michael@0: michael@0: //--------------------------------------------------------------------- michael@0: // The walks the PO tree and for each document it walks the content michael@0: // tree looking for any content that are sub-shells michael@0: // michael@0: // It then sets the mContent pointer in the "found" PO object back to the michael@0: // the document that contained it. michael@0: void michael@0: nsPrintEngine::MapContentToWebShells(nsPrintObject* aRootPO, michael@0: nsPrintObject* aPO) michael@0: { michael@0: NS_ASSERTION(aRootPO, "Pointer is null!"); michael@0: NS_ASSERTION(aPO, "Pointer is null!"); michael@0: michael@0: // Recursively walk the content from the root item michael@0: // XXX Would be faster to enumerate the subdocuments, although right now michael@0: // nsIDocument doesn't expose quite what would be needed. michael@0: nsCOMPtr viewer; michael@0: aPO->mDocShell->GetContentViewer(getter_AddRefs(viewer)); michael@0: if (!viewer) return; michael@0: michael@0: nsCOMPtr domDoc; michael@0: viewer->GetDOMDocument(getter_AddRefs(domDoc)); michael@0: nsCOMPtr doc = do_QueryInterface(domDoc); michael@0: if (!doc) return; michael@0: michael@0: Element* rootElement = doc->GetRootElement(); michael@0: if (rootElement) { michael@0: MapContentForPO(aPO, rootElement); michael@0: } else { michael@0: NS_WARNING("Null root content on (sub)document."); michael@0: } michael@0: michael@0: // Continue recursively walking the chilren of this PO michael@0: for (uint32_t i=0;imKids.Length();i++) { michael@0: MapContentToWebShells(aRootPO, aPO->mKids[i]); michael@0: } michael@0: michael@0: } michael@0: michael@0: //------------------------------------------------------- michael@0: // A Frame's sub-doc may contain content or a FrameSet michael@0: // When it contains a FrameSet the mFrameType for the PrintObject michael@0: // is always set to an eFrame. Which is fine when printing "AsIs" michael@0: // but is incorrect when when printing "Each Frame Separately". michael@0: // When printing "Each Frame Separately" the Frame really acts like michael@0: // a frameset. michael@0: // michael@0: // This method walks the PO tree and checks to see if the PrintObject is michael@0: // an eFrame and has children that are eFrames (meaning it's a Frame containing a FrameSet) michael@0: // If so, then the mFrameType need to be changed to eFrameSet michael@0: // michael@0: // Also note: We only want to call this we are printing "Each Frame Separately" michael@0: // when printing "As Is" leave it as an eFrame michael@0: void michael@0: nsPrintEngine::CheckForChildFrameSets(nsPrintObject* aPO) michael@0: { michael@0: NS_ASSERTION(aPO, "Pointer is null!"); michael@0: michael@0: // Continue recursively walking the chilren of this PO michael@0: bool hasChildFrames = false; michael@0: for (uint32_t i=0;imKids.Length();i++) { michael@0: nsPrintObject* po = aPO->mKids[i]; michael@0: if (po->mFrameType == eFrame) { michael@0: hasChildFrames = true; michael@0: CheckForChildFrameSets(po); michael@0: } michael@0: } michael@0: michael@0: if (hasChildFrames && aPO->mFrameType == eFrame) { michael@0: aPO->mFrameType = eFrameSet; michael@0: } michael@0: } michael@0: michael@0: //--------------------------------------------------------------------- michael@0: // This method is key to the entire print mechanism. michael@0: // michael@0: // This "maps" or figures out which sub-doc represents a michael@0: // given Frame or IFrame in its parent sub-doc. michael@0: // michael@0: // So the Mcontent pointer in the child sub-doc points to the michael@0: // content in the its parent document, that caused it to be printed. michael@0: // This is used later to (after reflow) to find the absolute location michael@0: // of the sub-doc on its parent's page frame so it can be michael@0: // printed in the correct location. michael@0: // michael@0: // This method recursvely "walks" the content for a document finding michael@0: // all the Frames and IFrames, then sets the "mFrameType" data member michael@0: // which tells us what type of PO we have michael@0: void michael@0: nsPrintEngine::MapContentForPO(nsPrintObject* aPO, michael@0: nsIContent* aContent) michael@0: { michael@0: NS_PRECONDITION(aPO && aContent, "Null argument"); michael@0: michael@0: nsIDocument* doc = aContent->GetDocument(); michael@0: michael@0: NS_ASSERTION(doc, "Content without a document from a document tree?"); michael@0: michael@0: nsIDocument* subDoc = doc->GetSubDocumentFor(aContent); michael@0: michael@0: if (subDoc) { michael@0: nsCOMPtr docShell(subDoc->GetDocShell()); michael@0: michael@0: if (docShell) { michael@0: nsPrintObject * po = nullptr; michael@0: int32_t cnt = aPO->mKids.Length(); michael@0: for (int32_t i=0;imKids.ElementAt(i); michael@0: if (kid->mDocument == subDoc) { michael@0: po = kid; michael@0: break; michael@0: } michael@0: } michael@0: michael@0: // XXX If a subdocument has no onscreen presentation, there will be no PO michael@0: // This is even if there should be a print presentation michael@0: if (po) { michael@0: michael@0: nsCOMPtr frame(do_QueryInterface(aContent)); michael@0: // "frame" elements not in a frameset context should be treated michael@0: // as iframes michael@0: if (frame && po->mParent->mFrameType == eFrameSet) { michael@0: po->mFrameType = eFrame; michael@0: } else { michael@0: // Assume something iframe-like, i.e. iframe, object, or embed michael@0: po->mFrameType = eIFrame; michael@0: SetPrintAsIs(po, true); michael@0: NS_ASSERTION(po->mParent, "The root must be a parent"); michael@0: po->mParent->mPrintAsIs = true; michael@0: } michael@0: } michael@0: } michael@0: } michael@0: michael@0: // walk children content michael@0: for (nsIContent* child = aContent->GetFirstChild(); michael@0: child; michael@0: child = child->GetNextSibling()) { michael@0: MapContentForPO(aPO, child); michael@0: } michael@0: } michael@0: michael@0: //--------------------------------------------------------------------- michael@0: bool michael@0: nsPrintEngine::IsThereAnIFrameSelected(nsIDocShell* aDocShell, michael@0: nsIDOMWindow* aDOMWin, michael@0: bool& aIsParentFrameSet) michael@0: { michael@0: aIsParentFrameSet = IsParentAFrameSet(aDocShell); michael@0: bool iFrameIsSelected = false; michael@0: if (mPrt && mPrt->mPrintObject) { michael@0: nsPrintObject* po = FindPrintObjectByDOMWin(mPrt->mPrintObject, aDOMWin); michael@0: iFrameIsSelected = po && po->mFrameType == eIFrame; michael@0: } else { michael@0: // First, check to see if we are a frameset michael@0: if (!aIsParentFrameSet) { michael@0: // Check to see if there is a currenlt focused frame michael@0: // if so, it means the selected frame is either the main docshell michael@0: // or an IFRAME michael@0: if (aDOMWin) { michael@0: // Get the main docshell's DOMWin to see if it matches michael@0: // the frame that is selected michael@0: nsCOMPtr domWin = do_GetInterface(aDocShell); michael@0: if (domWin != aDOMWin) { michael@0: iFrameIsSelected = true; // we have a selected IFRAME michael@0: } michael@0: } michael@0: } michael@0: } michael@0: michael@0: return iFrameIsSelected; michael@0: } michael@0: michael@0: //--------------------------------------------------------------------- michael@0: // Recursively sets all the PO items to be printed michael@0: // from the given item down into the tree michael@0: void michael@0: nsPrintEngine::SetPrintPO(nsPrintObject* aPO, bool aPrint) michael@0: { michael@0: NS_ASSERTION(aPO, "Pointer is null!"); michael@0: michael@0: // Set whether to print flag michael@0: aPO->mDontPrint = !aPrint; michael@0: michael@0: for (uint32_t i=0;imKids.Length();i++) { michael@0: SetPrintPO(aPO->mKids[i], aPrint); michael@0: } michael@0: } michael@0: michael@0: //--------------------------------------------------------------------- michael@0: // This will first use a Title and/or URL from the PrintSettings michael@0: // if one isn't set then it uses the one from the document michael@0: // then if not title is there we will make sure we send something back michael@0: // depending on the situation. michael@0: void michael@0: nsPrintEngine::GetDisplayTitleAndURL(nsPrintObject* aPO, michael@0: nsAString& aTitle, michael@0: nsAString& aURLStr, michael@0: eDocTitleDefault aDefType) michael@0: { michael@0: NS_ASSERTION(aPO, "Pointer is null!"); michael@0: michael@0: if (!mPrt) michael@0: return; michael@0: michael@0: aTitle.Truncate(); michael@0: aURLStr.Truncate(); michael@0: michael@0: // First check to see if the PrintSettings has defined an alternate title michael@0: // and use that if it did michael@0: if (mPrt->mPrintSettings) { michael@0: char16_t * docTitleStrPS = nullptr; michael@0: char16_t * docURLStrPS = nullptr; michael@0: mPrt->mPrintSettings->GetTitle(&docTitleStrPS); michael@0: mPrt->mPrintSettings->GetDocURL(&docURLStrPS); michael@0: michael@0: if (docTitleStrPS) { michael@0: aTitle = docTitleStrPS; michael@0: } michael@0: michael@0: if (docURLStrPS) { michael@0: aURLStr = docURLStrPS; michael@0: } michael@0: michael@0: nsMemory::Free(docTitleStrPS); michael@0: nsMemory::Free(docURLStrPS); michael@0: } michael@0: michael@0: nsAutoString docTitle; michael@0: nsAutoString docUrl; michael@0: GetDocumentTitleAndURL(aPO->mDocument, docTitle, docUrl); michael@0: michael@0: if (aURLStr.IsEmpty() && !docUrl.IsEmpty()) { michael@0: aURLStr = docUrl; michael@0: } michael@0: michael@0: if (aTitle.IsEmpty()) { michael@0: if (!docTitle.IsEmpty()) { michael@0: aTitle = docTitle; michael@0: } else { michael@0: if (aDefType == eDocTitleDefURLDoc) { michael@0: if (!aURLStr.IsEmpty()) { michael@0: aTitle = aURLStr; michael@0: } else if (mPrt->mBrandName) { michael@0: aTitle = mPrt->mBrandName; michael@0: } michael@0: } michael@0: } michael@0: } michael@0: } michael@0: michael@0: //--------------------------------------------------------------------- michael@0: nsresult nsPrintEngine::DocumentReadyForPrinting() michael@0: { michael@0: if (mPrt->mPrintFrameType == nsIPrintSettings::kEachFrameSep) { michael@0: CheckForChildFrameSets(mPrt->mPrintObject); michael@0: } michael@0: michael@0: // michael@0: // Send the document to the printer... michael@0: // michael@0: nsresult rv = SetupToPrintContent(); michael@0: if (NS_FAILED(rv)) { michael@0: // The print job was canceled or there was a problem michael@0: // So remove all other documents from the print list michael@0: DonePrintingPages(nullptr, rv); michael@0: } michael@0: return rv; michael@0: } michael@0: michael@0: /** --------------------------------------------------- michael@0: * Cleans up when an error occurred michael@0: */ michael@0: nsresult nsPrintEngine::CleanupOnFailure(nsresult aResult, bool aIsPrinting) michael@0: { michael@0: PR_PL(("**** Failed %s - rv 0x%X", aIsPrinting?"Printing":"Print Preview", aResult)); michael@0: michael@0: /* cleanup... */ michael@0: if (mPagePrintTimer) { michael@0: mPagePrintTimer->Stop(); michael@0: NS_RELEASE(mPagePrintTimer); michael@0: } michael@0: michael@0: if (aIsPrinting) { michael@0: SetIsPrinting(false); michael@0: } else { michael@0: SetIsPrintPreview(false); michael@0: SetIsCreatingPrintPreview(false); michael@0: } michael@0: michael@0: /* cleanup done, let's fire-up an error dialog to notify the user michael@0: * what went wrong... michael@0: * michael@0: * When rv == NS_ERROR_ABORT, it means we want out of the michael@0: * print job without displaying any error messages michael@0: */ michael@0: if (aResult != NS_ERROR_ABORT) { michael@0: ShowPrintErrorDialog(aResult, aIsPrinting); michael@0: } michael@0: michael@0: FirePrintCompletionEvent(); michael@0: michael@0: return aResult; michael@0: michael@0: } michael@0: michael@0: //--------------------------------------------------------------------- michael@0: void michael@0: nsPrintEngine::ShowPrintErrorDialog(nsresult aPrintError, bool aIsPrinting) michael@0: { michael@0: nsAutoCString stringName; michael@0: nsXPIDLString msg, title; michael@0: nsresult rv = NS_OK; michael@0: michael@0: switch(aPrintError) michael@0: { michael@0: #define ENTITY_FOR_ERROR(label) \ michael@0: case NS_ERROR_##label: stringName.AssignLiteral("PERR_" #label); break michael@0: michael@0: ENTITY_FOR_ERROR(GFX_PRINTER_NO_PRINTER_AVAILABLE); michael@0: ENTITY_FOR_ERROR(GFX_PRINTER_NAME_NOT_FOUND); michael@0: ENTITY_FOR_ERROR(GFX_PRINTER_COULD_NOT_OPEN_FILE); michael@0: ENTITY_FOR_ERROR(GFX_PRINTER_STARTDOC); michael@0: ENTITY_FOR_ERROR(GFX_PRINTER_ENDDOC); michael@0: ENTITY_FOR_ERROR(GFX_PRINTER_STARTPAGE); michael@0: ENTITY_FOR_ERROR(GFX_PRINTER_DOC_IS_BUSY); michael@0: michael@0: ENTITY_FOR_ERROR(ABORT); michael@0: ENTITY_FOR_ERROR(NOT_AVAILABLE); michael@0: ENTITY_FOR_ERROR(NOT_IMPLEMENTED); michael@0: ENTITY_FOR_ERROR(OUT_OF_MEMORY); michael@0: ENTITY_FOR_ERROR(UNEXPECTED); michael@0: michael@0: default: michael@0: ENTITY_FOR_ERROR(FAILURE); michael@0: michael@0: #undef ENTITY_FOR_ERROR michael@0: } michael@0: michael@0: if (!aIsPrinting) { michael@0: // Try first with _PP suffix. michael@0: stringName.AppendLiteral("_PP"); michael@0: rv = nsContentUtils::GetLocalizedString( michael@0: nsContentUtils::ePRINTING_PROPERTIES, stringName.get(), msg); michael@0: if (NS_FAILED(rv)) { michael@0: stringName.Truncate(stringName.Length() - 3); michael@0: } michael@0: } michael@0: if (aIsPrinting || NS_FAILED(rv)) { michael@0: rv = nsContentUtils::GetLocalizedString( michael@0: nsContentUtils::ePRINTING_PROPERTIES, stringName.get(), msg); michael@0: } michael@0: if (NS_FAILED(rv)) { michael@0: return; michael@0: } michael@0: michael@0: rv = nsContentUtils::GetLocalizedString( michael@0: nsContentUtils::ePRINTING_PROPERTIES, michael@0: aIsPrinting ? "print_error_dialog_title" michael@0: : "printpreview_error_dialog_title", michael@0: title); michael@0: if (NS_FAILED(rv)) { michael@0: return; michael@0: } michael@0: michael@0: nsCOMPtr wwatch = michael@0: do_GetService(NS_WINDOWWATCHER_CONTRACTID, &rv); michael@0: if (NS_FAILED(rv)) { michael@0: return; michael@0: } michael@0: michael@0: nsCOMPtr active; michael@0: wwatch->GetActiveWindow(getter_AddRefs(active)); michael@0: michael@0: nsCOMPtr dialog; michael@0: /* |GetNewPrompter| allows that |active| is |nullptr| michael@0: * (see bug 234982 ("nsPrintEngine::ShowPrintErrorDialog() fails in many cases")) */ michael@0: wwatch->GetNewPrompter(active, getter_AddRefs(dialog)); michael@0: if (!dialog) { michael@0: return; michael@0: } michael@0: michael@0: dialog->Alert(title.get(), msg.get()); michael@0: } michael@0: michael@0: //----------------------------------------------------------------- michael@0: //-- Section: Reflow Methods michael@0: //----------------------------------------------------------------- michael@0: michael@0: nsresult michael@0: nsPrintEngine::ReconstructAndReflow(bool doSetPixelScale) michael@0: { michael@0: #if defined(XP_WIN) && defined(EXTENDED_DEBUG_PRINTING) michael@0: // We need to clear all the output files here michael@0: // because they will be re-created with second reflow of the docs michael@0: if (kPrintingLogMod && kPrintingLogMod->level == DUMP_LAYOUT_LEVEL) { michael@0: RemoveFilesInDir(".\\"); michael@0: gDumpFileNameCnt = 0; michael@0: gDumpLOFileNameCnt = 0; michael@0: } michael@0: #endif michael@0: michael@0: for (uint32_t i = 0; i < mPrt->mPrintDocList.Length(); ++i) { michael@0: nsPrintObject* po = mPrt->mPrintDocList.ElementAt(i); michael@0: NS_ASSERTION(po, "nsPrintObject can't be null!"); michael@0: michael@0: if (po->mDontPrint || po->mInvisible) { michael@0: continue; michael@0: } michael@0: michael@0: UpdateZoomRatio(po, doSetPixelScale); michael@0: michael@0: po->mPresContext->SetPageScale(po->mZoomRatio); michael@0: michael@0: // Calculate scale factor from printer to screen michael@0: float printDPI = float(mPrt->mPrintDC->AppUnitsPerCSSInch()) / michael@0: float(mPrt->mPrintDC->AppUnitsPerDevPixel()); michael@0: po->mPresContext->SetPrintPreviewScale(mScreenDPI / printDPI); michael@0: michael@0: po->mPresShell->ReconstructFrames(); michael@0: michael@0: // For all views except the first one, setup the root view. michael@0: // ??? Can there be multiple po for the top-level-document? michael@0: bool documentIsTopLevel = true; michael@0: if (i != 0) { michael@0: nsSize adjSize; michael@0: bool doReturn; michael@0: nsresult rv = SetRootView(po, doReturn, documentIsTopLevel, adjSize); michael@0: michael@0: MOZ_ASSERT(!documentIsTopLevel, "How could this happen?"); michael@0: michael@0: if (NS_FAILED(rv) || doReturn) { michael@0: return rv; michael@0: } michael@0: } michael@0: michael@0: po->mPresShell->FlushPendingNotifications(Flush_Layout); michael@0: michael@0: nsresult rv = UpdateSelectionAndShrinkPrintObject(po, documentIsTopLevel); michael@0: NS_ENSURE_SUCCESS(rv, rv); michael@0: } michael@0: return NS_OK; michael@0: } michael@0: michael@0: //------------------------------------------------------- michael@0: nsresult michael@0: nsPrintEngine::SetupToPrintContent() michael@0: { michael@0: nsresult rv; michael@0: michael@0: bool didReconstruction = false; michael@0: michael@0: // If some new content got loaded since the initial reflow rebuild michael@0: // everything. michael@0: if (mDidLoadDataForPrinting) { michael@0: rv = ReconstructAndReflow(DoSetPixelScale()); michael@0: didReconstruction = true; michael@0: NS_ENSURE_SUCCESS(rv, rv); michael@0: } michael@0: michael@0: // Here is where we figure out if extra reflow for shrinking the content michael@0: // is required. michael@0: // But skip this step if we are in PrintPreview michael@0: bool ppIsShrinkToFit = mPrtPreview && mPrtPreview->mShrinkToFit; michael@0: if (mPrt->mShrinkToFit && !ppIsShrinkToFit) { michael@0: // Now look for the PO that has the smallest percent for shrink to fit michael@0: if (mPrt->mPrintDocList.Length() > 1 && mPrt->mPrintObject->mFrameType == eFrameSet) { michael@0: nsPrintObject* smallestPO = FindSmallestSTF(); michael@0: NS_ASSERTION(smallestPO, "There must always be an XMost PO!"); michael@0: if (smallestPO) { michael@0: // Calc the shrinkage based on the entire content area michael@0: mPrt->mShrinkRatio = smallestPO->mShrinkRatio; michael@0: } michael@0: } else { michael@0: // Single document so use the Shrink as calculated for the PO michael@0: mPrt->mShrinkRatio = mPrt->mPrintObject->mShrinkRatio; michael@0: } michael@0: michael@0: if (mPrt->mShrinkRatio < 0.998f) { michael@0: rv = ReconstructAndReflow(true); michael@0: didReconstruction = true; michael@0: NS_ENSURE_SUCCESS(rv, rv); michael@0: } michael@0: michael@0: #ifdef PR_LOGGING michael@0: float calcRatio = 0.0f; michael@0: if (mPrt->mPrintDocList.Length() > 1 && mPrt->mPrintObject->mFrameType == eFrameSet) { michael@0: nsPrintObject* smallestPO = FindSmallestSTF(); michael@0: NS_ASSERTION(smallestPO, "There must always be an XMost PO!"); michael@0: if (smallestPO) { michael@0: // Calc the shrinkage based on the entire content area michael@0: calcRatio = smallestPO->mShrinkRatio; michael@0: } michael@0: } else { michael@0: // Single document so use the Shrink as calculated for the PO michael@0: calcRatio = mPrt->mPrintObject->mShrinkRatio; michael@0: } michael@0: PR_PL(("**************************************************************************\n")); michael@0: PR_PL(("STF Ratio is: %8.5f Effective Ratio: %8.5f Diff: %8.5f\n", mPrt->mShrinkRatio, calcRatio, mPrt->mShrinkRatio-calcRatio)); michael@0: PR_PL(("**************************************************************************\n")); michael@0: #endif michael@0: } michael@0: michael@0: // If the frames got reconstructed and reflowed the number of pages might michael@0: // has changed. michael@0: if (didReconstruction) { michael@0: FirePrintPreviewUpdateEvent(); michael@0: } michael@0: michael@0: DUMP_DOC_LIST(("\nAfter Reflow------------------------------------------")); michael@0: PR_PL(("\n")); michael@0: PR_PL(("-------------------------------------------------------\n")); michael@0: PR_PL(("\n")); michael@0: michael@0: CalcNumPrintablePages(mPrt->mNumPrintablePages); michael@0: michael@0: PR_PL(("--- Printing %d pages\n", mPrt->mNumPrintablePages)); michael@0: DUMP_DOC_TREELAYOUT; michael@0: michael@0: // Print listener setup... michael@0: if (mPrt != nullptr) { michael@0: mPrt->OnStartPrinting(); michael@0: } michael@0: michael@0: char16_t* fileName = nullptr; michael@0: // check to see if we are printing to a file michael@0: bool isPrintToFile = false; michael@0: mPrt->mPrintSettings->GetPrintToFile(&isPrintToFile); michael@0: if (isPrintToFile) { michael@0: // On some platforms The BeginDocument needs to know the name of the file michael@0: // and it uses the PrintService to get it, so we need to set it into the PrintService here michael@0: mPrt->mPrintSettings->GetToFileName(&fileName); michael@0: } michael@0: michael@0: nsAutoString docTitleStr; michael@0: nsAutoString docURLStr; michael@0: GetDisplayTitleAndURL(mPrt->mPrintObject, docTitleStr, docURLStr, eDocTitleDefURLDoc); michael@0: michael@0: int32_t startPage = 1; michael@0: int32_t endPage = mPrt->mNumPrintablePages; michael@0: michael@0: int16_t printRangeType = nsIPrintSettings::kRangeAllPages; michael@0: mPrt->mPrintSettings->GetPrintRange(&printRangeType); michael@0: if (printRangeType == nsIPrintSettings::kRangeSpecifiedPageRange) { michael@0: mPrt->mPrintSettings->GetStartPageRange(&startPage); michael@0: mPrt->mPrintSettings->GetEndPageRange(&endPage); michael@0: if (endPage > mPrt->mNumPrintablePages) { michael@0: endPage = mPrt->mNumPrintablePages; michael@0: } michael@0: } michael@0: michael@0: rv = NS_OK; michael@0: // BeginDocument may pass back a FAILURE code michael@0: // i.e. On Windows, if you are printing to a file and hit "Cancel" michael@0: // to the "File Name" dialog, this comes back as an error michael@0: // Don't start printing when regression test are executed michael@0: if (!mPrt->mDebugFilePtr && mIsDoingPrinting) { michael@0: rv = mPrt->mPrintDC->BeginDocument(docTitleStr, fileName, startPage, endPage); michael@0: } michael@0: michael@0: if (mIsCreatingPrintPreview) { michael@0: // Copy docTitleStr and docURLStr to the pageSequenceFrame, to be displayed michael@0: // in the header michael@0: nsIPageSequenceFrame *seqFrame = mPrt->mPrintObject->mPresShell->GetPageSequenceFrame(); michael@0: if (seqFrame) { michael@0: seqFrame->StartPrint(mPrt->mPrintObject->mPresContext, michael@0: mPrt->mPrintSettings, docTitleStr, docURLStr); michael@0: } michael@0: } michael@0: michael@0: PR_PL(("****************** Begin Document ************************\n")); michael@0: michael@0: NS_ENSURE_SUCCESS(rv, rv); michael@0: michael@0: // This will print the docshell document michael@0: // when it completes asynchronously in the DonePrintingPages method michael@0: // it will check to see if there are more docshells to be printed and michael@0: // then PrintDocContent will be called again. michael@0: michael@0: if (mIsDoingPrinting) { michael@0: PrintDocContent(mPrt->mPrintObject, rv); // ignore return value michael@0: } michael@0: michael@0: return rv; michael@0: } michael@0: michael@0: //------------------------------------------------------- michael@0: // Recursively reflow each sub-doc and then calc michael@0: // all the frame locations of the sub-docs michael@0: nsresult michael@0: nsPrintEngine::ReflowDocList(nsPrintObject* aPO, bool aSetPixelScale) michael@0: { michael@0: NS_ENSURE_ARG_POINTER(aPO); michael@0: michael@0: // Check to see if the subdocument's element has been hidden by the parent document michael@0: if (aPO->mParent && aPO->mParent->mPresShell) { michael@0: nsIFrame* frame = aPO->mContent ? aPO->mContent->GetPrimaryFrame() : nullptr; michael@0: if (!frame || !frame->StyleVisibility()->IsVisible()) { michael@0: SetPrintPO(aPO, false); michael@0: aPO->mInvisible = true; michael@0: return NS_OK; michael@0: } michael@0: } michael@0: michael@0: UpdateZoomRatio(aPO, aSetPixelScale); michael@0: michael@0: nsresult rv; michael@0: // Reflow the PO michael@0: rv = ReflowPrintObject(aPO); michael@0: NS_ENSURE_SUCCESS(rv, rv); michael@0: michael@0: int32_t cnt = aPO->mKids.Length(); michael@0: for (int32_t i=0;imKids[i], aSetPixelScale); michael@0: NS_ENSURE_SUCCESS(rv, rv); michael@0: } michael@0: return NS_OK; michael@0: } michael@0: michael@0: void michael@0: nsPrintEngine::FirePrintPreviewUpdateEvent() michael@0: { michael@0: // Dispatch the event only while in PrintPreview. When printing, there is no michael@0: // listener bound to this event and therefore no need to dispatch it. michael@0: if (mIsDoingPrintPreview && !mIsDoingPrinting) { michael@0: nsCOMPtr cv = do_QueryInterface(mDocViewerPrint); michael@0: (new AsyncEventDispatcher( michael@0: cv->GetDocument(), NS_LITERAL_STRING("printPreviewUpdate"), true, true) michael@0: )->RunDOMEventWhenSafe(); michael@0: } michael@0: } michael@0: michael@0: nsresult michael@0: nsPrintEngine::InitPrintDocConstruction(bool aHandleError) michael@0: { michael@0: nsresult rv; michael@0: rv = ReflowDocList(mPrt->mPrintObject, DoSetPixelScale()); michael@0: NS_ENSURE_SUCCESS(rv, rv); michael@0: michael@0: FirePrintPreviewUpdateEvent(); michael@0: michael@0: if (mLoadCounter == 0) { michael@0: AfterNetworkPrint(aHandleError); michael@0: } michael@0: return rv; michael@0: } michael@0: michael@0: nsresult michael@0: nsPrintEngine::AfterNetworkPrint(bool aHandleError) michael@0: { michael@0: nsCOMPtr webProgress = do_QueryInterface(mPrt->mPrintObject->mDocShell); michael@0: michael@0: webProgress->RemoveProgressListener( michael@0: static_cast(this)); michael@0: michael@0: nsresult rv; michael@0: if (mIsDoingPrinting) { michael@0: rv = DocumentReadyForPrinting(); michael@0: } else { michael@0: rv = FinishPrintPreview(); michael@0: } michael@0: michael@0: /* cleaup on failure + notify user */ michael@0: if (aHandleError && NS_FAILED(rv)) { michael@0: CleanupOnFailure(rv, !mIsDoingPrinting); michael@0: } michael@0: michael@0: return rv; michael@0: } michael@0: michael@0: //////////////////////////////////////////////////////////////////////////////// michael@0: // nsIWebProgressListener michael@0: michael@0: NS_IMETHODIMP michael@0: nsPrintEngine::OnStateChange(nsIWebProgress* aWebProgress, michael@0: nsIRequest* aRequest, michael@0: uint32_t aStateFlags, michael@0: nsresult aStatus) michael@0: { michael@0: nsAutoCString name; michael@0: aRequest->GetName(name); michael@0: if (name.Equals("about:document-onload-blocker")) { michael@0: return NS_OK; michael@0: } michael@0: if (aStateFlags & STATE_START) { michael@0: nsCOMPtr channel = do_QueryInterface(aRequest); michael@0: michael@0: ++mLoadCounter; michael@0: } else if (aStateFlags & STATE_STOP) { michael@0: mDidLoadDataForPrinting = true; michael@0: --mLoadCounter; michael@0: michael@0: // If all resources are loaded, then do a small timeout and if there michael@0: // are still no new requests, then another reflow. michael@0: if (mLoadCounter == 0) { michael@0: AfterNetworkPrint(true); michael@0: } michael@0: } michael@0: return NS_OK; michael@0: } michael@0: michael@0: michael@0: michael@0: NS_IMETHODIMP michael@0: nsPrintEngine::OnProgressChange(nsIWebProgress* aWebProgress, michael@0: nsIRequest* aRequest, michael@0: int32_t aCurSelfProgress, michael@0: int32_t aMaxSelfProgress, michael@0: int32_t aCurTotalProgress, michael@0: int32_t aMaxTotalProgress) michael@0: { michael@0: NS_NOTREACHED("notification excluded in AddProgressListener(...)"); michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsPrintEngine::OnLocationChange(nsIWebProgress* aWebProgress, michael@0: nsIRequest* aRequest, michael@0: nsIURI* aLocation, michael@0: uint32_t aFlags) michael@0: { michael@0: NS_NOTREACHED("notification excluded in AddProgressListener(...)"); michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsPrintEngine::OnStatusChange(nsIWebProgress *aWebProgress, michael@0: nsIRequest *aRequest, michael@0: nsresult aStatus, michael@0: const char16_t *aMessage) michael@0: { michael@0: NS_NOTREACHED("notification excluded in AddProgressListener(...)"); michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsPrintEngine::OnSecurityChange(nsIWebProgress *aWebProgress, michael@0: nsIRequest *aRequest, michael@0: uint32_t aState) michael@0: { michael@0: NS_NOTREACHED("notification excluded in AddProgressListener(...)"); michael@0: return NS_OK; michael@0: } michael@0: michael@0: //------------------------------------------------------- michael@0: michael@0: void michael@0: nsPrintEngine::UpdateZoomRatio(nsPrintObject* aPO, bool aSetPixelScale) michael@0: { michael@0: // Here is where we set the shrinkage value into the DC michael@0: // and this is what actually makes it shrink michael@0: if (aSetPixelScale && aPO->mFrameType != eIFrame) { michael@0: float ratio; michael@0: if (mPrt->mPrintFrameType == nsIPrintSettings::kFramesAsIs || mPrt->mPrintFrameType == nsIPrintSettings::kNoFrames) { michael@0: ratio = mPrt->mShrinkRatio - 0.005f; // round down michael@0: } else { michael@0: ratio = aPO->mShrinkRatio - 0.005f; // round down michael@0: } michael@0: aPO->mZoomRatio = ratio; michael@0: } else if (!mPrt->mShrinkToFit) { michael@0: double scaling; michael@0: mPrt->mPrintSettings->GetScaling(&scaling); michael@0: aPO->mZoomRatio = float(scaling); michael@0: } michael@0: } michael@0: michael@0: nsresult michael@0: nsPrintEngine::UpdateSelectionAndShrinkPrintObject(nsPrintObject* aPO, michael@0: bool aDocumentIsTopLevel) michael@0: { michael@0: nsCOMPtr displayShell = aPO->mDocShell->GetPresShell(); michael@0: // Transfer Selection Ranges to the new Print PresShell michael@0: nsRefPtr selection, selectionPS; michael@0: // It's okay if there is no display shell, just skip copying the selection michael@0: if (displayShell) { michael@0: selection = displayShell->GetCurrentSelection(nsISelectionController::SELECTION_NORMAL); michael@0: } michael@0: selectionPS = aPO->mPresShell->GetCurrentSelection(nsISelectionController::SELECTION_NORMAL); michael@0: michael@0: // Reset all existing selection ranges that might have been added by calling michael@0: // this function before. michael@0: if (selectionPS) { michael@0: selectionPS->RemoveAllRanges(); michael@0: } michael@0: if (selection && selectionPS) { michael@0: int32_t cnt = selection->GetRangeCount(); michael@0: int32_t inx; michael@0: for (inx = 0; inx < cnt; ++inx) { michael@0: selectionPS->AddRange(selection->GetRangeAt(inx)); michael@0: } michael@0: } michael@0: michael@0: // If we are trying to shrink the contents to fit on the page michael@0: // we must first locate the "pageContent" frame michael@0: // Then we walk the frame tree and look for the "xmost" frame michael@0: // this is the frame where the right-hand side of the frame extends michael@0: // the furthest michael@0: if (mPrt->mShrinkToFit && aDocumentIsTopLevel) { michael@0: nsIPageSequenceFrame* pageSequence = aPO->mPresShell->GetPageSequenceFrame(); michael@0: NS_ENSURE_STATE(pageSequence); michael@0: pageSequence->GetSTFPercent(aPO->mShrinkRatio); michael@0: // Limit the shrink-to-fit scaling for some text-ish type of documents. michael@0: nsAutoString contentType; michael@0: aPO->mPresShell->GetDocument()->GetContentType(contentType); michael@0: if (contentType.EqualsLiteral("application/xhtml+xml") || michael@0: StringBeginsWith(contentType, NS_LITERAL_STRING("text/"))) { michael@0: int32_t limitPercent = michael@0: Preferences::GetInt("print.shrink-to-fit.scale-limit-percent", 20); michael@0: limitPercent = std::max(0, limitPercent); michael@0: limitPercent = std::min(100, limitPercent); michael@0: float minShrinkRatio = float(limitPercent) / 100; michael@0: aPO->mShrinkRatio = std::max(aPO->mShrinkRatio, minShrinkRatio); michael@0: } michael@0: } michael@0: return NS_OK; michael@0: } michael@0: michael@0: bool michael@0: nsPrintEngine::DoSetPixelScale() michael@0: { michael@0: // This is an Optimization michael@0: // If we are in PP then we already know all the shrinkage information michael@0: // so just transfer it to the PrintData and we will skip the extra shrinkage reflow michael@0: // michael@0: // doSetPixelScale tells Reflow whether to set the shrinkage value into the DC michael@0: // The first time we do not want to do this, the second time through we do michael@0: bool doSetPixelScale = false; michael@0: bool ppIsShrinkToFit = mPrtPreview && mPrtPreview->mShrinkToFit; michael@0: if (ppIsShrinkToFit) { michael@0: mPrt->mShrinkRatio = mPrtPreview->mShrinkRatio; michael@0: doSetPixelScale = true; michael@0: } michael@0: return doSetPixelScale; michael@0: } michael@0: michael@0: nsView* michael@0: nsPrintEngine::GetParentViewForRoot() michael@0: { michael@0: if (mIsCreatingPrintPreview) { michael@0: nsCOMPtr cv = do_QueryInterface(mDocViewerPrint); michael@0: if (cv) { michael@0: return cv->FindContainerView(); michael@0: } michael@0: } michael@0: return nullptr; michael@0: } michael@0: michael@0: nsresult michael@0: nsPrintEngine::SetRootView( michael@0: nsPrintObject* aPO, michael@0: bool& doReturn, michael@0: bool& documentIsTopLevel, michael@0: nsSize& adjSize michael@0: ) michael@0: { michael@0: bool canCreateScrollbars = true; michael@0: michael@0: nsView* rootView; michael@0: nsView* parentView = nullptr; michael@0: michael@0: doReturn = false; michael@0: michael@0: if (aPO->mParent && aPO->mParent->IsPrintable()) { michael@0: nsIFrame* frame = aPO->mContent ? aPO->mContent->GetPrimaryFrame() : nullptr; michael@0: // Without a frame, this document can't be displayed; therefore, there is no michael@0: // point to reflowing it michael@0: if (!frame) { michael@0: SetPrintPO(aPO, false); michael@0: doReturn = true; michael@0: return NS_OK; michael@0: } michael@0: michael@0: //XXX If printing supported printing document hierarchies with non-constant michael@0: // zoom this would be wrong as we use the same mPrt->mPrintDC for all michael@0: // subdocuments. michael@0: adjSize = frame->GetContentRect().Size(); michael@0: documentIsTopLevel = false; michael@0: // presshell exists because parent is printable michael@0: michael@0: // the top nsPrintObject's widget will always have scrollbars michael@0: if (frame && frame->GetType() == nsGkAtoms::subDocumentFrame) { michael@0: nsView* view = frame->GetView(); michael@0: NS_ENSURE_TRUE(view, NS_ERROR_FAILURE); michael@0: view = view->GetFirstChild(); michael@0: NS_ENSURE_TRUE(view, NS_ERROR_FAILURE); michael@0: parentView = view; michael@0: canCreateScrollbars = false; michael@0: } michael@0: } else { michael@0: nscoord pageWidth, pageHeight; michael@0: mPrt->mPrintDC->GetDeviceSurfaceDimensions(pageWidth, pageHeight); michael@0: adjSize = nsSize(pageWidth, pageHeight); michael@0: documentIsTopLevel = true; michael@0: parentView = GetParentViewForRoot(); michael@0: } michael@0: michael@0: if (aPO->mViewManager->GetRootView()) { michael@0: // Reuse the root view that is already on the root frame. michael@0: rootView = aPO->mViewManager->GetRootView(); michael@0: // Remove it from its existing parent if necessary michael@0: aPO->mViewManager->RemoveChild(rootView); michael@0: rootView->SetParent(parentView); michael@0: } else { michael@0: // Create a child window of the parent that is our "root view/window" michael@0: nsRect tbounds = nsRect(nsPoint(0, 0), adjSize); michael@0: rootView = aPO->mViewManager->CreateView(tbounds, parentView); michael@0: NS_ENSURE_TRUE(rootView, NS_ERROR_OUT_OF_MEMORY); michael@0: } michael@0: michael@0: if (mIsCreatingPrintPreview && documentIsTopLevel) { michael@0: aPO->mPresContext->SetPaginatedScrolling(canCreateScrollbars); michael@0: } michael@0: michael@0: // Setup hierarchical relationship in view manager michael@0: aPO->mViewManager->SetRootView(rootView); michael@0: michael@0: return NS_OK; michael@0: } michael@0: michael@0: // Reflow a nsPrintObject michael@0: nsresult michael@0: nsPrintEngine::ReflowPrintObject(nsPrintObject * aPO) michael@0: { michael@0: NS_ENSURE_STATE(aPO); michael@0: michael@0: if (!aPO->IsPrintable()) { michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_ASSERTION(!aPO->mPresContext, "Recreating prescontext"); michael@0: michael@0: // create the PresContext michael@0: nsPresContext::nsPresContextType type = michael@0: mIsCreatingPrintPreview ? nsPresContext::eContext_PrintPreview: michael@0: nsPresContext::eContext_Print; michael@0: nsView* parentView = michael@0: aPO->mParent && aPO->mParent->IsPrintable() ? nullptr : GetParentViewForRoot(); michael@0: aPO->mPresContext = parentView ? michael@0: new nsPresContext(aPO->mDocument, type) : michael@0: new nsRootPresContext(aPO->mDocument, type); michael@0: NS_ENSURE_TRUE(aPO->mPresContext, NS_ERROR_OUT_OF_MEMORY); michael@0: aPO->mPresContext->SetPrintSettings(mPrt->mPrintSettings); michael@0: michael@0: // set the presentation context to the value in the print settings michael@0: bool printBGColors; michael@0: mPrt->mPrintSettings->GetPrintBGColors(&printBGColors); michael@0: aPO->mPresContext->SetBackgroundColorDraw(printBGColors); michael@0: mPrt->mPrintSettings->GetPrintBGImages(&printBGColors); michael@0: aPO->mPresContext->SetBackgroundImageDraw(printBGColors); michael@0: michael@0: // init it with the DC michael@0: nsresult rv = aPO->mPresContext->Init(mPrt->mPrintDC); michael@0: NS_ENSURE_SUCCESS(rv, rv); michael@0: michael@0: aPO->mViewManager = new nsViewManager(); michael@0: michael@0: rv = aPO->mViewManager->Init(mPrt->mPrintDC); michael@0: NS_ENSURE_SUCCESS(rv,rv); michael@0: michael@0: nsStyleSet* styleSet; michael@0: rv = mDocViewerPrint->CreateStyleSet(aPO->mDocument, &styleSet); michael@0: NS_ENSURE_SUCCESS(rv, rv); michael@0: michael@0: aPO->mPresShell = aPO->mDocument->CreateShell(aPO->mPresContext, michael@0: aPO->mViewManager, styleSet); michael@0: if (!aPO->mPresShell) { michael@0: delete styleSet; michael@0: return NS_ERROR_FAILURE; michael@0: } michael@0: michael@0: styleSet->EndUpdate(); michael@0: michael@0: // The pres shell now owns the style set object. michael@0: michael@0: michael@0: bool doReturn = false;; michael@0: bool documentIsTopLevel = false; michael@0: nsSize adjSize; michael@0: michael@0: rv = SetRootView(aPO, doReturn, documentIsTopLevel, adjSize); michael@0: michael@0: if (NS_FAILED(rv) || doReturn) { michael@0: return rv; michael@0: } michael@0: michael@0: PR_PL(("In DV::ReflowPrintObject PO: %p pS: %p (%9s) Setting w,h to %d,%d\n", aPO, aPO->mPresShell.get(), michael@0: gFrameTypesStr[aPO->mFrameType], adjSize.width, adjSize.height)); michael@0: michael@0: michael@0: // This docshell stuff is weird; will go away when we stop having multiple michael@0: // presentations per document michael@0: aPO->mPresContext->SetContainer(aPO->mDocShell); michael@0: michael@0: aPO->mPresShell->BeginObservingDocument(); michael@0: michael@0: aPO->mPresContext->SetPageSize(adjSize); michael@0: aPO->mPresContext->SetIsRootPaginatedDocument(documentIsTopLevel); michael@0: aPO->mPresContext->SetPageScale(aPO->mZoomRatio); michael@0: // Calculate scale factor from printer to screen michael@0: float printDPI = float(mPrt->mPrintDC->AppUnitsPerCSSInch()) / michael@0: float(mPrt->mPrintDC->AppUnitsPerDevPixel()); michael@0: aPO->mPresContext->SetPrintPreviewScale(mScreenDPI / printDPI); michael@0: michael@0: if (mIsCreatingPrintPreview && documentIsTopLevel) { michael@0: mDocViewerPrint->SetPrintPreviewPresentation(aPO->mViewManager, michael@0: aPO->mPresContext, michael@0: aPO->mPresShell); michael@0: } michael@0: michael@0: rv = aPO->mPresShell->Initialize(adjSize.width, adjSize.height); michael@0: michael@0: NS_ENSURE_SUCCESS(rv, rv); michael@0: NS_ASSERTION(aPO->mPresShell, "Presshell should still be here"); michael@0: michael@0: // Process the reflow event Initialize posted michael@0: aPO->mPresShell->FlushPendingNotifications(Flush_Layout); michael@0: michael@0: rv = UpdateSelectionAndShrinkPrintObject(aPO, documentIsTopLevel); michael@0: NS_ENSURE_SUCCESS(rv, rv); michael@0: michael@0: #ifdef EXTENDED_DEBUG_PRINTING michael@0: if (kPrintingLogMod && kPrintingLogMod->level == DUMP_LAYOUT_LEVEL) { michael@0: nsAutoCString docStr; michael@0: nsAutoCString urlStr; michael@0: GetDocTitleAndURL(aPO, docStr, urlStr); michael@0: char filename[256]; michael@0: sprintf(filename, "print_dump_%d.txt", gDumpFileNameCnt++); michael@0: // Dump all the frames and view to a a file michael@0: FILE * fd = fopen(filename, "w"); michael@0: if (fd) { michael@0: nsIFrame *theRootFrame = michael@0: aPO->mPresShell->FrameManager()->GetRootFrame(); michael@0: fprintf(fd, "Title: %s\n", docStr.get()); michael@0: fprintf(fd, "URL: %s\n", urlStr.get()); michael@0: fprintf(fd, "--------------- Frames ----------------\n"); michael@0: nsRefPtr renderingContext = michael@0: mPrt->mPrintDocDC->CreateRenderingContext(); michael@0: RootFrameList(aPO->mPresContext, fd, 0); michael@0: //DumpFrames(fd, aPO->mPresContext, renderingContext, theRootFrame, 0); michael@0: fprintf(fd, "---------------------------------------\n\n"); michael@0: fprintf(fd, "--------------- Views From Root Frame----------------\n"); michael@0: nsView* v = theRootFrame->GetView(); michael@0: if (v) { michael@0: v->List(fd); michael@0: } else { michael@0: printf("View is null!\n"); michael@0: } michael@0: if (docShell) { michael@0: fprintf(fd, "--------------- All Views ----------------\n"); michael@0: DumpViews(docShell, fd); michael@0: fprintf(fd, "---------------------------------------\n\n"); michael@0: } michael@0: fclose(fd); michael@0: } michael@0: } michael@0: #endif michael@0: michael@0: return NS_OK; michael@0: } michael@0: michael@0: //------------------------------------------------------- michael@0: // Figure out how many documents and how many total pages we are printing michael@0: void michael@0: nsPrintEngine::CalcNumPrintablePages(int32_t& aNumPages) michael@0: { michael@0: aNumPages = 0; michael@0: // Count the number of printable documents michael@0: // and printable pages michael@0: for (uint32_t i=0; imPrintDocList.Length(); i++) { michael@0: nsPrintObject* po = mPrt->mPrintDocList.ElementAt(i); michael@0: NS_ASSERTION(po, "nsPrintObject can't be null!"); michael@0: if (po->mPresContext && po->mPresContext->IsRootPaginatedDocument()) { michael@0: nsIPageSequenceFrame* pageSequence = po->mPresShell->GetPageSequenceFrame(); michael@0: nsIFrame * seqFrame = do_QueryFrame(pageSequence); michael@0: if (seqFrame) { michael@0: nsIFrame* frame = seqFrame->GetFirstPrincipalChild(); michael@0: while (frame) { michael@0: aNumPages++; michael@0: frame = frame->GetNextSibling(); michael@0: } michael@0: } michael@0: } michael@0: } michael@0: } michael@0: michael@0: //----------------------------------------------------------------- michael@0: //-- Done: Reflow Methods michael@0: //----------------------------------------------------------------- michael@0: michael@0: //----------------------------------------------------------------- michael@0: //-- Section: Printing Methods michael@0: //----------------------------------------------------------------- michael@0: michael@0: //------------------------------------------------------- michael@0: // Called for each DocShell that needs to be printed michael@0: bool michael@0: nsPrintEngine::PrintDocContent(nsPrintObject* aPO, nsresult& aStatus) michael@0: { michael@0: NS_ASSERTION(aPO, "Pointer is null!"); michael@0: aStatus = NS_OK; michael@0: michael@0: if (!aPO->mHasBeenPrinted && aPO->IsPrintable()) { michael@0: aStatus = DoPrint(aPO); michael@0: return true; michael@0: } michael@0: michael@0: // If |aPO->mPrintAsIs| and |aPO->mHasBeenPrinted| are true, michael@0: // the kids frames are already processed in |PrintPage|. michael@0: if (!aPO->mInvisible && !(aPO->mPrintAsIs && aPO->mHasBeenPrinted)) { michael@0: for (uint32_t i=0;imKids.Length();i++) { michael@0: nsPrintObject* po = aPO->mKids[i]; michael@0: bool printed = PrintDocContent(po, aStatus); michael@0: if (printed || NS_FAILED(aStatus)) { michael@0: return true; michael@0: } michael@0: } michael@0: } michael@0: return false; michael@0: } michael@0: michael@0: static already_AddRefed michael@0: GetEqualNodeInCloneTree(nsIDOMNode* aNode, nsIDocument* aDoc) michael@0: { michael@0: nsCOMPtr content = do_QueryInterface(aNode); michael@0: // Selections in anonymous subtrees aren't supported. michael@0: if (content && content->IsInAnonymousSubtree()) { michael@0: return nullptr; michael@0: } michael@0: michael@0: nsCOMPtr node = do_QueryInterface(aNode); michael@0: NS_ENSURE_TRUE(node, nullptr); michael@0: michael@0: nsTArray indexArray; michael@0: nsINode* current = node; michael@0: NS_ENSURE_TRUE(current, nullptr); michael@0: while (current) { michael@0: nsINode* parent = current->GetParentNode(); michael@0: if (!parent) { michael@0: break; michael@0: } michael@0: int32_t index = parent->IndexOf(current); michael@0: NS_ENSURE_TRUE(index >= 0, nullptr); michael@0: indexArray.AppendElement(index); michael@0: current = parent; michael@0: } michael@0: NS_ENSURE_TRUE(current->IsNodeOfType(nsINode::eDOCUMENT), nullptr); michael@0: michael@0: current = aDoc; michael@0: for (int32_t i = indexArray.Length() - 1; i >= 0; --i) { michael@0: current = current->GetChildAt(indexArray[i]); michael@0: NS_ENSURE_TRUE(current, nullptr); michael@0: } michael@0: nsCOMPtr result = do_QueryInterface(current); michael@0: return result.forget(); michael@0: } michael@0: michael@0: static void michael@0: CloneRangeToSelection(nsRange* aRange, nsIDocument* aDoc, michael@0: Selection* aSelection) michael@0: { michael@0: if (aRange->Collapsed()) { michael@0: return; michael@0: } michael@0: michael@0: nsCOMPtr startContainer, endContainer; michael@0: aRange->GetStartContainer(getter_AddRefs(startContainer)); michael@0: int32_t startOffset = aRange->StartOffset(); michael@0: aRange->GetEndContainer(getter_AddRefs(endContainer)); michael@0: int32_t endOffset = aRange->EndOffset(); michael@0: NS_ENSURE_TRUE_VOID(startContainer && endContainer); michael@0: michael@0: nsCOMPtr newStart = GetEqualNodeInCloneTree(startContainer, aDoc); michael@0: nsCOMPtr newEnd = GetEqualNodeInCloneTree(endContainer, aDoc); michael@0: NS_ENSURE_TRUE_VOID(newStart && newEnd); michael@0: michael@0: nsCOMPtr newStartNode = do_QueryInterface(newStart); michael@0: NS_ENSURE_TRUE_VOID(newStartNode); michael@0: michael@0: nsRefPtr range = new nsRange(newStartNode); michael@0: nsresult rv = range->SetStart(newStartNode, startOffset); michael@0: NS_ENSURE_SUCCESS_VOID(rv); michael@0: rv = range->SetEnd(newEnd, endOffset); michael@0: NS_ENSURE_SUCCESS_VOID(rv); michael@0: michael@0: aSelection->AddRange(range); michael@0: } michael@0: michael@0: static nsresult CloneSelection(nsIDocument* aOrigDoc, nsIDocument* aDoc) michael@0: { michael@0: nsIPresShell* origShell = aOrigDoc->GetShell(); michael@0: nsIPresShell* shell = aDoc->GetShell(); michael@0: NS_ENSURE_STATE(origShell && shell); michael@0: michael@0: nsRefPtr origSelection = michael@0: origShell->GetCurrentSelection(nsISelectionController::SELECTION_NORMAL); michael@0: nsRefPtr selection = michael@0: shell->GetCurrentSelection(nsISelectionController::SELECTION_NORMAL); michael@0: NS_ENSURE_STATE(origSelection && selection); michael@0: michael@0: int32_t rangeCount = origSelection->GetRangeCount(); michael@0: for (int32_t i = 0; i < rangeCount; ++i) { michael@0: CloneRangeToSelection(origSelection->GetRangeAt(i), aDoc, selection); michael@0: } michael@0: return NS_OK; michael@0: } michael@0: michael@0: //------------------------------------------------------- michael@0: nsresult michael@0: nsPrintEngine::DoPrint(nsPrintObject * aPO) michael@0: { michael@0: PR_PL(("\n")); michael@0: PR_PL(("**************************** %s ****************************\n", gFrameTypesStr[aPO->mFrameType])); michael@0: PR_PL(("****** In DV::DoPrint PO: %p \n", aPO)); michael@0: michael@0: nsIPresShell* poPresShell = aPO->mPresShell; michael@0: nsPresContext* poPresContext = aPO->mPresContext; michael@0: michael@0: NS_ASSERTION(poPresContext, "PrintObject has not been reflowed"); michael@0: NS_ASSERTION(poPresContext->Type() != nsPresContext::eContext_PrintPreview, michael@0: "How did this context end up here?"); michael@0: michael@0: if (mPrt->mPrintProgressParams) { michael@0: SetDocAndURLIntoProgress(aPO, mPrt->mPrintProgressParams); michael@0: } michael@0: michael@0: { michael@0: int16_t printRangeType = nsIPrintSettings::kRangeAllPages; michael@0: nsresult rv; michael@0: if (mPrt->mPrintSettings != nullptr) { michael@0: mPrt->mPrintSettings->GetPrintRange(&printRangeType); michael@0: } michael@0: michael@0: // Ask the page sequence frame to print all the pages michael@0: nsIPageSequenceFrame* pageSequence = poPresShell->GetPageSequenceFrame(); michael@0: NS_ASSERTION(nullptr != pageSequence, "no page sequence frame"); michael@0: michael@0: // We are done preparing for printing, so we can turn this off michael@0: mPrt->mPreparingForPrint = false; michael@0: michael@0: // mPrt->mDebugFilePtr this is onlu non-null when compiled for debugging michael@0: if (nullptr != mPrt->mDebugFilePtr) { michael@0: #ifdef DEBUG michael@0: // output the regression test michael@0: nsIFrame* root = poPresShell->FrameManager()->GetRootFrame(); michael@0: root->DumpRegressionData(poPresContext, mPrt->mDebugFilePtr, 0); michael@0: fclose(mPrt->mDebugFilePtr); michael@0: SetIsPrinting(false); michael@0: #endif michael@0: } else { michael@0: #ifdef EXTENDED_DEBUG_PRINTING michael@0: nsIFrame* rootFrame = poPresShell->FrameManager()->GetRootFrame(); michael@0: if (aPO->IsPrintable()) { michael@0: nsAutoCString docStr; michael@0: nsAutoCString urlStr; michael@0: GetDocTitleAndURL(aPO, docStr, urlStr); michael@0: DumpLayoutData(docStr.get(), urlStr.get(), poPresContext, mPrt->mPrintDocDC, rootFrame, docShell, nullptr); michael@0: } michael@0: #endif michael@0: michael@0: if (!mPrt->mPrintSettings) { michael@0: // not sure what to do here! michael@0: SetIsPrinting(false); michael@0: return NS_ERROR_FAILURE; michael@0: } michael@0: michael@0: nsAutoString docTitleStr; michael@0: nsAutoString docURLStr; michael@0: GetDisplayTitleAndURL(aPO, docTitleStr, docURLStr, eDocTitleDefBlank); michael@0: michael@0: if (nsIPrintSettings::kRangeSelection == printRangeType) { michael@0: CloneSelection(aPO->mDocument->GetOriginalDocument(), aPO->mDocument); michael@0: michael@0: poPresContext->SetIsRenderingOnlySelection(true); michael@0: // temporarily creating rendering context michael@0: // which is needed to find the selection frames michael@0: nsRefPtr rc = michael@0: mPrt->mPrintDC->CreateRenderingContext(); michael@0: michael@0: // find the starting and ending page numbers michael@0: // via the selection michael@0: nsIFrame* startFrame; michael@0: nsIFrame* endFrame; michael@0: int32_t startPageNum; michael@0: int32_t endPageNum; michael@0: nsRect startRect; michael@0: nsRect endRect; michael@0: michael@0: nsRefPtr selectionPS = michael@0: poPresShell->GetCurrentSelection(nsISelectionController::SELECTION_NORMAL); michael@0: michael@0: rv = GetPageRangeForSelection(poPresShell, poPresContext, *rc, selectionPS, pageSequence, michael@0: &startFrame, startPageNum, startRect, michael@0: &endFrame, endPageNum, endRect); michael@0: if (NS_SUCCEEDED(rv)) { michael@0: mPrt->mPrintSettings->SetStartPageRange(startPageNum); michael@0: mPrt->mPrintSettings->SetEndPageRange(endPageNum); michael@0: nsIntMargin marginTwips(0,0,0,0); michael@0: nsIntMargin unwrtMarginTwips(0,0,0,0); michael@0: mPrt->mPrintSettings->GetMarginInTwips(marginTwips); michael@0: mPrt->mPrintSettings->GetUnwriteableMarginInTwips(unwrtMarginTwips); michael@0: nsMargin totalMargin = poPresContext->CSSTwipsToAppUnits(marginTwips + michael@0: unwrtMarginTwips); michael@0: if (startPageNum == endPageNum) { michael@0: startRect.y -= totalMargin.top; michael@0: endRect.y -= totalMargin.top; michael@0: michael@0: // Clip out selection regions above the top of the first page michael@0: if (startRect.y < 0) { michael@0: // Reduce height to be the height of the positive-territory michael@0: // region of original rect michael@0: startRect.height = std::max(0, startRect.YMost()); michael@0: startRect.y = 0; michael@0: } michael@0: if (endRect.y < 0) { michael@0: // Reduce height to be the height of the positive-territory michael@0: // region of original rect michael@0: endRect.height = std::max(0, endRect.YMost()); michael@0: endRect.y = 0; michael@0: } michael@0: NS_ASSERTION(endRect.y >= startRect.y, michael@0: "Selection end point should be after start point"); michael@0: NS_ASSERTION(startRect.height >= 0, michael@0: "rect should have non-negative height."); michael@0: NS_ASSERTION(endRect.height >= 0, michael@0: "rect should have non-negative height."); michael@0: michael@0: nscoord selectionHgt = endRect.y + endRect.height - startRect.y; michael@0: // XXX This is temporary fix for printing more than one page of a selection michael@0: pageSequence->SetSelectionHeight(startRect.y * aPO->mZoomRatio, michael@0: selectionHgt * aPO->mZoomRatio); michael@0: michael@0: // calc total pages by getting calculating the selection's height michael@0: // and then dividing it by how page content frames will fit. michael@0: nscoord pageWidth, pageHeight; michael@0: mPrt->mPrintDC->GetDeviceSurfaceDimensions(pageWidth, pageHeight); michael@0: pageHeight -= totalMargin.top + totalMargin.bottom; michael@0: int32_t totalPages = NSToIntCeil(float(selectionHgt) * aPO->mZoomRatio / float(pageHeight)); michael@0: pageSequence->SetTotalNumPages(totalPages); michael@0: } michael@0: } michael@0: } michael@0: michael@0: nsIFrame * seqFrame = do_QueryFrame(pageSequence); michael@0: if (!seqFrame) { michael@0: SetIsPrinting(false); michael@0: return NS_ERROR_FAILURE; michael@0: } michael@0: michael@0: mPageSeqFrame = pageSequence; michael@0: mPageSeqFrame->StartPrint(poPresContext, mPrt->mPrintSettings, docTitleStr, docURLStr); michael@0: michael@0: // Schedule Page to Print michael@0: PR_PL(("Scheduling Print of PO: %p (%s) \n", aPO, gFrameTypesStr[aPO->mFrameType])); michael@0: StartPagePrintTimer(aPO); michael@0: } michael@0: } michael@0: michael@0: return NS_OK; michael@0: } michael@0: michael@0: //--------------------------------------------------------------------- michael@0: void michael@0: nsPrintEngine::SetDocAndURLIntoProgress(nsPrintObject* aPO, michael@0: nsIPrintProgressParams* aParams) michael@0: { michael@0: NS_ASSERTION(aPO, "Must have valid nsPrintObject"); michael@0: NS_ASSERTION(aParams, "Must have valid nsIPrintProgressParams"); michael@0: michael@0: if (!aPO || !aPO->mDocShell || !aParams) { michael@0: return; michael@0: } michael@0: const uint32_t kTitleLength = 64; michael@0: michael@0: nsAutoString docTitleStr; michael@0: nsAutoString docURLStr; michael@0: GetDisplayTitleAndURL(aPO, docTitleStr, docURLStr, eDocTitleDefURLDoc); michael@0: michael@0: // Make sure the Titles & URLS don't get too long for the progress dialog michael@0: EllipseLongString(docTitleStr, kTitleLength, false); michael@0: EllipseLongString(docURLStr, kTitleLength, true); michael@0: michael@0: aParams->SetDocTitle(docTitleStr.get()); michael@0: aParams->SetDocURL(docURLStr.get()); michael@0: } michael@0: michael@0: //--------------------------------------------------------------------- michael@0: void michael@0: nsPrintEngine::EllipseLongString(nsAString& aStr, const uint32_t aLen, bool aDoFront) michael@0: { michael@0: // Make sure the URLS don't get too long for the progress dialog michael@0: if (aLen >= 3 && aStr.Length() > aLen) { michael@0: if (aDoFront) { michael@0: nsAutoString newStr; michael@0: newStr.AppendLiteral("..."); michael@0: newStr += Substring(aStr, aStr.Length() - (aLen - 3), aLen - 3); michael@0: aStr = newStr; michael@0: } else { michael@0: aStr.SetLength(aLen - 3); michael@0: aStr.AppendLiteral("..."); michael@0: } michael@0: } michael@0: } michael@0: michael@0: static bool michael@0: DocHasPrintCallbackCanvas(nsIDocument* aDoc, void* aData) michael@0: { michael@0: if (!aDoc) { michael@0: return true; michael@0: } michael@0: Element* root = aDoc->GetRootElement(); michael@0: if (!root) { michael@0: return true; michael@0: } michael@0: nsRefPtr canvases = NS_GetContentList(root, michael@0: kNameSpaceID_XHTML, michael@0: NS_LITERAL_STRING("canvas")); michael@0: uint32_t canvasCount = canvases->Length(true); michael@0: for (uint32_t i = 0; i < canvasCount; ++i) { michael@0: HTMLCanvasElement* canvas = HTMLCanvasElement::FromContentOrNull(canvases->Item(i, false)); michael@0: if (canvas && canvas->GetMozPrintCallback()) { michael@0: // This subdocument has a print callback. Set result and return false to michael@0: // stop iteration. michael@0: *static_cast(aData) = true; michael@0: return false; michael@0: } michael@0: } michael@0: return true; michael@0: } michael@0: michael@0: static bool michael@0: DocHasPrintCallbackCanvas(nsIDocument* aDoc) michael@0: { michael@0: bool result = false; michael@0: aDoc->EnumerateSubDocuments(&DocHasPrintCallbackCanvas, static_cast(&result)); michael@0: return result; michael@0: } michael@0: michael@0: /** michael@0: * Checks to see if the document this print engine is associated with has any michael@0: * canvases that have a mozPrintCallback. michael@0: */ michael@0: bool michael@0: nsPrintEngine::HasPrintCallbackCanvas() michael@0: { michael@0: if (!mDocument) { michael@0: return false; michael@0: } michael@0: // First check this mDocument. michael@0: bool result = false; michael@0: DocHasPrintCallbackCanvas(mDocument, static_cast(&result)); michael@0: // Also check the sub documents. michael@0: return result || DocHasPrintCallbackCanvas(mDocument); michael@0: } michael@0: michael@0: //------------------------------------------------------- michael@0: bool michael@0: nsPrintEngine::PrePrintPage() michael@0: { michael@0: NS_ASSERTION(mPageSeqFrame, "mPageSeqFrame is null!"); michael@0: NS_ASSERTION(mPrt, "mPrt is null!"); michael@0: michael@0: // Although these should NEVER be nullptr michael@0: // This is added insurance, to make sure we don't crash in optimized builds michael@0: if (!mPrt || !mPageSeqFrame) { michael@0: return true; // means we are done preparing the page. michael@0: } michael@0: michael@0: // Check setting to see if someone request it be cancelled michael@0: bool isCancelled = false; michael@0: mPrt->mPrintSettings->GetIsCancelled(&isCancelled); michael@0: if (isCancelled) michael@0: return true; michael@0: michael@0: // Ask mPageSeqFrame if the page is ready to be printed. michael@0: // If the page doesn't get printed at all, the |done| will be |true|. michael@0: bool done = false; michael@0: nsresult rv = mPageSeqFrame->PrePrintNextPage(mPagePrintTimer, &done); michael@0: if (NS_FAILED(rv)) { michael@0: // ??? ::PrintPage doesn't set |mPrt->mIsAborted = true| if rv != NS_ERROR_ABORT, michael@0: // but I don't really understand why this should be the right thing to do? michael@0: // Shouldn't |mPrt->mIsAborted| set to true all the time if something michael@0: // wents wrong? michael@0: if (rv != NS_ERROR_ABORT) { michael@0: ShowPrintErrorDialog(rv); michael@0: mPrt->mIsAborted = true; michael@0: } michael@0: done = true; michael@0: } michael@0: return done; michael@0: } michael@0: michael@0: bool michael@0: nsPrintEngine::PrintPage(nsPrintObject* aPO, michael@0: bool& aInRange) michael@0: { michael@0: NS_ASSERTION(aPO, "aPO is null!"); michael@0: NS_ASSERTION(mPageSeqFrame, "mPageSeqFrame is null!"); michael@0: NS_ASSERTION(mPrt, "mPrt is null!"); michael@0: michael@0: // Although these should NEVER be nullptr michael@0: // This is added insurance, to make sure we don't crash in optimized builds michael@0: if (!mPrt || !aPO || !mPageSeqFrame) { michael@0: ShowPrintErrorDialog(NS_ERROR_FAILURE); michael@0: return true; // means we are done printing michael@0: } michael@0: michael@0: PR_PL(("-----------------------------------\n")); michael@0: PR_PL(("------ In DV::PrintPage PO: %p (%s)\n", aPO, gFrameTypesStr[aPO->mFrameType])); michael@0: michael@0: // Check setting to see if someone request it be cancelled michael@0: bool isCancelled = false; michael@0: mPrt->mPrintSettings->GetIsCancelled(&isCancelled); michael@0: if (isCancelled || mPrt->mIsAborted) michael@0: return true; michael@0: michael@0: int32_t pageNum, numPages, endPage; michael@0: mPageSeqFrame->GetCurrentPageNum(&pageNum); michael@0: mPageSeqFrame->GetNumPages(&numPages); michael@0: michael@0: bool donePrinting; michael@0: bool isDoingPrintRange; michael@0: mPageSeqFrame->IsDoingPrintRange(&isDoingPrintRange); michael@0: if (isDoingPrintRange) { michael@0: int32_t fromPage; michael@0: int32_t toPage; michael@0: mPageSeqFrame->GetPrintRange(&fromPage, &toPage); michael@0: michael@0: if (fromPage > numPages) { michael@0: return true; michael@0: } michael@0: if (toPage > numPages) { michael@0: toPage = numPages; michael@0: } michael@0: michael@0: PR_PL(("****** Printing Page %d printing from %d to page %d\n", pageNum, fromPage, toPage)); michael@0: michael@0: donePrinting = pageNum >= toPage; michael@0: aInRange = pageNum >= fromPage && pageNum <= toPage; michael@0: endPage = (toPage - fromPage)+1; michael@0: } else { michael@0: PR_PL(("****** Printing Page %d of %d page(s)\n", pageNum, numPages)); michael@0: michael@0: donePrinting = pageNum >= numPages; michael@0: endPage = numPages; michael@0: aInRange = true; michael@0: } michael@0: michael@0: // XXX This is wrong, but the actual behavior in the presence of a print michael@0: // range sucks. michael@0: if (mPrt->mPrintFrameType == nsIPrintSettings::kEachFrameSep) michael@0: endPage = mPrt->mNumPrintablePages; michael@0: michael@0: mPrt->DoOnProgressChange(++mPrt->mNumPagesPrinted, endPage, false, 0); michael@0: michael@0: // Print the Page michael@0: // if a print job was cancelled externally, an EndPage or BeginPage may michael@0: // fail and the failure is passed back here. michael@0: // Returning true means we are done printing. michael@0: // michael@0: // When rv == NS_ERROR_ABORT, it means we want out of the michael@0: // print job without displaying any error messages michael@0: nsresult rv = mPageSeqFrame->PrintNextPage(); michael@0: if (NS_FAILED(rv)) { michael@0: if (rv != NS_ERROR_ABORT) { michael@0: ShowPrintErrorDialog(rv); michael@0: mPrt->mIsAborted = true; michael@0: } michael@0: return true; michael@0: } michael@0: michael@0: mPageSeqFrame->DoPageEnd(); michael@0: michael@0: return donePrinting; michael@0: } michael@0: michael@0: /** --------------------------------------------------- michael@0: * Find by checking frames type michael@0: */ michael@0: nsresult michael@0: nsPrintEngine::FindSelectionBoundsWithList(nsPresContext* aPresContext, michael@0: nsRenderingContext& aRC, michael@0: nsFrameList::Enumerator& aChildFrames, michael@0: nsIFrame * aParentFrame, michael@0: nsRect& aRect, michael@0: nsIFrame *& aStartFrame, michael@0: nsRect& aStartRect, michael@0: nsIFrame *& aEndFrame, michael@0: nsRect& aEndRect) michael@0: { michael@0: NS_ASSERTION(aPresContext, "Pointer is null!"); michael@0: NS_ASSERTION(aParentFrame, "Pointer is null!"); michael@0: michael@0: aRect += aParentFrame->GetPosition(); michael@0: for (; !aChildFrames.AtEnd(); aChildFrames.Next()) { michael@0: nsIFrame* child = aChildFrames.get(); michael@0: if (child->IsSelected() && child->IsVisibleForPainting()) { michael@0: nsRect r = child->GetRect(); michael@0: if (aStartFrame == nullptr) { michael@0: aStartFrame = child; michael@0: aStartRect.SetRect(aRect.x + r.x, aRect.y + r.y, r.width, r.height); michael@0: } else { michael@0: aEndFrame = child; michael@0: aEndRect.SetRect(aRect.x + r.x, aRect.y + r.y, r.width, r.height); michael@0: } michael@0: } michael@0: FindSelectionBounds(aPresContext, aRC, child, aRect, aStartFrame, aStartRect, aEndFrame, aEndRect); michael@0: child = child->GetNextSibling(); michael@0: } michael@0: aRect -= aParentFrame->GetPosition(); michael@0: return NS_OK; michael@0: } michael@0: michael@0: //------------------------------------------------------- michael@0: // Find the Frame that is XMost michael@0: nsresult michael@0: nsPrintEngine::FindSelectionBounds(nsPresContext* aPresContext, michael@0: nsRenderingContext& aRC, michael@0: nsIFrame * aParentFrame, michael@0: nsRect& aRect, michael@0: nsIFrame *& aStartFrame, michael@0: nsRect& aStartRect, michael@0: nsIFrame *& aEndFrame, michael@0: nsRect& aEndRect) michael@0: { michael@0: NS_ASSERTION(aPresContext, "Pointer is null!"); michael@0: NS_ASSERTION(aParentFrame, "Pointer is null!"); michael@0: michael@0: // loop through named child lists michael@0: nsIFrame::ChildListIterator lists(aParentFrame); michael@0: for (; !lists.IsDone(); lists.Next()) { michael@0: nsFrameList::Enumerator childFrames(lists.CurrentList()); michael@0: nsresult rv = FindSelectionBoundsWithList(aPresContext, aRC, childFrames, aParentFrame, aRect, aStartFrame, aStartRect, aEndFrame, aEndRect); michael@0: NS_ENSURE_SUCCESS(rv, rv); michael@0: } michael@0: return NS_OK; michael@0: } michael@0: michael@0: /** --------------------------------------------------- michael@0: * This method finds the starting and ending page numbers michael@0: * of the selection and also returns rect for each where michael@0: * the x,y of the rect is relative to the very top of the michael@0: * frame tree (absolutely positioned) michael@0: */ michael@0: nsresult michael@0: nsPrintEngine::GetPageRangeForSelection(nsIPresShell * aPresShell, michael@0: nsPresContext* aPresContext, michael@0: nsRenderingContext& aRC, michael@0: nsISelection* aSelection, michael@0: nsIPageSequenceFrame* aPageSeqFrame, michael@0: nsIFrame** aStartFrame, michael@0: int32_t& aStartPageNum, michael@0: nsRect& aStartRect, michael@0: nsIFrame** aEndFrame, michael@0: int32_t& aEndPageNum, michael@0: nsRect& aEndRect) michael@0: { michael@0: NS_ASSERTION(aPresShell, "Pointer is null!"); michael@0: NS_ASSERTION(aPresContext, "Pointer is null!"); michael@0: NS_ASSERTION(aSelection, "Pointer is null!"); michael@0: NS_ASSERTION(aPageSeqFrame, "Pointer is null!"); michael@0: NS_ASSERTION(aStartFrame, "Pointer is null!"); michael@0: NS_ASSERTION(aEndFrame, "Pointer is null!"); michael@0: michael@0: nsIFrame * seqFrame = do_QueryFrame(aPageSeqFrame); michael@0: if (!seqFrame) { michael@0: return NS_ERROR_FAILURE; michael@0: } michael@0: michael@0: nsIFrame * startFrame = nullptr; michael@0: nsIFrame * endFrame = nullptr; michael@0: michael@0: // start out with the sequence frame and search the entire frame tree michael@0: // capturing the starting and ending child frames of the selection michael@0: // and their rects michael@0: nsRect r = seqFrame->GetRect(); michael@0: FindSelectionBounds(aPresContext, aRC, seqFrame, r, michael@0: startFrame, aStartRect, endFrame, aEndRect); michael@0: michael@0: #ifdef DEBUG_rodsX michael@0: printf("Start Frame: %p\n", startFrame); michael@0: printf("End Frame: %p\n", endFrame); michael@0: #endif michael@0: michael@0: // initial the page numbers here michael@0: // in case we don't find and frames michael@0: aStartPageNum = -1; michael@0: aEndPageNum = -1; michael@0: michael@0: nsIFrame * startPageFrame; michael@0: nsIFrame * endPageFrame; michael@0: michael@0: // check to make sure we found a starting frame michael@0: if (startFrame != nullptr) { michael@0: // Now search up the tree to find what page the michael@0: // start/ending selections frames are on michael@0: // michael@0: // Check to see if start should be same as end if michael@0: // the end frame comes back null michael@0: if (endFrame == nullptr) { michael@0: // XXX the "GetPageFrame" step could be integrated into michael@0: // the FindSelectionBounds step, but walking up to find michael@0: // the parent of a child frame isn't expensive and it makes michael@0: // FindSelectionBounds a little easier to understand michael@0: startPageFrame = nsLayoutUtils::GetPageFrame(startFrame); michael@0: endPageFrame = startPageFrame; michael@0: aEndRect = aStartRect; michael@0: } else { michael@0: startPageFrame = nsLayoutUtils::GetPageFrame(startFrame); michael@0: endPageFrame = nsLayoutUtils::GetPageFrame(endFrame); michael@0: } michael@0: } else { michael@0: return NS_ERROR_FAILURE; michael@0: } michael@0: michael@0: #ifdef DEBUG_rodsX michael@0: printf("Start Page: %p\n", startPageFrame); michael@0: printf("End Page: %p\n", endPageFrame); michael@0: michael@0: // dump all the pages and their pointers michael@0: { michael@0: int32_t pageNum = 1; michael@0: nsIFrame* child = seqFrame->GetFirstPrincipalChild(); michael@0: while (child != nullptr) { michael@0: printf("Page: %d - %p\n", pageNum, child); michael@0: pageNum++; michael@0: child = child->GetNextSibling(); michael@0: } michael@0: } michael@0: #endif michael@0: michael@0: // Now that we have the page frames michael@0: // find out what the page numbers are for each frame michael@0: int32_t pageNum = 1; michael@0: nsIFrame* page = seqFrame->GetFirstPrincipalChild(); michael@0: while (page != nullptr) { michael@0: if (page == startPageFrame) { michael@0: aStartPageNum = pageNum; michael@0: } michael@0: if (page == endPageFrame) { michael@0: aEndPageNum = pageNum; michael@0: } michael@0: pageNum++; michael@0: page = page->GetNextSibling(); michael@0: } michael@0: michael@0: #ifdef DEBUG_rodsX michael@0: printf("Start Page No: %d\n", aStartPageNum); michael@0: printf("End Page No: %d\n", aEndPageNum); michael@0: #endif michael@0: michael@0: *aStartFrame = startPageFrame; michael@0: *aEndFrame = endPageFrame; michael@0: michael@0: return NS_OK; michael@0: } michael@0: michael@0: //----------------------------------------------------------------- michael@0: //-- Done: Printing Methods michael@0: //----------------------------------------------------------------- michael@0: michael@0: michael@0: //----------------------------------------------------------------- michael@0: //-- Section: Misc Support Methods michael@0: //----------------------------------------------------------------- michael@0: michael@0: //--------------------------------------------------------------------- michael@0: void nsPrintEngine::SetIsPrinting(bool aIsPrinting) michael@0: { michael@0: mIsDoingPrinting = aIsPrinting; michael@0: // Calling SetIsPrinting while in print preview confuses the document viewer michael@0: // This is safe because we prevent exiting print preview while printing michael@0: if (!mIsDoingPrintPreview && mDocViewerPrint) { michael@0: mDocViewerPrint->SetIsPrinting(aIsPrinting); michael@0: } michael@0: if (mPrt && aIsPrinting) { michael@0: mPrt->mPreparingForPrint = true; michael@0: } michael@0: } michael@0: michael@0: //--------------------------------------------------------------------- michael@0: void nsPrintEngine::SetIsPrintPreview(bool aIsPrintPreview) michael@0: { michael@0: mIsDoingPrintPreview = aIsPrintPreview; michael@0: michael@0: if (mDocViewerPrint) { michael@0: mDocViewerPrint->SetIsPrintPreview(aIsPrintPreview); michael@0: } michael@0: } michael@0: michael@0: //--------------------------------------------------------------------- michael@0: void michael@0: nsPrintEngine::CleanupDocTitleArray(char16_t**& aArray, int32_t& aCount) michael@0: { michael@0: for (int32_t i = aCount - 1; i >= 0; i--) { michael@0: nsMemory::Free(aArray[i]); michael@0: } michael@0: nsMemory::Free(aArray); michael@0: aArray = nullptr; michael@0: aCount = 0; michael@0: } michael@0: michael@0: //--------------------------------------------------------------------- michael@0: // static michael@0: bool nsPrintEngine::HasFramesetChild(nsIContent* aContent) michael@0: { michael@0: if (!aContent) { michael@0: return false; michael@0: } michael@0: michael@0: // do a breadth search across all siblings michael@0: for (nsIContent* child = aContent->GetFirstChild(); michael@0: child; michael@0: child = child->GetNextSibling()) { michael@0: if (child->IsHTML(nsGkAtoms::frameset)) { michael@0: return true; michael@0: } michael@0: } michael@0: michael@0: return false; michael@0: } michael@0: michael@0: michael@0: michael@0: /** --------------------------------------------------- michael@0: * Get the Focused Frame for a documentviewer michael@0: */ michael@0: already_AddRefed michael@0: nsPrintEngine::FindFocusedDOMWindow() michael@0: { michael@0: nsIFocusManager* fm = nsFocusManager::GetFocusManager(); michael@0: NS_ENSURE_TRUE(fm, nullptr); michael@0: michael@0: nsCOMPtr window(mDocument->GetWindow()); michael@0: NS_ENSURE_TRUE(window, nullptr); michael@0: michael@0: nsCOMPtr rootWindow = window->GetPrivateRoot(); michael@0: NS_ENSURE_TRUE(rootWindow, nullptr); michael@0: michael@0: nsCOMPtr focusedWindow; michael@0: nsFocusManager::GetFocusedDescendant(rootWindow, true, michael@0: getter_AddRefs(focusedWindow)); michael@0: NS_ENSURE_TRUE(focusedWindow, nullptr); michael@0: michael@0: if (IsWindowsInOurSubTree(focusedWindow)) { michael@0: return focusedWindow.forget(); michael@0: } michael@0: michael@0: return nullptr; michael@0: } michael@0: michael@0: //--------------------------------------------------------------------- michael@0: bool michael@0: nsPrintEngine::IsWindowsInOurSubTree(nsPIDOMWindow * window) michael@0: { michael@0: bool found = false; michael@0: michael@0: // now check to make sure it is in "our" tree of docshells michael@0: if (window) { michael@0: nsCOMPtr docShell = window->GetDocShell(); michael@0: michael@0: if (docShell) { michael@0: // get this DocViewer docshell michael@0: nsCOMPtr thisDVDocShell(do_QueryReferent(mContainer)); michael@0: while (!found) { michael@0: if (docShell) { michael@0: if (docShell == thisDVDocShell) { michael@0: found = true; michael@0: break; michael@0: } michael@0: } else { michael@0: break; // at top of tree michael@0: } michael@0: nsCOMPtr docShellItemParent; michael@0: docShell->GetSameTypeParent(getter_AddRefs(docShellItemParent)); michael@0: docShell = do_QueryInterface(docShellItemParent); michael@0: } // while michael@0: } michael@0: } // scriptobj michael@0: michael@0: return found; michael@0: } michael@0: michael@0: //------------------------------------------------------- michael@0: bool michael@0: nsPrintEngine::DonePrintingPages(nsPrintObject* aPO, nsresult aResult) michael@0: { michael@0: //NS_ASSERTION(aPO, "Pointer is null!"); michael@0: PR_PL(("****** In DV::DonePrintingPages PO: %p (%s)\n", aPO, aPO?gFrameTypesStr[aPO->mFrameType]:"")); michael@0: michael@0: // If there is a pageSeqFrame, make sure there are no more printCanvas active michael@0: // that might call |Notify| on the pagePrintTimer after things are cleaned up michael@0: // and printing was marked as being done. michael@0: if (mPageSeqFrame) { michael@0: mPageSeqFrame->ResetPrintCanvasList(); michael@0: } michael@0: michael@0: if (aPO && !mPrt->mIsAborted) { michael@0: aPO->mHasBeenPrinted = true; michael@0: nsresult rv; michael@0: bool didPrint = PrintDocContent(mPrt->mPrintObject, rv); michael@0: if (NS_SUCCEEDED(rv) && didPrint) { michael@0: PR_PL(("****** In DV::DonePrintingPages PO: %p (%s) didPrint:%s (Not Done Printing)\n", aPO, gFrameTypesStr[aPO->mFrameType], PRT_YESNO(didPrint))); michael@0: return false; michael@0: } michael@0: } michael@0: michael@0: if (NS_SUCCEEDED(aResult)) { michael@0: FirePrintCompletionEvent(); michael@0: } michael@0: michael@0: TurnScriptingOn(true); michael@0: SetIsPrinting(false); michael@0: michael@0: // Release reference to mPagePrintTimer; the timer object destroys itself michael@0: // after this returns true michael@0: NS_IF_RELEASE(mPagePrintTimer); michael@0: michael@0: return true; michael@0: } michael@0: michael@0: //------------------------------------------------------- michael@0: // Recursively sets the PO items to be printed "As Is" michael@0: // from the given item down into the tree michael@0: void michael@0: nsPrintEngine::SetPrintAsIs(nsPrintObject* aPO, bool aAsIs) michael@0: { michael@0: NS_ASSERTION(aPO, "Pointer is null!"); michael@0: michael@0: aPO->mPrintAsIs = aAsIs; michael@0: for (uint32_t i=0;imKids.Length();i++) { michael@0: SetPrintAsIs(aPO->mKids[i], aAsIs); michael@0: } michael@0: } michael@0: michael@0: //------------------------------------------------------- michael@0: // Given a DOMWindow it recursively finds the PO object that matches michael@0: nsPrintObject* michael@0: nsPrintEngine::FindPrintObjectByDOMWin(nsPrintObject* aPO, michael@0: nsIDOMWindow* aDOMWin) michael@0: { michael@0: NS_ASSERTION(aPO, "Pointer is null!"); michael@0: michael@0: // Often the CurFocused DOMWindow is passed in michael@0: // andit is valid for it to be null, so short circut michael@0: if (!aDOMWin) { michael@0: return nullptr; michael@0: } michael@0: michael@0: nsCOMPtr domDoc; michael@0: aDOMWin->GetDocument(getter_AddRefs(domDoc)); michael@0: nsCOMPtr doc = do_QueryInterface(domDoc); michael@0: if (aPO->mDocument && aPO->mDocument->GetOriginalDocument() == doc) { michael@0: return aPO; michael@0: } michael@0: michael@0: int32_t cnt = aPO->mKids.Length(); michael@0: for (int32_t i = 0; i < cnt; ++i) { michael@0: nsPrintObject* po = FindPrintObjectByDOMWin(aPO->mKids[i], aDOMWin); michael@0: if (po) { michael@0: return po; michael@0: } michael@0: } michael@0: michael@0: return nullptr; michael@0: } michael@0: michael@0: //------------------------------------------------------- michael@0: nsresult michael@0: nsPrintEngine::EnablePOsForPrinting() michael@0: { michael@0: // NOTE: All POs have been "turned off" for printing michael@0: // this is where we decided which POs get printed. michael@0: mPrt->mSelectedPO = nullptr; michael@0: michael@0: if (mPrt->mPrintSettings == nullptr) { michael@0: return NS_ERROR_FAILURE; michael@0: } michael@0: michael@0: mPrt->mPrintFrameType = nsIPrintSettings::kNoFrames; michael@0: mPrt->mPrintSettings->GetPrintFrameType(&mPrt->mPrintFrameType); michael@0: michael@0: int16_t printHowEnable = nsIPrintSettings::kFrameEnableNone; michael@0: mPrt->mPrintSettings->GetHowToEnableFrameUI(&printHowEnable); michael@0: michael@0: int16_t printRangeType = nsIPrintSettings::kRangeAllPages; michael@0: mPrt->mPrintSettings->GetPrintRange(&printRangeType); michael@0: michael@0: PR_PL(("\n")); michael@0: PR_PL(("********* nsPrintEngine::EnablePOsForPrinting *********\n")); michael@0: PR_PL(("PrintFrameType: %s \n", gPrintFrameTypeStr[mPrt->mPrintFrameType])); michael@0: PR_PL(("HowToEnableFrameUI: %s \n", gFrameHowToEnableStr[printHowEnable])); michael@0: PR_PL(("PrintRange: %s \n", gPrintRangeStr[printRangeType])); michael@0: PR_PL(("----\n")); michael@0: michael@0: // ***** This is the ultimate override ***** michael@0: // if we are printing the selection (either an IFrame or selection range) michael@0: // then set the mPrintFrameType as if it were the selected frame michael@0: if (printRangeType == nsIPrintSettings::kRangeSelection) { michael@0: mPrt->mPrintFrameType = nsIPrintSettings::kSelectedFrame; michael@0: printHowEnable = nsIPrintSettings::kFrameEnableNone; michael@0: } michael@0: michael@0: // This tells us that the "Frame" UI has turned off, michael@0: // so therefore there are no FrameSets/Frames/IFrames to be printed michael@0: // michael@0: // This means there are not FrameSets, michael@0: // but the document could contain an IFrame michael@0: if (printHowEnable == nsIPrintSettings::kFrameEnableNone) { michael@0: michael@0: // Print all the pages or a sub range of pages michael@0: if (printRangeType == nsIPrintSettings::kRangeAllPages || michael@0: printRangeType == nsIPrintSettings::kRangeSpecifiedPageRange) { michael@0: SetPrintPO(mPrt->mPrintObject, true); michael@0: michael@0: // Set the children so they are PrinAsIs michael@0: // In this case, the children are probably IFrames michael@0: if (mPrt->mPrintObject->mKids.Length() > 0) { michael@0: for (uint32_t i=0;imPrintObject->mKids.Length();i++) { michael@0: nsPrintObject* po = mPrt->mPrintObject->mKids[i]; michael@0: NS_ASSERTION(po, "nsPrintObject can't be null!"); michael@0: SetPrintAsIs(po); michael@0: } michael@0: michael@0: // ***** Another override ***** michael@0: mPrt->mPrintFrameType = nsIPrintSettings::kFramesAsIs; michael@0: } michael@0: PR_PL(("PrintFrameType: %s \n", gPrintFrameTypeStr[mPrt->mPrintFrameType])); michael@0: PR_PL(("HowToEnableFrameUI: %s \n", gFrameHowToEnableStr[printHowEnable])); michael@0: PR_PL(("PrintRange: %s \n", gPrintRangeStr[printRangeType])); michael@0: return NS_OK; michael@0: } michael@0: michael@0: // This means we are either printed a selected IFrame or michael@0: // we are printing the current selection michael@0: if (printRangeType == nsIPrintSettings::kRangeSelection) { michael@0: michael@0: // If the currentFocusDOMWin can'r be null if something is selected michael@0: if (mPrt->mCurrentFocusWin) { michael@0: // Find the selected IFrame michael@0: nsPrintObject * po = FindPrintObjectByDOMWin(mPrt->mPrintObject, mPrt->mCurrentFocusWin); michael@0: if (po != nullptr) { michael@0: mPrt->mSelectedPO = po; michael@0: // Makes sure all of its children are be printed "AsIs" michael@0: SetPrintAsIs(po); michael@0: michael@0: // Now, only enable this POs (the selected PO) and all of its children michael@0: SetPrintPO(po, true); michael@0: michael@0: // check to see if we have a range selection, michael@0: // as oppose to a insert selection michael@0: // this means if the user just clicked on the IFrame then michael@0: // there will not be a selection so we want the entire page to print michael@0: // michael@0: // XXX this is sort of a hack right here to make the page michael@0: // not try to reposition itself when printing selection michael@0: nsCOMPtr domWin = michael@0: do_QueryInterface(po->mDocument->GetOriginalDocument()->GetWindow()); michael@0: if (!IsThereARangeSelection(domWin)) { michael@0: printRangeType = nsIPrintSettings::kRangeAllPages; michael@0: mPrt->mPrintSettings->SetPrintRange(printRangeType); michael@0: } michael@0: PR_PL(("PrintFrameType: %s \n", gPrintFrameTypeStr[mPrt->mPrintFrameType])); michael@0: PR_PL(("HowToEnableFrameUI: %s \n", gFrameHowToEnableStr[printHowEnable])); michael@0: PR_PL(("PrintRange: %s \n", gPrintRangeStr[printRangeType])); michael@0: return NS_OK; michael@0: } michael@0: } else { michael@0: for (uint32_t i=0;imPrintDocList.Length();i++) { michael@0: nsPrintObject* po = mPrt->mPrintDocList.ElementAt(i); michael@0: NS_ASSERTION(po, "nsPrintObject can't be null!"); michael@0: nsCOMPtr domWin = do_GetInterface(po->mDocShell); michael@0: if (IsThereARangeSelection(domWin)) { michael@0: mPrt->mCurrentFocusWin = domWin; michael@0: SetPrintPO(po, true); michael@0: break; michael@0: } michael@0: } michael@0: return NS_OK; michael@0: } michael@0: } michael@0: } michael@0: michael@0: // check to see if there is a selection when a FrameSet is present michael@0: if (printRangeType == nsIPrintSettings::kRangeSelection) { michael@0: // If the currentFocusDOMWin can'r be null if something is selected michael@0: if (mPrt->mCurrentFocusWin) { michael@0: // Find the selected IFrame michael@0: nsPrintObject * po = FindPrintObjectByDOMWin(mPrt->mPrintObject, mPrt->mCurrentFocusWin); michael@0: if (po != nullptr) { michael@0: mPrt->mSelectedPO = po; michael@0: // Makes sure all of its children are be printed "AsIs" michael@0: SetPrintAsIs(po); michael@0: michael@0: // Now, only enable this POs (the selected PO) and all of its children michael@0: SetPrintPO(po, true); michael@0: michael@0: // check to see if we have a range selection, michael@0: // as oppose to a insert selection michael@0: // this means if the user just clicked on the IFrame then michael@0: // there will not be a selection so we want the entire page to print michael@0: // michael@0: // XXX this is sort of a hack right here to make the page michael@0: // not try to reposition itself when printing selection michael@0: nsCOMPtr domWin = michael@0: do_QueryInterface(po->mDocument->GetOriginalDocument()->GetWindow()); michael@0: if (!IsThereARangeSelection(domWin)) { michael@0: printRangeType = nsIPrintSettings::kRangeAllPages; michael@0: mPrt->mPrintSettings->SetPrintRange(printRangeType); michael@0: } michael@0: PR_PL(("PrintFrameType: %s \n", gPrintFrameTypeStr[mPrt->mPrintFrameType])); michael@0: PR_PL(("HowToEnableFrameUI: %s \n", gFrameHowToEnableStr[printHowEnable])); michael@0: PR_PL(("PrintRange: %s \n", gPrintRangeStr[printRangeType])); michael@0: return NS_OK; michael@0: } michael@0: } michael@0: } michael@0: michael@0: // If we are printing "AsIs" then sets all the POs to be printed as is michael@0: if (mPrt->mPrintFrameType == nsIPrintSettings::kFramesAsIs) { michael@0: SetPrintAsIs(mPrt->mPrintObject); michael@0: SetPrintPO(mPrt->mPrintObject, true); michael@0: return NS_OK; michael@0: } michael@0: michael@0: // If we are printing the selected Frame then michael@0: // find that PO for that selected DOMWin and set it all of its michael@0: // children to be printed michael@0: if (mPrt->mPrintFrameType == nsIPrintSettings::kSelectedFrame) { michael@0: michael@0: if ((mPrt->mIsParentAFrameSet && mPrt->mCurrentFocusWin) || mPrt->mIsIFrameSelected) { michael@0: nsPrintObject * po = FindPrintObjectByDOMWin(mPrt->mPrintObject, mPrt->mCurrentFocusWin); michael@0: if (po != nullptr) { michael@0: mPrt->mSelectedPO = po; michael@0: // NOTE: Calling this sets the "po" and michael@0: // we don't want to do this for documents that have no children, michael@0: // because then the "DoEndPage" gets called and it shouldn't michael@0: if (po->mKids.Length() > 0) { michael@0: // Makes sure that itself, and all of its children are printed "AsIs" michael@0: SetPrintAsIs(po); michael@0: } michael@0: michael@0: // Now, only enable this POs (the selected PO) and all of its children michael@0: SetPrintPO(po, true); michael@0: } michael@0: } michael@0: return NS_OK; michael@0: } michael@0: michael@0: // If we are print each subdoc separately, michael@0: // then don't print any of the FraneSet Docs michael@0: if (mPrt->mPrintFrameType == nsIPrintSettings::kEachFrameSep) { michael@0: SetPrintPO(mPrt->mPrintObject, true); michael@0: int32_t cnt = mPrt->mPrintDocList.Length(); michael@0: for (int32_t i=0;imPrintDocList.ElementAt(i); michael@0: NS_ASSERTION(po, "nsPrintObject can't be null!"); michael@0: if (po->mFrameType == eFrameSet) { michael@0: po->mDontPrint = true; michael@0: } michael@0: } michael@0: } michael@0: michael@0: return NS_OK; michael@0: } michael@0: michael@0: //------------------------------------------------------- michael@0: // Return the nsPrintObject with that is XMost (The widest frameset frame) AND michael@0: // contains the XMost (widest) layout frame michael@0: nsPrintObject* michael@0: nsPrintEngine::FindSmallestSTF() michael@0: { michael@0: float smallestRatio = 1.0f; michael@0: nsPrintObject* smallestPO = nullptr; michael@0: michael@0: for (uint32_t i=0;imPrintDocList.Length();i++) { michael@0: nsPrintObject* po = mPrt->mPrintDocList.ElementAt(i); michael@0: NS_ASSERTION(po, "nsPrintObject can't be null!"); michael@0: if (po->mFrameType != eFrameSet && po->mFrameType != eIFrame) { michael@0: if (po->mShrinkRatio < smallestRatio) { michael@0: smallestRatio = po->mShrinkRatio; michael@0: smallestPO = po; michael@0: } michael@0: } michael@0: } michael@0: michael@0: #ifdef EXTENDED_DEBUG_PRINTING michael@0: if (smallestPO) printf("*PO: %p Type: %d %10.3f\n", smallestPO, smallestPO->mFrameType, smallestPO->mShrinkRatio); michael@0: #endif michael@0: return smallestPO; michael@0: } michael@0: michael@0: //------------------------------------------------------- michael@0: void michael@0: nsPrintEngine::TurnScriptingOn(bool aDoTurnOn) michael@0: { michael@0: if (mIsDoingPrinting && aDoTurnOn && mDocViewerPrint && michael@0: mDocViewerPrint->GetIsPrintPreview()) { michael@0: // We don't want to turn scripting on if print preview is shown still after michael@0: // printing. michael@0: return; michael@0: } michael@0: michael@0: nsPrintData* prt = mPrt; michael@0: #ifdef NS_PRINT_PREVIEW michael@0: if (!prt) { michael@0: prt = mPrtPreview; michael@0: } michael@0: #endif michael@0: if (!prt) { michael@0: return; michael@0: } michael@0: michael@0: NS_ASSERTION(mDocument, "We MUST have a document."); michael@0: // First, get the script global object from the document... michael@0: michael@0: for (uint32_t i=0;imPrintDocList.Length();i++) { michael@0: nsPrintObject* po = prt->mPrintDocList.ElementAt(i); michael@0: NS_ASSERTION(po, "nsPrintObject can't be null!"); michael@0: michael@0: nsIDocument* doc = po->mDocument; michael@0: if (!doc) { michael@0: continue; michael@0: } michael@0: michael@0: if (nsCOMPtr window = doc->GetInnerWindow()) { michael@0: nsCOMPtr go = do_QueryInterface(window); michael@0: NS_WARN_IF_FALSE(go && go->GetGlobalJSObject(), "Can't get global"); michael@0: nsresult propThere = NS_PROPTABLE_PROP_NOT_THERE; michael@0: doc->GetProperty(nsGkAtoms::scriptEnabledBeforePrintOrPreview, michael@0: &propThere); michael@0: if (aDoTurnOn) { michael@0: if (propThere != NS_PROPTABLE_PROP_NOT_THERE) { michael@0: doc->DeleteProperty(nsGkAtoms::scriptEnabledBeforePrintOrPreview); michael@0: if (go && go->GetGlobalJSObject()) { michael@0: xpc::Scriptability::Get(go->GetGlobalJSObject()).Unblock(); michael@0: } michael@0: window->ResumeTimeouts(false); michael@0: } michael@0: } else { michael@0: // Have to be careful, because people call us over and over again with michael@0: // aDoTurnOn == false. So don't set the property if it's already michael@0: // set, since in that case we'd set it to the wrong value. michael@0: if (propThere == NS_PROPTABLE_PROP_NOT_THERE) { michael@0: // Stash the current value of IsScriptEnabled on the document, so michael@0: // that layout code running in print preview doesn't get confused. michael@0: doc->SetProperty(nsGkAtoms::scriptEnabledBeforePrintOrPreview, michael@0: NS_INT32_TO_PTR(doc->IsScriptEnabled())); michael@0: if (go && go->GetGlobalJSObject()) { michael@0: xpc::Scriptability::Get(go->GetGlobalJSObject()).Block(); michael@0: } michael@0: window->SuspendTimeouts(1, false); michael@0: } michael@0: } michael@0: } michael@0: } michael@0: } michael@0: michael@0: //----------------------------------------------------------------- michael@0: //-- Done: Misc Support Methods michael@0: //----------------------------------------------------------------- michael@0: michael@0: michael@0: //----------------------------------------------------------------- michael@0: //-- Section: Finishing up or Cleaning up michael@0: //----------------------------------------------------------------- michael@0: michael@0: //----------------------------------------------------------------- michael@0: void michael@0: nsPrintEngine::CloseProgressDialog(nsIWebProgressListener* aWebProgressListener) michael@0: { michael@0: if (aWebProgressListener) { michael@0: aWebProgressListener->OnStateChange(nullptr, nullptr, nsIWebProgressListener::STATE_STOP|nsIWebProgressListener::STATE_IS_DOCUMENT, NS_OK); michael@0: } michael@0: } michael@0: michael@0: //----------------------------------------------------------------- michael@0: nsresult michael@0: nsPrintEngine::FinishPrintPreview() michael@0: { michael@0: nsresult rv = NS_OK; michael@0: michael@0: #ifdef NS_PRINT_PREVIEW michael@0: michael@0: if (!mPrt) { michael@0: /* we're already finished with print preview */ michael@0: return rv; michael@0: } michael@0: michael@0: rv = DocumentReadyForPrinting(); michael@0: michael@0: SetIsCreatingPrintPreview(false); michael@0: michael@0: /* cleaup on failure + notify user */ michael@0: if (NS_FAILED(rv)) { michael@0: /* cleanup done, let's fire-up an error dialog to notify the user michael@0: * what went wrong... michael@0: */ michael@0: mPrt->OnEndPrinting(); michael@0: TurnScriptingOn(true); michael@0: michael@0: return rv; michael@0: } michael@0: michael@0: // At this point we are done preparing everything michael@0: // before it is to be created michael@0: michael@0: michael@0: if (mIsDoingPrintPreview && mOldPrtPreview) { michael@0: delete mOldPrtPreview; michael@0: mOldPrtPreview = nullptr; michael@0: } michael@0: michael@0: michael@0: mPrt->OnEndPrinting(); michael@0: michael@0: // PrintPreview was built using the mPrt (code reuse) michael@0: // then we assign it over michael@0: mPrtPreview = mPrt; michael@0: mPrt = nullptr; michael@0: michael@0: #endif // NS_PRINT_PREVIEW michael@0: michael@0: return NS_OK; michael@0: } michael@0: michael@0: //----------------------------------------------------------------- michael@0: //-- Done: Finishing up or Cleaning up michael@0: //----------------------------------------------------------------- michael@0: michael@0: michael@0: /*=============== Timer Related Code ======================*/ michael@0: nsresult michael@0: nsPrintEngine::StartPagePrintTimer(nsPrintObject* aPO) michael@0: { michael@0: if (!mPagePrintTimer) { michael@0: // Get the delay time in between the printing of each page michael@0: // this gives the user more time to press cancel michael@0: int32_t printPageDelay = 50; michael@0: mPrt->mPrintSettings->GetPrintPageDelay(&printPageDelay); michael@0: michael@0: nsRefPtr timer = michael@0: new nsPagePrintTimer(this, mDocViewerPrint, printPageDelay); michael@0: timer.forget(&mPagePrintTimer); michael@0: } michael@0: michael@0: return mPagePrintTimer->Start(aPO); michael@0: } michael@0: michael@0: /*=============== nsIObserver Interface ======================*/ michael@0: NS_IMETHODIMP michael@0: nsPrintEngine::Observe(nsISupports *aSubject, const char *aTopic, const char16_t *aData) michael@0: { michael@0: nsresult rv = NS_ERROR_FAILURE; michael@0: michael@0: rv = InitPrintDocConstruction(true); michael@0: if (!mIsDoingPrinting && mPrtPreview) { michael@0: mPrtPreview->OnEndPrinting(); michael@0: } michael@0: michael@0: return rv; michael@0: michael@0: } michael@0: michael@0: //--------------------------------------------------------------- michael@0: //-- PLEvent Notification michael@0: //--------------------------------------------------------------- michael@0: class nsPrintCompletionEvent : public nsRunnable { michael@0: public: michael@0: nsPrintCompletionEvent(nsIDocumentViewerPrint *docViewerPrint) michael@0: : mDocViewerPrint(docViewerPrint) { michael@0: NS_ASSERTION(mDocViewerPrint, "mDocViewerPrint is null."); michael@0: } michael@0: michael@0: NS_IMETHOD Run() MOZ_OVERRIDE { michael@0: if (mDocViewerPrint) michael@0: mDocViewerPrint->OnDonePrinting(); michael@0: return NS_OK; michael@0: } michael@0: michael@0: private: michael@0: nsCOMPtr mDocViewerPrint; michael@0: }; michael@0: michael@0: //----------------------------------------------------------- michael@0: void michael@0: nsPrintEngine::FirePrintCompletionEvent() michael@0: { michael@0: nsCOMPtr event = new nsPrintCompletionEvent(mDocViewerPrint); michael@0: if (NS_FAILED(NS_DispatchToCurrentThread(event))) michael@0: NS_WARNING("failed to dispatch print completion event"); michael@0: } michael@0: michael@0: //--------------------------------------------------------------- michael@0: //--------------------------------------------------------------- michael@0: //-- Debug helper routines michael@0: //--------------------------------------------------------------- michael@0: //--------------------------------------------------------------- michael@0: #if defined(XP_WIN) && defined(EXTENDED_DEBUG_PRINTING) michael@0: #include "windows.h" michael@0: #include "process.h" michael@0: #include "direct.h" michael@0: michael@0: #define MY_FINDFIRST(a,b) FindFirstFile(a,b) michael@0: #define MY_FINDNEXT(a,b) FindNextFile(a,b) michael@0: #define ISDIR(a) (a.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) michael@0: #define MY_FINDCLOSE(a) FindClose(a) michael@0: #define MY_FILENAME(a) a.cFileName michael@0: #define MY_FILESIZE(a) (a.nFileSizeHigh * MAXDWORD) + a.nFileSizeLow michael@0: michael@0: int RemoveFilesInDir(const char * aDir) michael@0: { michael@0: WIN32_FIND_DATA data_ptr; michael@0: HANDLE find_handle; michael@0: michael@0: char path[MAX_PATH]; michael@0: michael@0: strcpy(path, aDir); michael@0: michael@0: // Append slash to the end of the directory names if not there michael@0: if (path[strlen(path)-1] != '\\') michael@0: strcat(path, "\\"); michael@0: michael@0: char findPath[MAX_PATH]; michael@0: strcpy(findPath, path); michael@0: strcat(findPath, "*.*"); michael@0: michael@0: find_handle = MY_FINDFIRST(findPath, &data_ptr); michael@0: michael@0: if (find_handle != INVALID_HANDLE_VALUE) { michael@0: do { michael@0: if (ISDIR(data_ptr) michael@0: && (stricmp(MY_FILENAME(data_ptr),".")) michael@0: && (stricmp(MY_FILENAME(data_ptr),".."))) { michael@0: // skip michael@0: } michael@0: else if (!ISDIR(data_ptr)) { michael@0: if (!strncmp(MY_FILENAME(data_ptr), "print_dump", 10)) { michael@0: char fileName[MAX_PATH]; michael@0: strcpy(fileName, aDir); michael@0: strcat(fileName, "\\"); michael@0: strcat(fileName, MY_FILENAME(data_ptr)); michael@0: printf("Removing %s\n", fileName); michael@0: remove(fileName); michael@0: } michael@0: } michael@0: } while(MY_FINDNEXT(find_handle,&data_ptr)); michael@0: MY_FINDCLOSE(find_handle); michael@0: } michael@0: return TRUE; michael@0: } michael@0: #endif michael@0: michael@0: #ifdef EXTENDED_DEBUG_PRINTING michael@0: michael@0: /** --------------------------------------------------- michael@0: * Dumps Frames for Printing michael@0: */ michael@0: static void RootFrameList(nsPresContext* aPresContext, FILE* out, int32_t aIndent) michael@0: { michael@0: if (!aPresContext || !out) michael@0: return; michael@0: michael@0: nsIPresShell *shell = aPresContext->GetPresShell(); michael@0: if (shell) { michael@0: nsIFrame* frame = shell->FrameManager()->GetRootFrame(); michael@0: if (frame) { michael@0: frame->List(aPresContext, out, aIndent); michael@0: } michael@0: } michael@0: } michael@0: michael@0: /** --------------------------------------------------- michael@0: * Dumps Frames for Printing michael@0: */ michael@0: static void DumpFrames(FILE* out, michael@0: nsPresContext* aPresContext, michael@0: nsRenderingContext * aRendContext, michael@0: nsIFrame * aFrame, michael@0: int32_t aLevel) michael@0: { michael@0: NS_ASSERTION(out, "Pointer is null!"); michael@0: NS_ASSERTION(aPresContext, "Pointer is null!"); michael@0: NS_ASSERTION(aRendContext, "Pointer is null!"); michael@0: NS_ASSERTION(aFrame, "Pointer is null!"); michael@0: michael@0: nsIFrame* child = aFrame->GetFirstPrincipalChild(); michael@0: while (child != nullptr) { michael@0: for (int32_t i=0;iGetFrameName(tmp); michael@0: fputs(NS_LossyConvertUTF16toASCII(tmp).get(), out); michael@0: bool isSelected; michael@0: if (NS_SUCCEEDED(child->IsVisibleForPainting(aPresContext, *aRendContext, true, &isSelected))) { michael@0: fprintf(out, " %p %s", child, isSelected?"VIS":"UVS"); michael@0: nsRect rect = child->GetRect(); michael@0: fprintf(out, "[%d,%d,%d,%d] ", rect.x, rect.y, rect.width, rect.height); michael@0: fprintf(out, "v: %p ", (void*)child->GetView()); michael@0: fprintf(out, "\n"); michael@0: DumpFrames(out, aPresContext, aRendContext, child, aLevel+1); michael@0: child = child->GetNextSibling(); michael@0: } michael@0: } michael@0: } michael@0: michael@0: michael@0: /** --------------------------------------------------- michael@0: * Dumps the Views from the DocShell michael@0: */ michael@0: static void michael@0: DumpViews(nsIDocShell* aDocShell, FILE* out) michael@0: { michael@0: NS_ASSERTION(aDocShell, "Pointer is null!"); michael@0: NS_ASSERTION(out, "Pointer is null!"); michael@0: michael@0: if (nullptr != aDocShell) { michael@0: fprintf(out, "docshell=%p \n", aDocShell); michael@0: nsIPresShell* shell = nsPrintEngine::GetPresShellFor(aDocShell); michael@0: if (shell) { michael@0: nsViewManager* vm = shell->GetViewManager(); michael@0: if (vm) { michael@0: nsView* root = vm->GetRootView(); michael@0: if (root) { michael@0: root->List(out); michael@0: } michael@0: } michael@0: } michael@0: else { michael@0: fputs("null pres shell\n", out); michael@0: } michael@0: michael@0: // dump the views of the sub documents michael@0: int32_t i, n; michael@0: aDocShell->GetChildCount(&n); michael@0: for (i = 0; i < n; i++) { michael@0: nsCOMPtr child; michael@0: aDocShell->GetChildAt(i, getter_AddRefs(child)); michael@0: nsCOMPtr childAsShell(do_QueryInterface(child)); michael@0: if (childAsShell) { michael@0: DumpViews(childAsShell, out); michael@0: } michael@0: } michael@0: } michael@0: } michael@0: michael@0: /** --------------------------------------------------- michael@0: * Dumps the Views and Frames michael@0: */ michael@0: void DumpLayoutData(char* aTitleStr, michael@0: char* aURLStr, michael@0: nsPresContext* aPresContext, michael@0: nsDeviceContext * aDC, michael@0: nsIFrame * aRootFrame, michael@0: nsIDocShekk * aDocShell, michael@0: FILE* aFD = nullptr) michael@0: { michael@0: if (!kPrintingLogMod || kPrintingLogMod->level != DUMP_LAYOUT_LEVEL) return; michael@0: michael@0: if (aPresContext == nullptr || aDC == nullptr) { michael@0: return; michael@0: } michael@0: michael@0: #ifdef NS_PRINT_PREVIEW michael@0: if (aPresContext->Type() == nsPresContext::eContext_PrintPreview) { michael@0: return; michael@0: } michael@0: #endif michael@0: michael@0: NS_ASSERTION(aRootFrame, "Pointer is null!"); michael@0: NS_ASSERTION(aDocShell, "Pointer is null!"); michael@0: michael@0: // Dump all the frames and view to a a file michael@0: char filename[256]; michael@0: sprintf(filename, "print_dump_layout_%d.txt", gDumpLOFileNameCnt++); michael@0: FILE * fd = aFD?aFD:fopen(filename, "w"); michael@0: if (fd) { michael@0: fprintf(fd, "Title: %s\n", aTitleStr?aTitleStr:""); michael@0: fprintf(fd, "URL: %s\n", aURLStr?aURLStr:""); michael@0: fprintf(fd, "--------------- Frames ----------------\n"); michael@0: fprintf(fd, "--------------- Frames ----------------\n"); michael@0: nsRefPtr renderingContext = michael@0: aDC->CreateRenderingContext(); michael@0: RootFrameList(aPresContext, fd, 0); michael@0: //DumpFrames(fd, aPresContext, renderingContext, aRootFrame, 0); michael@0: fprintf(fd, "---------------------------------------\n\n"); michael@0: fprintf(fd, "--------------- Views From Root Frame----------------\n"); michael@0: nsView* v = aRootFrame->GetView(); michael@0: if (v) { michael@0: v->List(fd); michael@0: } else { michael@0: printf("View is null!\n"); michael@0: } michael@0: if (aDocShell) { michael@0: fprintf(fd, "--------------- All Views ----------------\n"); michael@0: DumpViews(aDocShell, fd); michael@0: fprintf(fd, "---------------------------------------\n\n"); michael@0: } michael@0: if (aFD == nullptr) { michael@0: fclose(fd); michael@0: } michael@0: } michael@0: } michael@0: michael@0: //------------------------------------------------------------- michael@0: static void DumpPrintObjectsList(nsTArray * aDocList) michael@0: { michael@0: if (!kPrintingLogMod || kPrintingLogMod->level != DUMP_LAYOUT_LEVEL) return; michael@0: michael@0: NS_ASSERTION(aDocList, "Pointer is null!"); michael@0: michael@0: const char types[][3] = {"DC", "FR", "IF", "FS"}; michael@0: PR_PL(("Doc List\n***************************************************\n")); michael@0: PR_PL(("T P A H PO DocShell Seq Page Root Page# Rect\n")); michael@0: int32_t cnt = aDocList->Length(); michael@0: for (int32_t i=0;iElementAt(i); michael@0: NS_ASSERTION(po, "nsPrintObject can't be null!"); michael@0: nsIFrame* rootFrame = nullptr; michael@0: if (po->mPresShell) { michael@0: rootFrame = po->mPresShell->FrameManager()->GetRootFrame(); michael@0: while (rootFrame != nullptr) { michael@0: nsIPageSequenceFrame * sqf = do_QueryFrame(rootFrame); michael@0: if (sqf) { michael@0: break; michael@0: } michael@0: rootFrame = rootFrame->GetFirstPrincipalChild(); michael@0: } michael@0: } michael@0: michael@0: PR_PL(("%s %d %d %d %p %p %p %p %p %d %d,%d,%d,%d\n", types[po->mFrameType], michael@0: po->IsPrintable(), po->mPrintAsIs, po->mHasBeenPrinted, po, po->mDocShell.get(), po->mSeqFrame, michael@0: po->mPageFrame, rootFrame, po->mPageNum, po->mRect.x, po->mRect.y, po->mRect.width, po->mRect.height)); michael@0: } michael@0: } michael@0: michael@0: //------------------------------------------------------------- michael@0: static void DumpPrintObjectsTree(nsPrintObject * aPO, int aLevel, FILE* aFD) michael@0: { michael@0: if (!kPrintingLogMod || kPrintingLogMod->level != DUMP_LAYOUT_LEVEL) return; michael@0: michael@0: NS_ASSERTION(aPO, "Pointer is null!"); michael@0: michael@0: FILE * fd = aFD?aFD:stdout; michael@0: const char types[][3] = {"DC", "FR", "IF", "FS"}; michael@0: if (aLevel == 0) { michael@0: fprintf(fd, "DocTree\n***************************************************\n"); michael@0: fprintf(fd, "T PO DocShell Seq Page Page# Rect\n"); michael@0: } michael@0: int32_t cnt = aPO->mKids.Length(); michael@0: for (int32_t i=0;imKids.ElementAt(i); michael@0: NS_ASSERTION(po, "nsPrintObject can't be null!"); michael@0: for (int32_t k=0;kmFrameType], po, po->mDocShell.get(), po->mSeqFrame, michael@0: po->mPageFrame, po->mPageNum, po->mRect.x, po->mRect.y, po->mRect.width, po->mRect.height); michael@0: } michael@0: } michael@0: michael@0: //------------------------------------------------------------- michael@0: static void GetDocTitleAndURL(nsPrintObject* aPO, nsACString& aDocStr, nsACString& aURLStr) michael@0: { michael@0: nsAutoString docTitleStr; michael@0: nsAutoString docURLStr; michael@0: nsPrintEngine::GetDisplayTitleAndURL(aPO, michael@0: docTitleStr, docURLStr, michael@0: nsPrintEngine::eDocTitleDefURLDoc); michael@0: aDocStr = NS_ConvertUTF16toUTF8(docTitleStr); michael@0: aURLStr = NS_ConvertUTF16toUTF8(docURLStr); michael@0: } michael@0: michael@0: //------------------------------------------------------------- michael@0: static void DumpPrintObjectsTreeLayout(nsPrintObject * aPO, michael@0: nsDeviceContext * aDC, michael@0: int aLevel, FILE * aFD) michael@0: { michael@0: if (!kPrintingLogMod || kPrintingLogMod->level != DUMP_LAYOUT_LEVEL) return; michael@0: michael@0: NS_ASSERTION(aPO, "Pointer is null!"); michael@0: NS_ASSERTION(aDC, "Pointer is null!"); michael@0: michael@0: const char types[][3] = {"DC", "FR", "IF", "FS"}; michael@0: FILE * fd = nullptr; michael@0: if (aLevel == 0) { michael@0: fd = fopen("tree_layout.txt", "w"); michael@0: fprintf(fd, "DocTree\n***************************************************\n"); michael@0: fprintf(fd, "***************************************************\n"); michael@0: fprintf(fd, "T PO DocShell Seq Page Page# Rect\n"); michael@0: } else { michael@0: fd = aFD; michael@0: } michael@0: if (fd) { michael@0: nsIFrame* rootFrame = nullptr; michael@0: if (aPO->mPresShell) { michael@0: rootFrame = aPO->mPresShell->FrameManager()->GetRootFrame(); michael@0: } michael@0: for (int32_t k=0;kmFrameType], aPO, aPO->mDocShell.get(), aPO->mSeqFrame, michael@0: aPO->mPageFrame, aPO->mPageNum, aPO->mRect.x, aPO->mRect.y, aPO->mRect.width, aPO->mRect.height); michael@0: if (aPO->IsPrintable()) { michael@0: nsAutoCString docStr; michael@0: nsAutoCString urlStr; michael@0: GetDocTitleAndURL(aPO, docStr, urlStr); michael@0: DumpLayoutData(docStr.get(), urlStr.get(), aPO->mPresContext, aDC, rootFrame, aPO->mDocShell, fd); michael@0: } michael@0: fprintf(fd, "<***************************************************>\n"); michael@0: michael@0: int32_t cnt = aPO->mKids.Length(); michael@0: for (int32_t i=0;imKids.ElementAt(i); michael@0: NS_ASSERTION(po, "nsPrintObject can't be null!"); michael@0: DumpPrintObjectsTreeLayout(po, aDC, aLevel+1, fd); michael@0: } michael@0: } michael@0: if (aLevel == 0 && fd) { michael@0: fclose(fd); michael@0: } michael@0: } michael@0: michael@0: //------------------------------------------------------------- michael@0: static void DumpPrintObjectsListStart(const char * aStr, nsTArray * aDocList) michael@0: { michael@0: if (!kPrintingLogMod || kPrintingLogMod->level != DUMP_LAYOUT_LEVEL) return; michael@0: michael@0: NS_ASSERTION(aStr, "Pointer is null!"); michael@0: NS_ASSERTION(aDocList, "Pointer is null!"); michael@0: michael@0: PR_PL(("%s\n", aStr)); michael@0: DumpPrintObjectsList(aDocList); michael@0: } michael@0: michael@0: #define DUMP_DOC_LIST(_title) DumpPrintObjectsListStart((_title), mPrt->mPrintDocList); michael@0: #define DUMP_DOC_TREE DumpPrintObjectsTree(mPrt->mPrintObject); michael@0: #define DUMP_DOC_TREELAYOUT DumpPrintObjectsTreeLayout(mPrt->mPrintObject, mPrt->mPrintDC); michael@0: michael@0: #else michael@0: #define DUMP_DOC_LIST(_title) michael@0: #define DUMP_DOC_TREE michael@0: #define DUMP_DOC_TREELAYOUT michael@0: #endif michael@0: michael@0: //--------------------------------------------------------------- michael@0: //--------------------------------------------------------------- michael@0: //-- End of debug helper routines michael@0: //---------------------------------------------------------------