layout/printing/nsPrintEngine.cpp

changeset 0
6474c204b198
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/layout/printing/nsPrintEngine.cpp	Wed Dec 31 06:09:35 2014 +0100
     1.3 @@ -0,0 +1,3977 @@
     1.4 +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
     1.5 +/* This Source Code Form is subject to the terms of the Mozilla Public
     1.6 + * License, v. 2.0. If a copy of the MPL was not distributed with this
     1.7 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
     1.8 +
     1.9 +#include "nsPrintEngine.h"
    1.10 +
    1.11 +#include "nsIStringBundle.h"
    1.12 +#include "nsReadableUtils.h"
    1.13 +#include "nsCRT.h"
    1.14 +
    1.15 +#include "mozilla/AsyncEventDispatcher.h"
    1.16 +#include "mozilla/dom/Selection.h"
    1.17 +#include "nsIScriptGlobalObject.h"
    1.18 +#include "nsPIDOMWindow.h"
    1.19 +#include "nsIDocShell.h"
    1.20 +#include "nsIFrame.h"
    1.21 +#include "nsIURI.h"
    1.22 +#include "nsITextToSubURI.h"
    1.23 +#include "nsError.h"
    1.24 +
    1.25 +#include "nsView.h"
    1.26 +#include <algorithm>
    1.27 +
    1.28 +// Print Options
    1.29 +#include "nsIPrintSettings.h"
    1.30 +#include "nsIPrintSettingsService.h"
    1.31 +#include "nsIPrintOptions.h"
    1.32 +#include "nsIPrintSession.h"
    1.33 +#include "nsGfxCIID.h"
    1.34 +#include "nsIServiceManager.h"
    1.35 +#include "nsGkAtoms.h"
    1.36 +#include "nsXPCOM.h"
    1.37 +#include "nsISupportsPrimitives.h"
    1.38 +
    1.39 +static const char sPrintSettingsServiceContractID[] = "@mozilla.org/gfx/printsettings-service;1";
    1.40 +
    1.41 +// Printing Events
    1.42 +#include "nsPrintPreviewListener.h"
    1.43 +#include "nsThreadUtils.h"
    1.44 +
    1.45 +// Printing
    1.46 +#include "nsIWebBrowserPrint.h"
    1.47 +#include "nsIDOMHTMLFrameElement.h"
    1.48 +#include "nsIDOMHTMLFrameSetElement.h"
    1.49 +#include "nsIDOMHTMLIFrameElement.h"
    1.50 +#include "nsIDOMHTMLObjectElement.h"
    1.51 +#include "nsIDOMHTMLEmbedElement.h"
    1.52 +
    1.53 +// Print Preview
    1.54 +#include "imgIContainer.h" // image animation mode constants
    1.55 +#include "nsIWebBrowserPrint.h" // needed for PrintPreview Navigation constants
    1.56 +
    1.57 +// Print Progress
    1.58 +#include "nsIPrintProgress.h"
    1.59 +#include "nsIPrintProgressParams.h"
    1.60 +#include "nsIObserver.h"
    1.61 +
    1.62 +// Print error dialog
    1.63 +#include "nsIPrompt.h"
    1.64 +#include "nsIWindowWatcher.h"
    1.65 +
    1.66 +// Printing Prompts
    1.67 +#include "nsIPrintingPromptService.h"
    1.68 +static const char kPrintingPromptService[] = "@mozilla.org/embedcomp/printingprompt-service;1";
    1.69 +
    1.70 +// Printing Timer
    1.71 +#include "nsPagePrintTimer.h"
    1.72 +
    1.73 +// FrameSet
    1.74 +#include "nsIDocument.h"
    1.75 +
    1.76 +// Focus
    1.77 +#include "nsISelectionController.h"
    1.78 +
    1.79 +// Misc
    1.80 +#include "nsISupportsUtils.h"
    1.81 +#include "nsIScriptContext.h"
    1.82 +#include "nsIDOMDocument.h"
    1.83 +#include "nsISelectionListener.h"
    1.84 +#include "nsISelectionPrivate.h"
    1.85 +#include "nsIDOMRange.h"
    1.86 +#include "nsContentCID.h"
    1.87 +#include "nsLayoutCID.h"
    1.88 +#include "nsContentUtils.h"
    1.89 +#include "nsIPresShell.h"
    1.90 +#include "nsLayoutUtils.h"
    1.91 +#include "mozilla/Preferences.h"
    1.92 +
    1.93 +#include "nsWidgetsCID.h"
    1.94 +#include "nsIDeviceContextSpec.h"
    1.95 +#include "nsViewManager.h"
    1.96 +#include "nsView.h"
    1.97 +#include "nsRenderingContext.h"
    1.98 +
    1.99 +#include "nsIPageSequenceFrame.h"
   1.100 +#include "nsIURL.h"
   1.101 +#include "nsIContentViewerEdit.h"
   1.102 +#include "nsIContentViewerFile.h"
   1.103 +#include "nsIMarkupDocumentViewer.h"
   1.104 +#include "nsIInterfaceRequestor.h"
   1.105 +#include "nsIInterfaceRequestorUtils.h"
   1.106 +#include "nsIDocShellTreeOwner.h"
   1.107 +#include "nsIWebBrowserChrome.h"
   1.108 +#include "nsIBaseWindow.h"
   1.109 +#include "nsILayoutHistoryState.h"
   1.110 +#include "nsFrameManager.h"
   1.111 +#include "nsHTMLReflowState.h"
   1.112 +#include "nsIDOMHTMLAnchorElement.h"
   1.113 +#include "nsIDOMHTMLAreaElement.h"
   1.114 +#include "nsIDOMHTMLLinkElement.h"
   1.115 +#include "nsIDOMHTMLImageElement.h"
   1.116 +#include "nsIContentViewerContainer.h"
   1.117 +#include "nsIContentViewer.h"
   1.118 +#include "nsIDocumentViewerPrint.h"
   1.119 +
   1.120 +#include "nsFocusManager.h"
   1.121 +#include "nsRange.h"
   1.122 +#include "nsCDefaultURIFixup.h"
   1.123 +#include "nsIURIFixup.h"
   1.124 +#include "mozilla/dom/Element.h"
   1.125 +#include "nsContentList.h"
   1.126 +#include "nsIChannel.h"
   1.127 +#include "xpcpublic.h"
   1.128 +
   1.129 +using namespace mozilla;
   1.130 +using namespace mozilla::dom;
   1.131 +
   1.132 +//-----------------------------------------------------
   1.133 +// PR LOGGING
   1.134 +#ifdef MOZ_LOGGING
   1.135 +#define FORCE_PR_LOG /* Allow logging in the release build */
   1.136 +#endif
   1.137 +
   1.138 +#include "prlog.h"
   1.139 +
   1.140 +#ifdef PR_LOGGING
   1.141 +
   1.142 +#ifdef DEBUG
   1.143 +// PR_LOGGING is force to always be on (even in release builds)
   1.144 +// but we only want some of it on,
   1.145 +//#define EXTENDED_DEBUG_PRINTING 
   1.146 +#endif
   1.147 +
   1.148 +#define DUMP_LAYOUT_LEVEL 9 // this turns on the dumping of each doucment's layout info
   1.149 +
   1.150 +#ifndef PR_PL
   1.151 +static PRLogModuleInfo *
   1.152 +GetPrintingLog()
   1.153 +{
   1.154 +  static PRLogModuleInfo *sLog;
   1.155 +  if (!sLog)
   1.156 +    sLog = PR_NewLogModule("printing");
   1.157 +  return sLog;
   1.158 +}
   1.159 +#define PR_PL(_p1)  PR_LOG(GetPrintingLog(), PR_LOG_DEBUG, _p1);
   1.160 +#endif
   1.161 +
   1.162 +#ifdef EXTENDED_DEBUG_PRINTING
   1.163 +static uint32_t gDumpFileNameCnt   = 0;
   1.164 +static uint32_t gDumpLOFileNameCnt = 0;
   1.165 +#endif
   1.166 +
   1.167 +#define PRT_YESNO(_p) ((_p)?"YES":"NO")
   1.168 +static const char * gFrameTypesStr[]       = {"eDoc", "eFrame", "eIFrame", "eFrameSet"};
   1.169 +static const char * gPrintFrameTypeStr[]   = {"kNoFrames", "kFramesAsIs", "kSelectedFrame", "kEachFrameSep"};
   1.170 +static const char * gFrameHowToEnableStr[] = {"kFrameEnableNone", "kFrameEnableAll", "kFrameEnableAsIsAndEach"};
   1.171 +static const char * gPrintRangeStr[]       = {"kRangeAllPages", "kRangeSpecifiedPageRange", "kRangeSelection", "kRangeFocusFrame"};
   1.172 +#else
   1.173 +#define PRT_YESNO(_p)
   1.174 +#define PR_PL(_p1)
   1.175 +#endif
   1.176 +
   1.177 +#ifdef EXTENDED_DEBUG_PRINTING
   1.178 +// Forward Declarations
   1.179 +static void DumpPrintObjectsListStart(const char * aStr, nsTArray<nsPrintObject*> * aDocList);
   1.180 +static void DumpPrintObjectsTree(nsPrintObject * aPO, int aLevel= 0, FILE* aFD = nullptr);
   1.181 +static void DumpPrintObjectsTreeLayout(nsPrintObject * aPO,nsDeviceContext * aDC, int aLevel= 0, FILE * aFD = nullptr);
   1.182 +
   1.183 +#define DUMP_DOC_LIST(_title) DumpPrintObjectsListStart((_title), mPrt->mPrintDocList);
   1.184 +#define DUMP_DOC_TREE DumpPrintObjectsTree(mPrt->mPrintObject);
   1.185 +#define DUMP_DOC_TREELAYOUT DumpPrintObjectsTreeLayout(mPrt->mPrintObject, mPrt->mPrintDC);
   1.186 +#else
   1.187 +#define DUMP_DOC_LIST(_title)
   1.188 +#define DUMP_DOC_TREE
   1.189 +#define DUMP_DOC_TREELAYOUT
   1.190 +#endif
   1.191 +
   1.192 +class nsScriptSuppressor
   1.193 +{
   1.194 +public:
   1.195 +  nsScriptSuppressor(nsPrintEngine* aPrintEngine)
   1.196 +  : mPrintEngine(aPrintEngine), mSuppressed(false) {}
   1.197 +
   1.198 +  ~nsScriptSuppressor() { Unsuppress(); }
   1.199 +
   1.200 +  void Suppress()
   1.201 +  {
   1.202 +    if (mPrintEngine) {
   1.203 +      mSuppressed = true;
   1.204 +      mPrintEngine->TurnScriptingOn(false);
   1.205 +    }
   1.206 +  }
   1.207 +  
   1.208 +  void Unsuppress()
   1.209 +  {
   1.210 +    if (mPrintEngine && mSuppressed) {
   1.211 +      mPrintEngine->TurnScriptingOn(true);
   1.212 +    }
   1.213 +    mSuppressed = false;
   1.214 +  }
   1.215 +
   1.216 +  void Disconnect() { mPrintEngine = nullptr; }
   1.217 +protected:
   1.218 +  nsRefPtr<nsPrintEngine> mPrintEngine;
   1.219 +  bool                    mSuppressed;
   1.220 +};
   1.221 +
   1.222 +NS_IMPL_ISUPPORTS(nsPrintEngine, nsIWebProgressListener,
   1.223 +                  nsISupportsWeakReference, nsIObserver)
   1.224 +
   1.225 +//---------------------------------------------------
   1.226 +//-- nsPrintEngine Class Impl
   1.227 +//---------------------------------------------------
   1.228 +nsPrintEngine::nsPrintEngine() :
   1.229 +  mIsCreatingPrintPreview(false),
   1.230 +  mIsDoingPrinting(false),
   1.231 +  mIsDoingPrintPreview(false),
   1.232 +  mProgressDialogIsShown(false),
   1.233 +  mScreenDPI(115.0f),
   1.234 +  mPrt(nullptr),
   1.235 +  mPagePrintTimer(nullptr),
   1.236 +  mPageSeqFrame(nullptr),
   1.237 +  mPrtPreview(nullptr),
   1.238 +  mOldPrtPreview(nullptr),
   1.239 +  mDebugFile(nullptr),
   1.240 +  mLoadCounter(0),
   1.241 +  mDidLoadDataForPrinting(false),
   1.242 +  mIsDestroying(false),
   1.243 +  mDisallowSelectionPrint(false),
   1.244 +  mNoMarginBoxes(false)
   1.245 +{
   1.246 +}
   1.247 +
   1.248 +//-------------------------------------------------------
   1.249 +nsPrintEngine::~nsPrintEngine()
   1.250 +{
   1.251 +  Destroy(); // for insurance
   1.252 +}
   1.253 +
   1.254 +//-------------------------------------------------------
   1.255 +void nsPrintEngine::Destroy()
   1.256 +{
   1.257 +  if (mIsDestroying) {
   1.258 +    return;
   1.259 +  }
   1.260 +  mIsDestroying = true;
   1.261 +
   1.262 +  if (mPrt) {
   1.263 +    delete mPrt;
   1.264 +    mPrt = nullptr;
   1.265 +  }
   1.266 +
   1.267 +#ifdef NS_PRINT_PREVIEW
   1.268 +  if (mPrtPreview) {
   1.269 +    delete mPrtPreview;
   1.270 +    mPrtPreview = nullptr;
   1.271 +  }
   1.272 +
   1.273 +  // This is insruance
   1.274 +  if (mOldPrtPreview) {
   1.275 +    delete mOldPrtPreview;
   1.276 +    mOldPrtPreview = nullptr;
   1.277 +  }
   1.278 +
   1.279 +#endif
   1.280 +  mDocViewerPrint = nullptr;
   1.281 +}
   1.282 +
   1.283 +//-------------------------------------------------------
   1.284 +void nsPrintEngine::DestroyPrintingData()
   1.285 +{
   1.286 +  if (mPrt) {
   1.287 +    nsPrintData* data = mPrt;
   1.288 +    mPrt = nullptr;
   1.289 +    delete data;
   1.290 +  }
   1.291 +}
   1.292 +
   1.293 +//---------------------------------------------------------------------------------
   1.294 +//-- Section: Methods needed by the DocViewer
   1.295 +//---------------------------------------------------------------------------------
   1.296 +
   1.297 +//--------------------------------------------------------
   1.298 +nsresult nsPrintEngine::Initialize(nsIDocumentViewerPrint* aDocViewerPrint, 
   1.299 +                                   nsIDocShell*            aContainer,
   1.300 +                                   nsIDocument*            aDocument,
   1.301 +                                   float                   aScreenDPI,
   1.302 +                                   FILE*                   aDebugFile)
   1.303 +{
   1.304 +  NS_ENSURE_ARG_POINTER(aDocViewerPrint);
   1.305 +  NS_ENSURE_ARG_POINTER(aContainer);
   1.306 +  NS_ENSURE_ARG_POINTER(aDocument);
   1.307 +
   1.308 +  mDocViewerPrint = aDocViewerPrint;
   1.309 +  mContainer      = do_GetWeakReference(aContainer);
   1.310 +  mDocument       = aDocument;
   1.311 +  mScreenDPI      = aScreenDPI;
   1.312 +
   1.313 +  mDebugFile      = aDebugFile;      // ok to be nullptr
   1.314 +
   1.315 +  return NS_OK;
   1.316 +}
   1.317 +
   1.318 +//-------------------------------------------------------
   1.319 +bool
   1.320 +nsPrintEngine::CheckBeforeDestroy()
   1.321 +{
   1.322 +  if (mPrt && mPrt->mPreparingForPrint) {
   1.323 +    mPrt->mDocWasToBeDestroyed = true;
   1.324 +    return true;
   1.325 +  }
   1.326 +  return false;
   1.327 +}
   1.328 +
   1.329 +//-------------------------------------------------------
   1.330 +nsresult
   1.331 +nsPrintEngine::Cancelled()
   1.332 +{
   1.333 +  if (mPrt && mPrt->mPrintSettings) {
   1.334 +    return mPrt->mPrintSettings->SetIsCancelled(true);
   1.335 +  }
   1.336 +  return NS_ERROR_FAILURE;
   1.337 +}
   1.338 +
   1.339 +//-------------------------------------------------------
   1.340 +// Install our event listeners on the document to prevent 
   1.341 +// some events from being processed while in PrintPreview 
   1.342 +//
   1.343 +// No return code - if this fails, there isn't much we can do
   1.344 +void
   1.345 +nsPrintEngine::InstallPrintPreviewListener()
   1.346 +{
   1.347 +  if (!mPrt->mPPEventListeners) {
   1.348 +    nsCOMPtr<nsIDocShell> docShell = do_QueryReferent(mContainer);
   1.349 +    nsCOMPtr<nsPIDOMWindow> win(do_GetInterface(docShell));
   1.350 +    if (win) {
   1.351 +      nsCOMPtr<EventTarget> target = do_QueryInterface(win->GetFrameElementInternal());
   1.352 +      mPrt->mPPEventListeners = new nsPrintPreviewListener(target);
   1.353 +      mPrt->mPPEventListeners->AddListeners();
   1.354 +    }
   1.355 +  }
   1.356 +}
   1.357 +
   1.358 +//----------------------------------------------------------------------
   1.359 +nsresult 
   1.360 +nsPrintEngine::GetSeqFrameAndCountPagesInternal(nsPrintObject*  aPO,
   1.361 +                                                nsIFrame*&    aSeqFrame,
   1.362 +                                                int32_t&      aCount)
   1.363 +{
   1.364 +  NS_ENSURE_ARG_POINTER(aPO);
   1.365 +
   1.366 +  // Finds the SimplePageSequencer frame
   1.367 +  nsIPageSequenceFrame* seqFrame = aPO->mPresShell->GetPageSequenceFrame();
   1.368 +  aSeqFrame = do_QueryFrame(seqFrame);
   1.369 +  if (!aSeqFrame) {
   1.370 +    return NS_ERROR_FAILURE;
   1.371 +  }
   1.372 +
   1.373 +  // first count the total number of pages
   1.374 +  aCount = 0;
   1.375 +  nsIFrame* pageFrame = aSeqFrame->GetFirstPrincipalChild();
   1.376 +  while (pageFrame != nullptr) {
   1.377 +    aCount++;
   1.378 +    pageFrame = pageFrame->GetNextSibling();
   1.379 +  }
   1.380 +
   1.381 +  return NS_OK;
   1.382 +
   1.383 +}
   1.384 +
   1.385 +//-----------------------------------------------------------------
   1.386 +nsresult nsPrintEngine::GetSeqFrameAndCountPages(nsIFrame*& aSeqFrame, int32_t& aCount)
   1.387 +{
   1.388 +  NS_ASSERTION(mPrtPreview, "mPrtPreview can't be null!");
   1.389 +  return GetSeqFrameAndCountPagesInternal(mPrtPreview->mPrintObject, aSeqFrame, aCount);
   1.390 +}
   1.391 +//---------------------------------------------------------------------------------
   1.392 +//-- Done: Methods needed by the DocViewer
   1.393 +//---------------------------------------------------------------------------------
   1.394 +
   1.395 +
   1.396 +//---------------------------------------------------------------------------------
   1.397 +//-- Section: nsIWebBrowserPrint
   1.398 +//---------------------------------------------------------------------------------
   1.399 +
   1.400 +// Foward decl for Debug Helper Functions
   1.401 +#ifdef EXTENDED_DEBUG_PRINTING
   1.402 +static int RemoveFilesInDir(const char * aDir);
   1.403 +static void GetDocTitleAndURL(nsPrintObject* aPO, char *& aDocStr, char *& aURLStr);
   1.404 +static void DumpPrintObjectsTree(nsPrintObject * aPO, int aLevel, FILE* aFD);
   1.405 +static void DumpPrintObjectsList(nsTArray<nsPrintObject*> * aDocList);
   1.406 +static void RootFrameList(nsPresContext* aPresContext, FILE* out, int32_t aIndent);
   1.407 +static void DumpViews(nsIDocShell* aDocShell, FILE* out);
   1.408 +static void DumpLayoutData(char* aTitleStr, char* aURLStr,
   1.409 +                           nsPresContext* aPresContext,
   1.410 +                           nsDeviceContext * aDC, nsIFrame * aRootFrame,
   1.411 +                           nsIDocShell * aDocShell, FILE* aFD);
   1.412 +#endif
   1.413 +
   1.414 +//--------------------------------------------------------------------------------
   1.415 +
   1.416 +nsresult
   1.417 +nsPrintEngine::CommonPrint(bool                    aIsPrintPreview,
   1.418 +                           nsIPrintSettings*       aPrintSettings,
   1.419 +                           nsIWebProgressListener* aWebProgressListener,
   1.420 +                           nsIDOMDocument* aDoc) {
   1.421 +  nsRefPtr<nsPrintEngine> kungfuDeathGrip = this;
   1.422 +  nsresult rv = DoCommonPrint(aIsPrintPreview, aPrintSettings,
   1.423 +                              aWebProgressListener, aDoc);
   1.424 +  if (NS_FAILED(rv)) {
   1.425 +    if (aIsPrintPreview) {
   1.426 +      SetIsCreatingPrintPreview(false);
   1.427 +      SetIsPrintPreview(false);
   1.428 +    } else {
   1.429 +      SetIsPrinting(false);
   1.430 +    }
   1.431 +    if (mProgressDialogIsShown)
   1.432 +      CloseProgressDialog(aWebProgressListener);
   1.433 +    if (rv != NS_ERROR_ABORT && rv != NS_ERROR_OUT_OF_MEMORY)
   1.434 +      ShowPrintErrorDialog(rv, !aIsPrintPreview);
   1.435 +    delete mPrt;
   1.436 +    mPrt = nullptr;
   1.437 +  }
   1.438 +
   1.439 +  return rv;
   1.440 +}
   1.441 +
   1.442 +nsresult
   1.443 +nsPrintEngine::DoCommonPrint(bool                    aIsPrintPreview,
   1.444 +                             nsIPrintSettings*       aPrintSettings,
   1.445 +                             nsIWebProgressListener* aWebProgressListener,
   1.446 +                             nsIDOMDocument*         aDoc)
   1.447 +{
   1.448 +  nsresult rv;
   1.449 +
   1.450 +  if (aIsPrintPreview) {
   1.451 +    // The WebProgressListener can be QI'ed to nsIPrintingPromptService
   1.452 +    // then that means the progress dialog is already being shown.
   1.453 +    nsCOMPtr<nsIPrintingPromptService> pps(do_QueryInterface(aWebProgressListener));
   1.454 +    mProgressDialogIsShown = pps != nullptr;
   1.455 +
   1.456 +    if (mIsDoingPrintPreview) {
   1.457 +      mOldPrtPreview = mPrtPreview;
   1.458 +      mPrtPreview = nullptr;
   1.459 +    }
   1.460 +  } else {
   1.461 +    mProgressDialogIsShown = false;
   1.462 +  }
   1.463 +
   1.464 +  mPrt = new nsPrintData(aIsPrintPreview ? nsPrintData::eIsPrintPreview :
   1.465 +                                           nsPrintData::eIsPrinting);
   1.466 +  NS_ENSURE_TRUE(mPrt, NS_ERROR_OUT_OF_MEMORY);
   1.467 +
   1.468 +  // if they don't pass in a PrintSettings, then get the Global PS
   1.469 +  mPrt->mPrintSettings = aPrintSettings;
   1.470 +  if (!mPrt->mPrintSettings) {
   1.471 +    rv = GetGlobalPrintSettings(getter_AddRefs(mPrt->mPrintSettings));
   1.472 +    NS_ENSURE_SUCCESS(rv, rv);
   1.473 +  }
   1.474 +
   1.475 +  rv = CheckForPrinters(mPrt->mPrintSettings);
   1.476 +  NS_ENSURE_SUCCESS(rv, rv);
   1.477 +
   1.478 +  mPrt->mPrintSettings->SetIsCancelled(false);
   1.479 +  mPrt->mPrintSettings->GetShrinkToFit(&mPrt->mShrinkToFit);
   1.480 +
   1.481 +  // In the case the margin boxes are not printed store the print settings for
   1.482 +  // the footer/header to be used as default print setting for follow up prints.
   1.483 +  mPrt->mPrintSettings->SetPersistMarginBoxSettings(!mNoMarginBoxes);
   1.484 +
   1.485 +  if (mNoMarginBoxes) {
   1.486 +    // Set the footer/header to blank.
   1.487 +    const char16_t* emptyString = EmptyString().get();
   1.488 +    mPrt->mPrintSettings->SetHeaderStrLeft(emptyString);
   1.489 +    mPrt->mPrintSettings->SetHeaderStrCenter(emptyString);
   1.490 +    mPrt->mPrintSettings->SetHeaderStrRight(emptyString);
   1.491 +    mPrt->mPrintSettings->SetFooterStrLeft(emptyString);
   1.492 +    mPrt->mPrintSettings->SetFooterStrCenter(emptyString);
   1.493 +    mPrt->mPrintSettings->SetFooterStrRight(emptyString);
   1.494 +  }
   1.495 +
   1.496 +  if (aIsPrintPreview) {
   1.497 +    SetIsCreatingPrintPreview(true);
   1.498 +    SetIsPrintPreview(true);
   1.499 +    nsCOMPtr<nsIMarkupDocumentViewer> viewer =
   1.500 +      do_QueryInterface(mDocViewerPrint);
   1.501 +    if (viewer) {
   1.502 +      viewer->SetTextZoom(1.0f);
   1.503 +      viewer->SetFullZoom(1.0f);
   1.504 +      viewer->SetMinFontSize(0);
   1.505 +    }
   1.506 +  }
   1.507 +
   1.508 +  // Create a print session and let the print settings know about it.
   1.509 +  // The print settings hold an nsWeakPtr to the session so it does not
   1.510 +  // need to be cleared from the settings at the end of the job.
   1.511 +  // XXX What lifetime does the printSession need to have?
   1.512 +  nsCOMPtr<nsIPrintSession> printSession;
   1.513 +  if (!aIsPrintPreview) {
   1.514 +    printSession = do_CreateInstance("@mozilla.org/gfx/printsession;1", &rv);
   1.515 +    NS_ENSURE_SUCCESS(rv, rv);
   1.516 +    mPrt->mPrintSettings->SetPrintSession(printSession);
   1.517 +  }
   1.518 +
   1.519 +  if (aWebProgressListener != nullptr) {
   1.520 +    mPrt->mPrintProgressListeners.AppendObject(aWebProgressListener);
   1.521 +  }
   1.522 +
   1.523 +  // Get the currently focused window and cache it
   1.524 +  // because the Print Dialog will "steal" focus and later when you try
   1.525 +  // to get the currently focused windows it will be nullptr
   1.526 +  mPrt->mCurrentFocusWin = FindFocusedDOMWindow();
   1.527 +
   1.528 +  // Check to see if there is a "regular" selection
   1.529 +  bool isSelection = IsThereARangeSelection(mPrt->mCurrentFocusWin);
   1.530 +
   1.531 +  // Get the docshell for this documentviewer
   1.532 +  nsCOMPtr<nsIDocShell> webContainer(do_QueryReferent(mContainer, &rv));
   1.533 +  NS_ENSURE_SUCCESS(rv, rv);
   1.534 +
   1.535 +  {
   1.536 +    if (aIsPrintPreview) {
   1.537 +      nsCOMPtr<nsIContentViewer> viewer;
   1.538 +      webContainer->GetContentViewer(getter_AddRefs(viewer));
   1.539 +      if (viewer && viewer->GetDocument() && viewer->GetDocument()->IsShowing()) {
   1.540 +        viewer->GetDocument()->OnPageHide(false, nullptr);
   1.541 +      }
   1.542 +    }
   1.543 +
   1.544 +    nsAutoScriptBlocker scriptBlocker;
   1.545 +    mPrt->mPrintObject = new nsPrintObject();
   1.546 +    NS_ENSURE_TRUE(mPrt->mPrintObject, NS_ERROR_OUT_OF_MEMORY);
   1.547 +    rv = mPrt->mPrintObject->Init(webContainer, aDoc, aIsPrintPreview);
   1.548 +    NS_ENSURE_SUCCESS(rv, rv);
   1.549 +
   1.550 +    NS_ENSURE_TRUE(mPrt->mPrintDocList.AppendElement(mPrt->mPrintObject),
   1.551 +                   NS_ERROR_OUT_OF_MEMORY);
   1.552 +
   1.553 +    mPrt->mIsParentAFrameSet = IsParentAFrameSet(webContainer);
   1.554 +    mPrt->mPrintObject->mFrameType = mPrt->mIsParentAFrameSet ? eFrameSet : eDoc;
   1.555 +
   1.556 +    // Build the "tree" of PrintObjects
   1.557 +    BuildDocTree(mPrt->mPrintObject->mDocShell, &mPrt->mPrintDocList,
   1.558 +                 mPrt->mPrintObject);
   1.559 +  }
   1.560 +
   1.561 +  if (!aIsPrintPreview) {
   1.562 +    SetIsPrinting(true);
   1.563 +  }
   1.564 +
   1.565 +  // XXX This isn't really correct...
   1.566 +  if (!mPrt->mPrintObject->mDocument ||
   1.567 +      !mPrt->mPrintObject->mDocument->GetRootElement())
   1.568 +    return NS_ERROR_GFX_PRINTER_STARTDOC;
   1.569 +
   1.570 +  // Create the linkage from the sub-docs back to the content element
   1.571 +  // in the parent document
   1.572 +  MapContentToWebShells(mPrt->mPrintObject, mPrt->mPrintObject);
   1.573 +
   1.574 +  mPrt->mIsIFrameSelected = IsThereAnIFrameSelected(webContainer, mPrt->mCurrentFocusWin, mPrt->mIsParentAFrameSet);
   1.575 +
   1.576 +  // Setup print options for UI
   1.577 +  if (mPrt->mIsParentAFrameSet) {
   1.578 +    if (mPrt->mCurrentFocusWin) {
   1.579 +      mPrt->mPrintSettings->SetHowToEnableFrameUI(nsIPrintSettings::kFrameEnableAll);
   1.580 +    } else {
   1.581 +      mPrt->mPrintSettings->SetHowToEnableFrameUI(nsIPrintSettings::kFrameEnableAsIsAndEach);
   1.582 +    }
   1.583 +  } else {
   1.584 +    mPrt->mPrintSettings->SetHowToEnableFrameUI(nsIPrintSettings::kFrameEnableNone);
   1.585 +  }
   1.586 +  // Now determine how to set up the Frame print UI
   1.587 +  mPrt->mPrintSettings->SetPrintOptions(nsIPrintSettings::kEnableSelectionRB,
   1.588 +                                        isSelection || mPrt->mIsIFrameSelected);
   1.589 +
   1.590 +  nsCOMPtr<nsIDeviceContextSpec> devspec
   1.591 +    (do_CreateInstance("@mozilla.org/gfx/devicecontextspec;1", &rv));
   1.592 +  NS_ENSURE_SUCCESS(rv, rv);
   1.593 +
   1.594 +  nsScriptSuppressor scriptSuppressor(this);
   1.595 +  if (!aIsPrintPreview) {
   1.596 +#ifdef DEBUG
   1.597 +    mPrt->mDebugFilePtr = mDebugFile;
   1.598 +#endif
   1.599 +
   1.600 +    scriptSuppressor.Suppress();
   1.601 +    bool printSilently;
   1.602 +    mPrt->mPrintSettings->GetPrintSilent(&printSilently);
   1.603 +
   1.604 +    // Check prefs for a default setting as to whether we should print silently
   1.605 +    printSilently =
   1.606 +      Preferences::GetBool("print.always_print_silent", printSilently);
   1.607 +
   1.608 +    // Ask dialog to be Print Shown via the Plugable Printing Dialog Service
   1.609 +    // This service is for the Print Dialog and the Print Progress Dialog
   1.610 +    // If printing silently or you can't get the service continue on
   1.611 +    if (!printSilently) {
   1.612 +      nsCOMPtr<nsIPrintingPromptService> printPromptService(do_GetService(kPrintingPromptService));
   1.613 +      if (printPromptService) {
   1.614 +        nsIDOMWindow *domWin = mDocument->GetWindow(); 
   1.615 +        NS_ENSURE_TRUE(domWin, NS_ERROR_FAILURE);
   1.616 +
   1.617 +        // Platforms not implementing a given dialog for the service may
   1.618 +        // return NS_ERROR_NOT_IMPLEMENTED or an error code.
   1.619 +        //
   1.620 +        // NS_ERROR_NOT_IMPLEMENTED indicates they want default behavior
   1.621 +        // Any other error code means we must bail out
   1.622 +        //
   1.623 +        nsCOMPtr<nsIWebBrowserPrint> wbp(do_QueryInterface(mDocViewerPrint));
   1.624 +        rv = printPromptService->ShowPrintDialog(domWin, wbp,
   1.625 +                                                 mPrt->mPrintSettings);
   1.626 +        //
   1.627 +        // ShowPrintDialog triggers an event loop which means we can't assume
   1.628 +        // that the state of this->{anything} matches the state we've checked
   1.629 +        // above. Including that a given {thing} is non null.
   1.630 +        if (!mPrt) {
   1.631 +          return NS_ERROR_FAILURE;
   1.632 +        }
   1.633 +
   1.634 +        if (NS_SUCCEEDED(rv)) {
   1.635 +          // since we got the dialog and it worked then make sure we 
   1.636 +          // are telling GFX we want to print silent
   1.637 +          printSilently = true;
   1.638 +
   1.639 +          if (mPrt->mPrintSettings) {
   1.640 +            // The user might have changed shrink-to-fit in the print dialog, so update our copy of its state
   1.641 +            mPrt->mPrintSettings->GetShrinkToFit(&mPrt->mShrinkToFit);
   1.642 +          }
   1.643 +        } else if (rv == NS_ERROR_NOT_IMPLEMENTED) {
   1.644 +          // This means the Dialog service was there,
   1.645 +          // but they choose not to implement this dialog and
   1.646 +          // are looking for default behavior from the toolkit
   1.647 +          rv = NS_OK;
   1.648 +        }
   1.649 +      } else {
   1.650 +        // No dialog service available
   1.651 +        rv = NS_ERROR_NOT_IMPLEMENTED;
   1.652 +      }
   1.653 +    } else {
   1.654 +      // Call any code that requires a run of the event loop.
   1.655 +      rv = mPrt->mPrintSettings->SetupSilentPrinting();
   1.656 +    }
   1.657 +    // Check explicitly for abort because it's expected
   1.658 +    if (rv == NS_ERROR_ABORT) 
   1.659 +      return rv;
   1.660 +    NS_ENSURE_SUCCESS(rv, rv);
   1.661 +  }
   1.662 +
   1.663 +  rv = devspec->Init(nullptr, mPrt->mPrintSettings, aIsPrintPreview);
   1.664 +  NS_ENSURE_SUCCESS(rv, rv);
   1.665 +
   1.666 +  mPrt->mPrintDC = new nsDeviceContext();
   1.667 +  rv = mPrt->mPrintDC->InitForPrinting(devspec);
   1.668 +  NS_ENSURE_SUCCESS(rv, rv);
   1.669 +
   1.670 +  if (aIsPrintPreview) {
   1.671 +    mPrt->mPrintSettings->SetPrintFrameType(nsIPrintSettings::kFramesAsIs);
   1.672 +
   1.673 +    // override any UI that wants to PrintPreview any selection or page range
   1.674 +    // we want to view every page in PrintPreview each time
   1.675 +    mPrt->mPrintSettings->SetPrintRange(nsIPrintSettings::kRangeAllPages);
   1.676 +  } else {
   1.677 +    // Always check and set the print settings first and then fall back
   1.678 +    // onto the PrintService if there isn't a PrintSettings
   1.679 +    //
   1.680 +    // Posiible Usage values:
   1.681 +    //   nsIPrintSettings::kUseInternalDefault
   1.682 +    //   nsIPrintSettings::kUseSettingWhenPossible
   1.683 +    //
   1.684 +    // NOTE: The consts are the same for PrintSettings and PrintSettings
   1.685 +    int16_t printFrameTypeUsage = nsIPrintSettings::kUseSettingWhenPossible;
   1.686 +    mPrt->mPrintSettings->GetPrintFrameTypeUsage(&printFrameTypeUsage);
   1.687 +
   1.688 +    // Ok, see if we are going to use our value and override the default
   1.689 +    if (printFrameTypeUsage == nsIPrintSettings::kUseSettingWhenPossible) {
   1.690 +      // Get the Print Options/Settings PrintFrameType to see what is preferred
   1.691 +      int16_t printFrameType = nsIPrintSettings::kEachFrameSep;
   1.692 +      mPrt->mPrintSettings->GetPrintFrameType(&printFrameType);
   1.693 +
   1.694 +      // Don't let anybody do something stupid like try to set it to
   1.695 +      // kNoFrames when we are printing a FrameSet
   1.696 +      if (printFrameType == nsIPrintSettings::kNoFrames) {
   1.697 +        mPrt->mPrintFrameType = nsIPrintSettings::kEachFrameSep;
   1.698 +        mPrt->mPrintSettings->SetPrintFrameType(mPrt->mPrintFrameType);
   1.699 +      } else {
   1.700 +        // First find out from the PrinService what options are available
   1.701 +        // to us for Printing FrameSets
   1.702 +        int16_t howToEnableFrameUI;
   1.703 +        mPrt->mPrintSettings->GetHowToEnableFrameUI(&howToEnableFrameUI);
   1.704 +        if (howToEnableFrameUI != nsIPrintSettings::kFrameEnableNone) {
   1.705 +          switch (howToEnableFrameUI) {
   1.706 +          case nsIPrintSettings::kFrameEnableAll:
   1.707 +            mPrt->mPrintFrameType = printFrameType;
   1.708 +            break;
   1.709 +
   1.710 +          case nsIPrintSettings::kFrameEnableAsIsAndEach:
   1.711 +            if (printFrameType != nsIPrintSettings::kSelectedFrame) {
   1.712 +              mPrt->mPrintFrameType = printFrameType;
   1.713 +            } else { // revert back to a good value
   1.714 +              mPrt->mPrintFrameType = nsIPrintSettings::kEachFrameSep;
   1.715 +            }
   1.716 +            break;
   1.717 +          } // switch
   1.718 +          mPrt->mPrintSettings->SetPrintFrameType(mPrt->mPrintFrameType);
   1.719 +        }
   1.720 +      }
   1.721 +    } else {
   1.722 +      mPrt->mPrintSettings->GetPrintFrameType(&mPrt->mPrintFrameType);
   1.723 +    }
   1.724 +  }
   1.725 +
   1.726 +  if (mPrt->mPrintFrameType == nsIPrintSettings::kEachFrameSep) {
   1.727 +    CheckForChildFrameSets(mPrt->mPrintObject);
   1.728 +  }
   1.729 +
   1.730 +  if (NS_FAILED(EnablePOsForPrinting())) {
   1.731 +    return NS_ERROR_FAILURE;
   1.732 +  }
   1.733 +
   1.734 +  // Attach progressListener to catch network requests.
   1.735 +  nsCOMPtr<nsIWebProgress> webProgress = do_QueryInterface(mPrt->mPrintObject->mDocShell);
   1.736 +  webProgress->AddProgressListener(
   1.737 +    static_cast<nsIWebProgressListener*>(this),
   1.738 +    nsIWebProgress::NOTIFY_STATE_REQUEST);
   1.739 +
   1.740 +  mLoadCounter = 0;
   1.741 +  mDidLoadDataForPrinting = false;
   1.742 +
   1.743 +  if (aIsPrintPreview) {
   1.744 +    bool notifyOnInit = false;
   1.745 +    ShowPrintProgress(false, notifyOnInit);
   1.746 +
   1.747 +    // Very important! Turn Off scripting
   1.748 +    TurnScriptingOn(false);
   1.749 +
   1.750 +    if (!notifyOnInit) {
   1.751 +      InstallPrintPreviewListener();
   1.752 +      rv = InitPrintDocConstruction(false);
   1.753 +    } else {
   1.754 +      rv = NS_OK;
   1.755 +    }
   1.756 +  } else {
   1.757 +    bool doNotify;
   1.758 +    ShowPrintProgress(true, doNotify);
   1.759 +    if (!doNotify) {
   1.760 +      // Print listener setup...
   1.761 +      mPrt->OnStartPrinting();
   1.762 +
   1.763 +      rv = InitPrintDocConstruction(false);
   1.764 +    }
   1.765 +  }
   1.766 +
   1.767 +  // We will enable scripting later after printing has finished.
   1.768 +  scriptSuppressor.Disconnect();
   1.769 +
   1.770 +  return NS_OK;
   1.771 +}
   1.772 +
   1.773 +//---------------------------------------------------------------------------------
   1.774 +NS_IMETHODIMP
   1.775 +nsPrintEngine::Print(nsIPrintSettings*       aPrintSettings,
   1.776 +                     nsIWebProgressListener* aWebProgressListener)
   1.777 +{
   1.778 +  // If we have a print preview document, use that instead of the original
   1.779 +  // mDocument. That way animated images etc. get printed using the same state
   1.780 +  // as in print preview.
   1.781 +  nsCOMPtr<nsIDOMDocument> doc =
   1.782 +    do_QueryInterface(mPrtPreview && mPrtPreview->mPrintObject ?
   1.783 +                        mPrtPreview->mPrintObject->mDocument : mDocument);
   1.784 +
   1.785 +  return CommonPrint(false, aPrintSettings, aWebProgressListener, doc);
   1.786 +}
   1.787 +
   1.788 +NS_IMETHODIMP
   1.789 +nsPrintEngine::PrintPreview(nsIPrintSettings* aPrintSettings, 
   1.790 +                                 nsIDOMWindow *aChildDOMWin, 
   1.791 +                                 nsIWebProgressListener* aWebProgressListener)
   1.792 +{
   1.793 +  // Get the DocShell and see if it is busy
   1.794 +  // (We can't Print Preview this document if it is still busy)
   1.795 +  nsCOMPtr<nsIDocShell> docShell(do_QueryReferent(mContainer));
   1.796 +  NS_ENSURE_STATE(docShell);
   1.797 +
   1.798 +  uint32_t busyFlags = nsIDocShell::BUSY_FLAGS_NONE;
   1.799 +  if (NS_FAILED(docShell->GetBusyFlags(&busyFlags)) ||
   1.800 +      busyFlags != nsIDocShell::BUSY_FLAGS_NONE) {
   1.801 +    CloseProgressDialog(aWebProgressListener);
   1.802 +    ShowPrintErrorDialog(NS_ERROR_GFX_PRINTER_DOC_IS_BUSY, false);
   1.803 +    return NS_ERROR_FAILURE;
   1.804 +  }
   1.805 +
   1.806 +  NS_ENSURE_STATE(aChildDOMWin);
   1.807 +  nsCOMPtr<nsIDOMDocument> doc;
   1.808 +  aChildDOMWin->GetDocument(getter_AddRefs(doc));
   1.809 +  NS_ENSURE_STATE(doc);
   1.810 +
   1.811 +  // Document is not busy -- go ahead with the Print Preview
   1.812 +  return CommonPrint(true, aPrintSettings, aWebProgressListener, doc);
   1.813 +}
   1.814 +
   1.815 +//----------------------------------------------------------------------------------
   1.816 +/* readonly attribute boolean isFramesetDocument; */
   1.817 +NS_IMETHODIMP
   1.818 +nsPrintEngine::GetIsFramesetDocument(bool *aIsFramesetDocument)
   1.819 +{
   1.820 +  nsCOMPtr<nsIDocShell> webContainer(do_QueryReferent(mContainer));
   1.821 +  *aIsFramesetDocument = IsParentAFrameSet(webContainer);
   1.822 +  return NS_OK;
   1.823 +}
   1.824 +
   1.825 +//----------------------------------------------------------------------------------
   1.826 +/* readonly attribute boolean isIFrameSelected; */
   1.827 +NS_IMETHODIMP 
   1.828 +nsPrintEngine::GetIsIFrameSelected(bool *aIsIFrameSelected)
   1.829 +{
   1.830 +  *aIsIFrameSelected = false;
   1.831 +
   1.832 +  // Get the docshell for this documentviewer
   1.833 +  nsCOMPtr<nsIDocShell> webContainer(do_QueryReferent(mContainer));
   1.834 +  // Get the currently focused window
   1.835 +  nsCOMPtr<nsIDOMWindow> currentFocusWin = FindFocusedDOMWindow();
   1.836 +  if (currentFocusWin && webContainer) {
   1.837 +    // Get whether the doc contains a frameset 
   1.838 +    // Also, check to see if the currently focus docshell
   1.839 +    // is a child of this docshell
   1.840 +    bool isParentFrameSet;
   1.841 +    *aIsIFrameSelected = IsThereAnIFrameSelected(webContainer, currentFocusWin, isParentFrameSet);
   1.842 +  }
   1.843 +  return NS_OK;
   1.844 +}
   1.845 +
   1.846 +//----------------------------------------------------------------------------------
   1.847 +/* readonly attribute boolean isRangeSelection; */
   1.848 +NS_IMETHODIMP 
   1.849 +nsPrintEngine::GetIsRangeSelection(bool *aIsRangeSelection)
   1.850 +{
   1.851 +  // Get the currently focused window 
   1.852 +  nsCOMPtr<nsIDOMWindow> currentFocusWin = FindFocusedDOMWindow();
   1.853 +  *aIsRangeSelection = IsThereARangeSelection(currentFocusWin);
   1.854 +  return NS_OK;
   1.855 +}
   1.856 +
   1.857 +//----------------------------------------------------------------------------------
   1.858 +/* readonly attribute boolean isFramesetFrameSelected; */
   1.859 +NS_IMETHODIMP 
   1.860 +nsPrintEngine::GetIsFramesetFrameSelected(bool *aIsFramesetFrameSelected)
   1.861 +{
   1.862 +  // Get the currently focused window 
   1.863 +  nsCOMPtr<nsIDOMWindow> currentFocusWin = FindFocusedDOMWindow();
   1.864 +  *aIsFramesetFrameSelected = currentFocusWin != nullptr;
   1.865 +  return NS_OK;
   1.866 +}
   1.867 +
   1.868 +//----------------------------------------------------------------------------------
   1.869 +/* readonly attribute long printPreviewNumPages; */
   1.870 +NS_IMETHODIMP
   1.871 +nsPrintEngine::GetPrintPreviewNumPages(int32_t *aPrintPreviewNumPages)
   1.872 +{
   1.873 +  NS_ENSURE_ARG_POINTER(aPrintPreviewNumPages);
   1.874 +
   1.875 +  nsPrintData* prt = nullptr;
   1.876 +  nsIFrame* seqFrame  = nullptr;
   1.877 +  *aPrintPreviewNumPages = 0;
   1.878 +
   1.879 +  // When calling this function, the FinishPrintPreview() function might not
   1.880 +  // been called as there are still some 
   1.881 +  if (mPrtPreview) {
   1.882 +    prt = mPrtPreview;
   1.883 +  } else {
   1.884 +    prt = mPrt;
   1.885 +  }
   1.886 +  if ((!prt) ||
   1.887 +      NS_FAILED(GetSeqFrameAndCountPagesInternal(prt->mPrintObject, seqFrame, *aPrintPreviewNumPages))) {
   1.888 +    return NS_ERROR_FAILURE;
   1.889 +  }
   1.890 +  return NS_OK;
   1.891 +}
   1.892 +
   1.893 +//----------------------------------------------------------------------------------
   1.894 +// Enumerate all the documents for their titles
   1.895 +NS_IMETHODIMP
   1.896 +nsPrintEngine::EnumerateDocumentNames(uint32_t* aCount,
   1.897 +                                      char16_t*** aResult)
   1.898 +{
   1.899 +  NS_ENSURE_ARG(aCount);
   1.900 +  NS_ENSURE_ARG_POINTER(aResult);
   1.901 +
   1.902 +  *aCount = 0;
   1.903 +  *aResult = nullptr;
   1.904 +
   1.905 +  int32_t     numDocs = mPrt->mPrintDocList.Length();
   1.906 +  char16_t** array   = (char16_t**) nsMemory::Alloc(numDocs * sizeof(char16_t*));
   1.907 +  if (!array)
   1.908 +    return NS_ERROR_OUT_OF_MEMORY;
   1.909 +
   1.910 +  for (int32_t i=0;i<numDocs;i++) {
   1.911 +    nsPrintObject* po = mPrt->mPrintDocList.ElementAt(i);
   1.912 +    NS_ASSERTION(po, "nsPrintObject can't be null!");
   1.913 +    nsAutoString docTitleStr;
   1.914 +    nsAutoString docURLStr;
   1.915 +    GetDocumentTitleAndURL(po->mDocument, docTitleStr, docURLStr);
   1.916 +
   1.917 +    // Use the URL if the doc is empty
   1.918 +    if (docTitleStr.IsEmpty() && !docURLStr.IsEmpty()) {
   1.919 +      docTitleStr = docURLStr;
   1.920 +    }
   1.921 +    array[i] = ToNewUnicode(docTitleStr);
   1.922 +  }
   1.923 +  *aCount  = numDocs;
   1.924 +  *aResult = array;
   1.925 +
   1.926 +  return NS_OK;
   1.927 +
   1.928 +}
   1.929 +
   1.930 +//----------------------------------------------------------------------------------
   1.931 +/* readonly attribute nsIPrintSettings globalPrintSettings; */
   1.932 +nsresult
   1.933 +nsPrintEngine::GetGlobalPrintSettings(nsIPrintSettings **aGlobalPrintSettings)
   1.934 +{
   1.935 +  NS_ENSURE_ARG_POINTER(aGlobalPrintSettings);
   1.936 +
   1.937 +  nsresult rv = NS_ERROR_FAILURE;
   1.938 +  nsCOMPtr<nsIPrintSettingsService> printSettingsService =
   1.939 +    do_GetService(sPrintSettingsServiceContractID, &rv);
   1.940 +  if (NS_SUCCEEDED(rv)) {
   1.941 +    rv = printSettingsService->GetGlobalPrintSettings(aGlobalPrintSettings);
   1.942 +  }
   1.943 +  return rv;
   1.944 +}
   1.945 +
   1.946 +//----------------------------------------------------------------------------------
   1.947 +/* readonly attribute boolean doingPrint; */
   1.948 +NS_IMETHODIMP
   1.949 +nsPrintEngine::GetDoingPrint(bool *aDoingPrint)
   1.950 +{
   1.951 +  NS_ENSURE_ARG_POINTER(aDoingPrint);
   1.952 +  *aDoingPrint = mIsDoingPrinting;
   1.953 +  return NS_OK;
   1.954 +}
   1.955 +
   1.956 +//----------------------------------------------------------------------------------
   1.957 +/* readonly attribute boolean doingPrintPreview; */
   1.958 +NS_IMETHODIMP
   1.959 +nsPrintEngine::GetDoingPrintPreview(bool *aDoingPrintPreview)
   1.960 +{
   1.961 +  NS_ENSURE_ARG_POINTER(aDoingPrintPreview);
   1.962 +  *aDoingPrintPreview = mIsDoingPrintPreview;
   1.963 +  return NS_OK;
   1.964 +}
   1.965 +
   1.966 +//----------------------------------------------------------------------------------
   1.967 +/* readonly attribute nsIPrintSettings currentPrintSettings; */
   1.968 +NS_IMETHODIMP
   1.969 +nsPrintEngine::GetCurrentPrintSettings(nsIPrintSettings * *aCurrentPrintSettings)
   1.970 +{
   1.971 +  NS_ENSURE_ARG_POINTER(aCurrentPrintSettings);
   1.972 +
   1.973 +  if (mPrt) {
   1.974 +    *aCurrentPrintSettings = mPrt->mPrintSettings;
   1.975 +
   1.976 +  } else if (mPrtPreview) {
   1.977 +    *aCurrentPrintSettings = mPrtPreview->mPrintSettings;
   1.978 +
   1.979 +  } else {
   1.980 +    *aCurrentPrintSettings = nullptr;
   1.981 +  }
   1.982 +  NS_IF_ADDREF(*aCurrentPrintSettings);
   1.983 +  return NS_OK;
   1.984 +}
   1.985 +
   1.986 +//-----------------------------------------------------------------
   1.987 +//-- Section: Pre-Reflow Methods
   1.988 +//-----------------------------------------------------------------
   1.989 +
   1.990 +//---------------------------------------------------------------------
   1.991 +// This method checks to see if there is at least one printer defined
   1.992 +// and if so, it sets the first printer in the list as the default name
   1.993 +// in the PrintSettings which is then used for Printer Preview
   1.994 +nsresult
   1.995 +nsPrintEngine::CheckForPrinters(nsIPrintSettings* aPrintSettings)
   1.996 +{
   1.997 +#if defined(XP_MACOSX) || defined(ANDROID)
   1.998 +  // Mac doesn't support retrieving a printer list.
   1.999 +  return NS_OK;
  1.1000 +#else
  1.1001 +  NS_ENSURE_ARG_POINTER(aPrintSettings);
  1.1002 +
  1.1003 +  // See if aPrintSettings already has a printer
  1.1004 +  nsXPIDLString printerName;
  1.1005 +  nsresult rv = aPrintSettings->GetPrinterName(getter_Copies(printerName));
  1.1006 +  if (NS_SUCCEEDED(rv) && !printerName.IsEmpty()) {
  1.1007 +    return NS_OK;
  1.1008 +  }
  1.1009 +
  1.1010 +  // aPrintSettings doesn't have a printer set. Try to fetch the default.
  1.1011 +  nsCOMPtr<nsIPrintSettingsService> printSettingsService =
  1.1012 +    do_GetService(sPrintSettingsServiceContractID, &rv);
  1.1013 +  NS_ENSURE_SUCCESS(rv, rv);
  1.1014 +
  1.1015 +  rv = printSettingsService->GetDefaultPrinterName(getter_Copies(printerName));
  1.1016 +  if (NS_SUCCEEDED(rv) && !printerName.IsEmpty()) {
  1.1017 +    rv = aPrintSettings->SetPrinterName(printerName.get());
  1.1018 +  }
  1.1019 +  return rv;
  1.1020 +#endif
  1.1021 +}
  1.1022 +
  1.1023 +//----------------------------------------------------------------------
  1.1024 +// Set up to use the "pluggable" Print Progress Dialog
  1.1025 +void
  1.1026 +nsPrintEngine::ShowPrintProgress(bool aIsForPrinting, bool& aDoNotify)
  1.1027 +{
  1.1028 +  // default to not notifying, that if something here goes wrong
  1.1029 +  // or we aren't going to show the progress dialog we can straight into 
  1.1030 +  // reflowing the doc for printing.
  1.1031 +  aDoNotify = false;
  1.1032 +
  1.1033 +  // Assume we can't do progress and then see if we can
  1.1034 +  bool showProgresssDialog = false;
  1.1035 +
  1.1036 +  // if it is already being shown then don't bother to find out if it should be
  1.1037 +  // so skip this and leave mShowProgressDialog set to FALSE
  1.1038 +  if (!mProgressDialogIsShown) {
  1.1039 +    showProgresssDialog = Preferences::GetBool("print.show_print_progress");
  1.1040 +  }
  1.1041 +
  1.1042 +  // Turning off the showing of Print Progress in Prefs overrides
  1.1043 +  // whether the calling PS desire to have it on or off, so only check PS if 
  1.1044 +  // prefs says it's ok to be on.
  1.1045 +  if (showProgresssDialog) {
  1.1046 +    mPrt->mPrintSettings->GetShowPrintProgress(&showProgresssDialog);
  1.1047 +  }
  1.1048 +
  1.1049 +  // Now open the service to get the progress dialog
  1.1050 +  // If we don't get a service, that's ok, then just don't show progress
  1.1051 +  if (showProgresssDialog) {
  1.1052 +    nsCOMPtr<nsIPrintingPromptService> printPromptService(do_GetService(kPrintingPromptService));
  1.1053 +    if (printPromptService) {
  1.1054 +      nsPIDOMWindow *domWin = mDocument->GetWindow(); 
  1.1055 +      if (!domWin) return;
  1.1056 +
  1.1057 +      nsCOMPtr<nsIDocShell> docShell = domWin->GetDocShell();
  1.1058 +      if (!docShell) return;
  1.1059 +      nsCOMPtr<nsIDocShellTreeOwner> owner;
  1.1060 +      docShell->GetTreeOwner(getter_AddRefs(owner));
  1.1061 +      nsCOMPtr<nsIWebBrowserChrome> browserChrome = do_GetInterface(owner);
  1.1062 +      if (!browserChrome) return;
  1.1063 +      bool isModal = true;
  1.1064 +      browserChrome->IsWindowModal(&isModal);
  1.1065 +      if (isModal) {
  1.1066 +        // Showing a print progress dialog when printing a modal window
  1.1067 +        // isn't supported. See bug 301560.
  1.1068 +        return;
  1.1069 +      }
  1.1070 +
  1.1071 +      nsCOMPtr<nsIWebProgressListener> printProgressListener;
  1.1072 +
  1.1073 +      nsCOMPtr<nsIWebBrowserPrint> wbp(do_QueryInterface(mDocViewerPrint));
  1.1074 +      nsresult rv = printPromptService->ShowProgress(domWin, wbp, mPrt->mPrintSettings, this, aIsForPrinting,
  1.1075 +                                                     getter_AddRefs(printProgressListener), 
  1.1076 +                                                     getter_AddRefs(mPrt->mPrintProgressParams), 
  1.1077 +                                                     &aDoNotify);
  1.1078 +      if (NS_SUCCEEDED(rv)) {
  1.1079 +        if (printProgressListener && mPrt->mPrintProgressParams) {
  1.1080 +          mPrt->mPrintProgressListeners.AppendObject(printProgressListener);
  1.1081 +          SetDocAndURLIntoProgress(mPrt->mPrintObject, mPrt->mPrintProgressParams);
  1.1082 +        }
  1.1083 +      }
  1.1084 +    }
  1.1085 +  }
  1.1086 +}
  1.1087 +
  1.1088 +//---------------------------------------------------------------------
  1.1089 +bool
  1.1090 +nsPrintEngine::IsThereARangeSelection(nsIDOMWindow* aDOMWin)
  1.1091 +{
  1.1092 +  if (mDisallowSelectionPrint)
  1.1093 +    return false;
  1.1094 +
  1.1095 +  nsCOMPtr<nsIPresShell> presShell;
  1.1096 +  if (aDOMWin) {
  1.1097 +    nsCOMPtr<nsPIDOMWindow> window(do_QueryInterface(aDOMWin));
  1.1098 +    presShell = window->GetDocShell()->GetPresShell();
  1.1099 +  }
  1.1100 +
  1.1101 +  if (!presShell)
  1.1102 +    return false;
  1.1103 +
  1.1104 +  // check here to see if there is a range selection
  1.1105 +  // so we know whether to turn on the "Selection" radio button
  1.1106 +  Selection* selection =
  1.1107 +    presShell->GetCurrentSelection(nsISelectionController::SELECTION_NORMAL);
  1.1108 +  if (!selection) {
  1.1109 +    return false;
  1.1110 +  }
  1.1111 +
  1.1112 +  int32_t rangeCount = selection->GetRangeCount();
  1.1113 +  if (!rangeCount) {
  1.1114 +    return false;
  1.1115 +  }
  1.1116 +
  1.1117 +  if (rangeCount > 1) {
  1.1118 +    return true;
  1.1119 +  }
  1.1120 +
  1.1121 +  // check to make sure it isn't an insertion selection
  1.1122 +  return selection->GetRangeAt(0) && !selection->IsCollapsed();
  1.1123 +}
  1.1124 +
  1.1125 +//---------------------------------------------------------------------
  1.1126 +bool
  1.1127 +nsPrintEngine::IsParentAFrameSet(nsIDocShell * aParent)
  1.1128 +{
  1.1129 +  // See if the incoming doc is the root document
  1.1130 +  if (!aParent) return false;
  1.1131 +
  1.1132 +  // When it is the top level document we need to check
  1.1133 +  // to see if it contains a frameset. If it does, then
  1.1134 +  // we only want to print the doc's children and not the document itself
  1.1135 +  // For anything else we always print all the children and the document
  1.1136 +  // for example, if the doc contains an IFRAME we eant to print the child
  1.1137 +  // document (the IFRAME) and then the rest of the document.
  1.1138 +  //
  1.1139 +  // XXX we really need to search the frame tree, and not the content
  1.1140 +  // but there is no way to distinguish between IFRAMEs and FRAMEs
  1.1141 +  // with the GetFrameType call.
  1.1142 +  // Bug 53459 has been files so we can eventually distinguish
  1.1143 +  // between IFRAME frames and FRAME frames
  1.1144 +  bool isFrameSet = false;
  1.1145 +  // only check to see if there is a frameset if there is
  1.1146 +  // NO parent doc for this doc. meaning this parent is the root doc
  1.1147 +  nsCOMPtr<nsIDOMDocument> domDoc = do_GetInterface(aParent);
  1.1148 +  nsCOMPtr<nsIDocument> doc = do_QueryInterface(domDoc);
  1.1149 +  if (doc) {
  1.1150 +    nsIContent *rootElement = doc->GetRootElement();
  1.1151 +    if (rootElement) {
  1.1152 +      isFrameSet = HasFramesetChild(rootElement);
  1.1153 +    }
  1.1154 +  }
  1.1155 +  return isFrameSet;
  1.1156 +}
  1.1157 +
  1.1158 +
  1.1159 +//---------------------------------------------------------------------
  1.1160 +// Recursively build a list of sub documents to be printed
  1.1161 +// that mirrors the document tree
  1.1162 +void
  1.1163 +nsPrintEngine::BuildDocTree(nsIDocShell *      aParentNode,
  1.1164 +                            nsTArray<nsPrintObject*> * aDocList,
  1.1165 +                            nsPrintObject *            aPO)
  1.1166 +{
  1.1167 +  NS_ASSERTION(aParentNode, "Pointer is null!");
  1.1168 +  NS_ASSERTION(aDocList, "Pointer is null!");
  1.1169 +  NS_ASSERTION(aPO, "Pointer is null!");
  1.1170 +
  1.1171 +  int32_t childWebshellCount;
  1.1172 +  aParentNode->GetChildCount(&childWebshellCount);
  1.1173 +  if (childWebshellCount > 0) {
  1.1174 +    for (int32_t i=0;i<childWebshellCount;i++) {
  1.1175 +      nsCOMPtr<nsIDocShellTreeItem> child;
  1.1176 +      aParentNode->GetChildAt(i, getter_AddRefs(child));
  1.1177 +      nsCOMPtr<nsIDocShell> childAsShell(do_QueryInterface(child));
  1.1178 +
  1.1179 +      nsCOMPtr<nsIContentViewer>  viewer;
  1.1180 +      childAsShell->GetContentViewer(getter_AddRefs(viewer));
  1.1181 +      if (viewer) {
  1.1182 +        nsCOMPtr<nsIContentViewerFile> viewerFile(do_QueryInterface(viewer));
  1.1183 +        if (viewerFile) {
  1.1184 +          nsCOMPtr<nsIDOMDocument> doc = do_GetInterface(childAsShell);
  1.1185 +          nsPrintObject * po = new nsPrintObject();
  1.1186 +          po->mParent = aPO;
  1.1187 +          nsresult rv = po->Init(childAsShell, doc, aPO->mPrintPreview);
  1.1188 +          if (NS_FAILED(rv))
  1.1189 +            NS_NOTREACHED("Init failed?");
  1.1190 +          aPO->mKids.AppendElement(po);
  1.1191 +          aDocList->AppendElement(po);
  1.1192 +          BuildDocTree(childAsShell, aDocList, po);
  1.1193 +        }
  1.1194 +      }
  1.1195 +    }
  1.1196 +  }
  1.1197 +}
  1.1198 +
  1.1199 +//---------------------------------------------------------------------
  1.1200 +void
  1.1201 +nsPrintEngine::GetDocumentTitleAndURL(nsIDocument* aDoc,
  1.1202 +                                      nsAString&   aTitle,
  1.1203 +                                      nsAString&   aURLStr)
  1.1204 +{
  1.1205 +  NS_ASSERTION(aDoc, "Pointer is null!");
  1.1206 +
  1.1207 +  aTitle.Truncate();
  1.1208 +  aURLStr.Truncate();
  1.1209 +
  1.1210 +  nsCOMPtr<nsIDOMDocument> doc = do_QueryInterface(aDoc);
  1.1211 +  doc->GetTitle(aTitle);
  1.1212 +
  1.1213 +  nsIURI* url = aDoc->GetDocumentURI();
  1.1214 +  if (!url) return;
  1.1215 +
  1.1216 +  nsCOMPtr<nsIURIFixup> urifixup(do_GetService(NS_URIFIXUP_CONTRACTID));
  1.1217 +  if (!urifixup) return;
  1.1218 +
  1.1219 +  nsCOMPtr<nsIURI> exposableURI;
  1.1220 +  urifixup->CreateExposableURI(url, getter_AddRefs(exposableURI));
  1.1221 +
  1.1222 +  if (!exposableURI) return;
  1.1223 +
  1.1224 +  nsAutoCString urlCStr;
  1.1225 +  exposableURI->GetSpec(urlCStr);
  1.1226 +
  1.1227 +  nsresult rv;
  1.1228 +  nsCOMPtr<nsITextToSubURI> textToSubURI = 
  1.1229 +    do_GetService(NS_ITEXTTOSUBURI_CONTRACTID, &rv);
  1.1230 +  if (NS_FAILED(rv)) return;
  1.1231 +
  1.1232 +  textToSubURI->UnEscapeURIForUI(NS_LITERAL_CSTRING("UTF-8"),
  1.1233 +                                 urlCStr, aURLStr);
  1.1234 +}
  1.1235 +
  1.1236 +//---------------------------------------------------------------------
  1.1237 +// The walks the PO tree and for each document it walks the content
  1.1238 +// tree looking for any content that are sub-shells
  1.1239 +//
  1.1240 +// It then sets the mContent pointer in the "found" PO object back to the
  1.1241 +// the document that contained it.
  1.1242 +void
  1.1243 +nsPrintEngine::MapContentToWebShells(nsPrintObject* aRootPO,
  1.1244 +                                     nsPrintObject* aPO)
  1.1245 +{
  1.1246 +  NS_ASSERTION(aRootPO, "Pointer is null!");
  1.1247 +  NS_ASSERTION(aPO, "Pointer is null!");
  1.1248 +
  1.1249 +  // Recursively walk the content from the root item
  1.1250 +  // XXX Would be faster to enumerate the subdocuments, although right now
  1.1251 +  //     nsIDocument doesn't expose quite what would be needed.
  1.1252 +  nsCOMPtr<nsIContentViewer> viewer;
  1.1253 +  aPO->mDocShell->GetContentViewer(getter_AddRefs(viewer));
  1.1254 +  if (!viewer) return;
  1.1255 +
  1.1256 +  nsCOMPtr<nsIDOMDocument> domDoc;
  1.1257 +  viewer->GetDOMDocument(getter_AddRefs(domDoc));
  1.1258 +  nsCOMPtr<nsIDocument> doc = do_QueryInterface(domDoc);
  1.1259 +  if (!doc) return;
  1.1260 +
  1.1261 +  Element* rootElement = doc->GetRootElement();
  1.1262 +  if (rootElement) {
  1.1263 +    MapContentForPO(aPO, rootElement);
  1.1264 +  } else {
  1.1265 +    NS_WARNING("Null root content on (sub)document.");
  1.1266 +  }
  1.1267 +
  1.1268 +  // Continue recursively walking the chilren of this PO
  1.1269 +  for (uint32_t i=0;i<aPO->mKids.Length();i++) {
  1.1270 +    MapContentToWebShells(aRootPO, aPO->mKids[i]);
  1.1271 +  }
  1.1272 +
  1.1273 +}
  1.1274 +
  1.1275 +//-------------------------------------------------------
  1.1276 +// A Frame's sub-doc may contain content or a FrameSet
  1.1277 +// When it contains a FrameSet the mFrameType for the PrintObject
  1.1278 +// is always set to an eFrame. Which is fine when printing "AsIs"
  1.1279 +// but is incorrect when when printing "Each Frame Separately".
  1.1280 +// When printing "Each Frame Separately" the Frame really acts like
  1.1281 +// a frameset.
  1.1282 +//
  1.1283 +// This method walks the PO tree and checks to see if the PrintObject is
  1.1284 +// an eFrame and has children that are eFrames (meaning it's a Frame containing a FrameSet)
  1.1285 +// If so, then the mFrameType need to be changed to eFrameSet
  1.1286 +//
  1.1287 +// Also note: We only want to call this we are printing "Each Frame Separately"
  1.1288 +//            when printing "As Is" leave it as an eFrame
  1.1289 +void
  1.1290 +nsPrintEngine::CheckForChildFrameSets(nsPrintObject* aPO)
  1.1291 +{
  1.1292 +  NS_ASSERTION(aPO, "Pointer is null!");
  1.1293 +
  1.1294 +  // Continue recursively walking the chilren of this PO
  1.1295 +  bool hasChildFrames = false;
  1.1296 +  for (uint32_t i=0;i<aPO->mKids.Length();i++) {
  1.1297 +    nsPrintObject* po = aPO->mKids[i];
  1.1298 +    if (po->mFrameType == eFrame) {
  1.1299 +      hasChildFrames = true;
  1.1300 +      CheckForChildFrameSets(po);
  1.1301 +    }
  1.1302 +  }
  1.1303 +
  1.1304 +  if (hasChildFrames && aPO->mFrameType == eFrame) {
  1.1305 +    aPO->mFrameType = eFrameSet;
  1.1306 +  }
  1.1307 +}
  1.1308 +
  1.1309 +//---------------------------------------------------------------------
  1.1310 +// This method is key to the entire print mechanism.
  1.1311 +//
  1.1312 +// This "maps" or figures out which sub-doc represents a
  1.1313 +// given Frame or IFrame in its parent sub-doc.
  1.1314 +//
  1.1315 +// So the Mcontent pointer in the child sub-doc points to the
  1.1316 +// content in the its parent document, that caused it to be printed.
  1.1317 +// This is used later to (after reflow) to find the absolute location
  1.1318 +// of the sub-doc on its parent's page frame so it can be
  1.1319 +// printed in the correct location.
  1.1320 +//
  1.1321 +// This method recursvely "walks" the content for a document finding
  1.1322 +// all the Frames and IFrames, then sets the "mFrameType" data member
  1.1323 +// which tells us what type of PO we have
  1.1324 +void
  1.1325 +nsPrintEngine::MapContentForPO(nsPrintObject*   aPO,
  1.1326 +                               nsIContent*      aContent)
  1.1327 +{
  1.1328 +  NS_PRECONDITION(aPO && aContent, "Null argument");
  1.1329 +
  1.1330 +  nsIDocument* doc = aContent->GetDocument();
  1.1331 +
  1.1332 +  NS_ASSERTION(doc, "Content without a document from a document tree?");
  1.1333 +
  1.1334 +  nsIDocument* subDoc = doc->GetSubDocumentFor(aContent);
  1.1335 +
  1.1336 +  if (subDoc) {
  1.1337 +    nsCOMPtr<nsIDocShell> docShell(subDoc->GetDocShell());
  1.1338 +
  1.1339 +    if (docShell) {
  1.1340 +      nsPrintObject * po = nullptr;
  1.1341 +      int32_t cnt = aPO->mKids.Length();
  1.1342 +      for (int32_t i=0;i<cnt;i++) {
  1.1343 +        nsPrintObject* kid = aPO->mKids.ElementAt(i);
  1.1344 +        if (kid->mDocument == subDoc) {
  1.1345 +          po = kid;
  1.1346 +          break;
  1.1347 +        }
  1.1348 +      }
  1.1349 +
  1.1350 +      // XXX If a subdocument has no onscreen presentation, there will be no PO
  1.1351 +      //     This is even if there should be a print presentation
  1.1352 +      if (po) {
  1.1353 +
  1.1354 +        nsCOMPtr<nsIDOMHTMLFrameElement> frame(do_QueryInterface(aContent));
  1.1355 +        // "frame" elements not in a frameset context should be treated
  1.1356 +        // as iframes
  1.1357 +        if (frame && po->mParent->mFrameType == eFrameSet) {
  1.1358 +          po->mFrameType = eFrame;
  1.1359 +        } else {
  1.1360 +          // Assume something iframe-like, i.e. iframe, object, or embed
  1.1361 +          po->mFrameType = eIFrame;
  1.1362 +          SetPrintAsIs(po, true);
  1.1363 +          NS_ASSERTION(po->mParent, "The root must be a parent");
  1.1364 +          po->mParent->mPrintAsIs = true;
  1.1365 +        }
  1.1366 +      }
  1.1367 +    }
  1.1368 +  }
  1.1369 +
  1.1370 +  // walk children content
  1.1371 +  for (nsIContent* child = aContent->GetFirstChild();
  1.1372 +       child;
  1.1373 +       child = child->GetNextSibling()) {
  1.1374 +    MapContentForPO(aPO, child);
  1.1375 +  }
  1.1376 +}
  1.1377 +
  1.1378 +//---------------------------------------------------------------------
  1.1379 +bool
  1.1380 +nsPrintEngine::IsThereAnIFrameSelected(nsIDocShell* aDocShell,
  1.1381 +                                       nsIDOMWindow* aDOMWin,
  1.1382 +                                       bool& aIsParentFrameSet)
  1.1383 +{
  1.1384 +  aIsParentFrameSet = IsParentAFrameSet(aDocShell);
  1.1385 +  bool iFrameIsSelected = false;
  1.1386 +  if (mPrt && mPrt->mPrintObject) {
  1.1387 +    nsPrintObject* po = FindPrintObjectByDOMWin(mPrt->mPrintObject, aDOMWin);
  1.1388 +    iFrameIsSelected = po && po->mFrameType == eIFrame;
  1.1389 +  } else {
  1.1390 +    // First, check to see if we are a frameset
  1.1391 +    if (!aIsParentFrameSet) {
  1.1392 +      // Check to see if there is a currenlt focused frame
  1.1393 +      // if so, it means the selected frame is either the main docshell
  1.1394 +      // or an IFRAME
  1.1395 +      if (aDOMWin) {
  1.1396 +        // Get the main docshell's DOMWin to see if it matches 
  1.1397 +        // the frame that is selected
  1.1398 +        nsCOMPtr<nsIDOMWindow> domWin = do_GetInterface(aDocShell);
  1.1399 +        if (domWin != aDOMWin) {
  1.1400 +          iFrameIsSelected = true; // we have a selected IFRAME
  1.1401 +        }
  1.1402 +      }
  1.1403 +    }
  1.1404 +  }
  1.1405 +
  1.1406 +  return iFrameIsSelected;
  1.1407 +}
  1.1408 +
  1.1409 +//---------------------------------------------------------------------
  1.1410 +// Recursively sets all the PO items to be printed
  1.1411 +// from the given item down into the tree
  1.1412 +void
  1.1413 +nsPrintEngine::SetPrintPO(nsPrintObject* aPO, bool aPrint)
  1.1414 +{
  1.1415 +  NS_ASSERTION(aPO, "Pointer is null!");
  1.1416 +
  1.1417 +  // Set whether to print flag
  1.1418 +  aPO->mDontPrint = !aPrint;
  1.1419 +
  1.1420 +  for (uint32_t i=0;i<aPO->mKids.Length();i++) {
  1.1421 +    SetPrintPO(aPO->mKids[i], aPrint);
  1.1422 +  } 
  1.1423 +}
  1.1424 +
  1.1425 +//---------------------------------------------------------------------
  1.1426 +// This will first use a Title and/or URL from the PrintSettings
  1.1427 +// if one isn't set then it uses the one from the document
  1.1428 +// then if not title is there we will make sure we send something back
  1.1429 +// depending on the situation.
  1.1430 +void
  1.1431 +nsPrintEngine::GetDisplayTitleAndURL(nsPrintObject*   aPO,
  1.1432 +                                     nsAString&       aTitle,
  1.1433 +                                     nsAString&       aURLStr,
  1.1434 +                                     eDocTitleDefault aDefType)
  1.1435 +{
  1.1436 +  NS_ASSERTION(aPO, "Pointer is null!");
  1.1437 +
  1.1438 +  if (!mPrt)
  1.1439 +    return;
  1.1440 +
  1.1441 +  aTitle.Truncate();
  1.1442 +  aURLStr.Truncate();
  1.1443 +
  1.1444 +  // First check to see if the PrintSettings has defined an alternate title
  1.1445 +  // and use that if it did
  1.1446 +  if (mPrt->mPrintSettings) {
  1.1447 +    char16_t * docTitleStrPS = nullptr;
  1.1448 +    char16_t * docURLStrPS   = nullptr;
  1.1449 +    mPrt->mPrintSettings->GetTitle(&docTitleStrPS);
  1.1450 +    mPrt->mPrintSettings->GetDocURL(&docURLStrPS);
  1.1451 +
  1.1452 +    if (docTitleStrPS) {
  1.1453 +      aTitle = docTitleStrPS;
  1.1454 +    }
  1.1455 +
  1.1456 +    if (docURLStrPS) {
  1.1457 +      aURLStr = docURLStrPS;
  1.1458 +    }
  1.1459 +
  1.1460 +    nsMemory::Free(docTitleStrPS);
  1.1461 +    nsMemory::Free(docURLStrPS);
  1.1462 +  }
  1.1463 +
  1.1464 +  nsAutoString docTitle;
  1.1465 +  nsAutoString docUrl;
  1.1466 +  GetDocumentTitleAndURL(aPO->mDocument, docTitle, docUrl);
  1.1467 +
  1.1468 +  if (aURLStr.IsEmpty() && !docUrl.IsEmpty()) {
  1.1469 +    aURLStr = docUrl;
  1.1470 +  }
  1.1471 +
  1.1472 +  if (aTitle.IsEmpty()) {
  1.1473 +    if (!docTitle.IsEmpty()) {
  1.1474 +      aTitle = docTitle;
  1.1475 +    } else {
  1.1476 +      if (aDefType == eDocTitleDefURLDoc) {
  1.1477 +        if (!aURLStr.IsEmpty()) {
  1.1478 +          aTitle = aURLStr;
  1.1479 +        } else if (mPrt->mBrandName) {
  1.1480 +          aTitle = mPrt->mBrandName;
  1.1481 +        }
  1.1482 +      }
  1.1483 +    }
  1.1484 +  }
  1.1485 +}
  1.1486 +
  1.1487 +//---------------------------------------------------------------------
  1.1488 +nsresult nsPrintEngine::DocumentReadyForPrinting()
  1.1489 +{
  1.1490 +  if (mPrt->mPrintFrameType == nsIPrintSettings::kEachFrameSep) {
  1.1491 +    CheckForChildFrameSets(mPrt->mPrintObject);
  1.1492 +  }
  1.1493 +
  1.1494 +  //
  1.1495 +  // Send the document to the printer...
  1.1496 +  //
  1.1497 +  nsresult rv = SetupToPrintContent();
  1.1498 +  if (NS_FAILED(rv)) {
  1.1499 +    // The print job was canceled or there was a problem
  1.1500 +    // So remove all other documents from the print list
  1.1501 +    DonePrintingPages(nullptr, rv);
  1.1502 +  }
  1.1503 +  return rv;
  1.1504 +}
  1.1505 +
  1.1506 +/** ---------------------------------------------------
  1.1507 + *  Cleans up when an error occurred
  1.1508 + */
  1.1509 +nsresult nsPrintEngine::CleanupOnFailure(nsresult aResult, bool aIsPrinting)
  1.1510 +{
  1.1511 +  PR_PL(("****  Failed %s - rv 0x%X", aIsPrinting?"Printing":"Print Preview", aResult));
  1.1512 +
  1.1513 +  /* cleanup... */
  1.1514 +  if (mPagePrintTimer) {
  1.1515 +    mPagePrintTimer->Stop();
  1.1516 +    NS_RELEASE(mPagePrintTimer);
  1.1517 +  }
  1.1518 +  
  1.1519 +  if (aIsPrinting) {
  1.1520 +    SetIsPrinting(false);
  1.1521 +  } else {
  1.1522 +    SetIsPrintPreview(false);
  1.1523 +    SetIsCreatingPrintPreview(false);
  1.1524 +  }
  1.1525 +
  1.1526 +  /* cleanup done, let's fire-up an error dialog to notify the user
  1.1527 +   * what went wrong... 
  1.1528 +   * 
  1.1529 +   * When rv == NS_ERROR_ABORT, it means we want out of the 
  1.1530 +   * print job without displaying any error messages
  1.1531 +   */
  1.1532 +  if (aResult != NS_ERROR_ABORT) {
  1.1533 +    ShowPrintErrorDialog(aResult, aIsPrinting);
  1.1534 +  }
  1.1535 +
  1.1536 +  FirePrintCompletionEvent();
  1.1537 +
  1.1538 +  return aResult;
  1.1539 +
  1.1540 +}
  1.1541 +
  1.1542 +//---------------------------------------------------------------------
  1.1543 +void
  1.1544 +nsPrintEngine::ShowPrintErrorDialog(nsresult aPrintError, bool aIsPrinting)
  1.1545 +{
  1.1546 +  nsAutoCString stringName;
  1.1547 +  nsXPIDLString msg, title;
  1.1548 +  nsresult rv = NS_OK;
  1.1549 +
  1.1550 +  switch(aPrintError)
  1.1551 +  {
  1.1552 +#define ENTITY_FOR_ERROR(label) \
  1.1553 +    case NS_ERROR_##label: stringName.AssignLiteral("PERR_" #label); break
  1.1554 +
  1.1555 +    ENTITY_FOR_ERROR(GFX_PRINTER_NO_PRINTER_AVAILABLE);
  1.1556 +    ENTITY_FOR_ERROR(GFX_PRINTER_NAME_NOT_FOUND);
  1.1557 +    ENTITY_FOR_ERROR(GFX_PRINTER_COULD_NOT_OPEN_FILE);
  1.1558 +    ENTITY_FOR_ERROR(GFX_PRINTER_STARTDOC);
  1.1559 +    ENTITY_FOR_ERROR(GFX_PRINTER_ENDDOC);
  1.1560 +    ENTITY_FOR_ERROR(GFX_PRINTER_STARTPAGE);
  1.1561 +    ENTITY_FOR_ERROR(GFX_PRINTER_DOC_IS_BUSY);
  1.1562 +
  1.1563 +    ENTITY_FOR_ERROR(ABORT);
  1.1564 +    ENTITY_FOR_ERROR(NOT_AVAILABLE);
  1.1565 +    ENTITY_FOR_ERROR(NOT_IMPLEMENTED);
  1.1566 +    ENTITY_FOR_ERROR(OUT_OF_MEMORY);
  1.1567 +    ENTITY_FOR_ERROR(UNEXPECTED);
  1.1568 +
  1.1569 +    default:
  1.1570 +    ENTITY_FOR_ERROR(FAILURE);
  1.1571 +
  1.1572 +#undef ENTITY_FOR_ERROR
  1.1573 +  }
  1.1574 +
  1.1575 +  if (!aIsPrinting) {
  1.1576 +    // Try first with _PP suffix.
  1.1577 +    stringName.AppendLiteral("_PP");
  1.1578 +    rv = nsContentUtils::GetLocalizedString(
  1.1579 +             nsContentUtils::ePRINTING_PROPERTIES, stringName.get(), msg);
  1.1580 +    if (NS_FAILED(rv)) {
  1.1581 +      stringName.Truncate(stringName.Length() - 3);
  1.1582 +    }
  1.1583 +  }
  1.1584 +  if (aIsPrinting || NS_FAILED(rv)) {
  1.1585 +    rv = nsContentUtils::GetLocalizedString(
  1.1586 +             nsContentUtils::ePRINTING_PROPERTIES, stringName.get(), msg);
  1.1587 +  }
  1.1588 +  if (NS_FAILED(rv)) {
  1.1589 +    return;
  1.1590 +  }
  1.1591 +
  1.1592 +  rv = nsContentUtils::GetLocalizedString(
  1.1593 +           nsContentUtils::ePRINTING_PROPERTIES,
  1.1594 +           aIsPrinting ? "print_error_dialog_title"
  1.1595 +                       : "printpreview_error_dialog_title",
  1.1596 +           title);
  1.1597 +  if (NS_FAILED(rv)) {
  1.1598 +    return;
  1.1599 +  }
  1.1600 +
  1.1601 +  nsCOMPtr<nsIWindowWatcher> wwatch =
  1.1602 +    do_GetService(NS_WINDOWWATCHER_CONTRACTID, &rv);
  1.1603 +  if (NS_FAILED(rv)) {
  1.1604 +    return;
  1.1605 +  }
  1.1606 +
  1.1607 +  nsCOMPtr<nsIDOMWindow> active;
  1.1608 +  wwatch->GetActiveWindow(getter_AddRefs(active));
  1.1609 +
  1.1610 +  nsCOMPtr<nsIPrompt> dialog;
  1.1611 +  /* |GetNewPrompter| allows that |active| is |nullptr|
  1.1612 +   * (see bug 234982 ("nsPrintEngine::ShowPrintErrorDialog() fails in many cases")) */
  1.1613 +  wwatch->GetNewPrompter(active, getter_AddRefs(dialog));
  1.1614 +  if (!dialog) {
  1.1615 +    return;
  1.1616 +  }
  1.1617 +
  1.1618 +  dialog->Alert(title.get(), msg.get());
  1.1619 +}
  1.1620 +
  1.1621 +//-----------------------------------------------------------------
  1.1622 +//-- Section: Reflow Methods
  1.1623 +//-----------------------------------------------------------------
  1.1624 +
  1.1625 +nsresult
  1.1626 +nsPrintEngine::ReconstructAndReflow(bool doSetPixelScale)
  1.1627 +{
  1.1628 +#if defined(XP_WIN) && defined(EXTENDED_DEBUG_PRINTING)
  1.1629 +  // We need to clear all the output files here
  1.1630 +  // because they will be re-created with second reflow of the docs
  1.1631 +  if (kPrintingLogMod && kPrintingLogMod->level == DUMP_LAYOUT_LEVEL) {
  1.1632 +    RemoveFilesInDir(".\\");
  1.1633 +    gDumpFileNameCnt   = 0;
  1.1634 +    gDumpLOFileNameCnt = 0;
  1.1635 +  }
  1.1636 +#endif
  1.1637 +
  1.1638 +  for (uint32_t i = 0; i < mPrt->mPrintDocList.Length(); ++i) {
  1.1639 +    nsPrintObject* po = mPrt->mPrintDocList.ElementAt(i);
  1.1640 +    NS_ASSERTION(po, "nsPrintObject can't be null!");
  1.1641 +
  1.1642 +    if (po->mDontPrint || po->mInvisible) {
  1.1643 +      continue;
  1.1644 +    }
  1.1645 +
  1.1646 +    UpdateZoomRatio(po, doSetPixelScale);
  1.1647 +
  1.1648 +    po->mPresContext->SetPageScale(po->mZoomRatio);
  1.1649 +
  1.1650 +    // Calculate scale factor from printer to screen
  1.1651 +    float printDPI = float(mPrt->mPrintDC->AppUnitsPerCSSInch()) /
  1.1652 +                     float(mPrt->mPrintDC->AppUnitsPerDevPixel());
  1.1653 +    po->mPresContext->SetPrintPreviewScale(mScreenDPI / printDPI);
  1.1654 +
  1.1655 +    po->mPresShell->ReconstructFrames();
  1.1656 +
  1.1657 +    // For all views except the first one, setup the root view.
  1.1658 +    // ??? Can there be multiple po for the top-level-document?
  1.1659 +    bool documentIsTopLevel = true;
  1.1660 +    if (i != 0) {
  1.1661 +      nsSize adjSize;
  1.1662 +      bool doReturn; 
  1.1663 +      nsresult rv = SetRootView(po, doReturn, documentIsTopLevel, adjSize);
  1.1664 +
  1.1665 +      MOZ_ASSERT(!documentIsTopLevel, "How could this happen?");
  1.1666 +      
  1.1667 +      if (NS_FAILED(rv) || doReturn) {
  1.1668 +        return rv; 
  1.1669 +      }
  1.1670 +    }
  1.1671 +
  1.1672 +    po->mPresShell->FlushPendingNotifications(Flush_Layout);
  1.1673 +
  1.1674 +    nsresult rv = UpdateSelectionAndShrinkPrintObject(po, documentIsTopLevel);
  1.1675 +    NS_ENSURE_SUCCESS(rv, rv);
  1.1676 +  }
  1.1677 +  return NS_OK;
  1.1678 +}
  1.1679 +
  1.1680 +//-------------------------------------------------------
  1.1681 +nsresult
  1.1682 +nsPrintEngine::SetupToPrintContent()
  1.1683 +{
  1.1684 +  nsresult rv;
  1.1685 +
  1.1686 +  bool didReconstruction = false;
  1.1687 +  
  1.1688 +  // If some new content got loaded since the initial reflow rebuild
  1.1689 +  // everything.
  1.1690 +  if (mDidLoadDataForPrinting) {
  1.1691 +    rv = ReconstructAndReflow(DoSetPixelScale());
  1.1692 +    didReconstruction = true;
  1.1693 +    NS_ENSURE_SUCCESS(rv, rv);
  1.1694 +  }
  1.1695 +
  1.1696 +  // Here is where we figure out if extra reflow for shrinking the content
  1.1697 +  // is required.
  1.1698 +  // But skip this step if we are in PrintPreview
  1.1699 +  bool ppIsShrinkToFit = mPrtPreview && mPrtPreview->mShrinkToFit;
  1.1700 +  if (mPrt->mShrinkToFit && !ppIsShrinkToFit) {
  1.1701 +    // Now look for the PO that has the smallest percent for shrink to fit
  1.1702 +    if (mPrt->mPrintDocList.Length() > 1 && mPrt->mPrintObject->mFrameType == eFrameSet) {
  1.1703 +      nsPrintObject* smallestPO = FindSmallestSTF();
  1.1704 +      NS_ASSERTION(smallestPO, "There must always be an XMost PO!");
  1.1705 +      if (smallestPO) {
  1.1706 +        // Calc the shrinkage based on the entire content area
  1.1707 +        mPrt->mShrinkRatio = smallestPO->mShrinkRatio;
  1.1708 +      }
  1.1709 +    } else {
  1.1710 +      // Single document so use the Shrink as calculated for the PO
  1.1711 +      mPrt->mShrinkRatio = mPrt->mPrintObject->mShrinkRatio;
  1.1712 +    }
  1.1713 +
  1.1714 +    if (mPrt->mShrinkRatio < 0.998f) {
  1.1715 +      rv = ReconstructAndReflow(true);
  1.1716 +      didReconstruction = true;
  1.1717 +      NS_ENSURE_SUCCESS(rv, rv);
  1.1718 +    }
  1.1719 +
  1.1720 +#ifdef PR_LOGGING
  1.1721 +    float calcRatio = 0.0f;
  1.1722 +    if (mPrt->mPrintDocList.Length() > 1 && mPrt->mPrintObject->mFrameType == eFrameSet) {
  1.1723 +      nsPrintObject* smallestPO = FindSmallestSTF();
  1.1724 +      NS_ASSERTION(smallestPO, "There must always be an XMost PO!");
  1.1725 +      if (smallestPO) {
  1.1726 +        // Calc the shrinkage based on the entire content area
  1.1727 +        calcRatio = smallestPO->mShrinkRatio;
  1.1728 +      }
  1.1729 +    } else {
  1.1730 +      // Single document so use the Shrink as calculated for the PO
  1.1731 +      calcRatio = mPrt->mPrintObject->mShrinkRatio;
  1.1732 +    }
  1.1733 +    PR_PL(("**************************************************************************\n"));
  1.1734 +    PR_PL(("STF Ratio is: %8.5f Effective Ratio: %8.5f Diff: %8.5f\n", mPrt->mShrinkRatio, calcRatio,  mPrt->mShrinkRatio-calcRatio));
  1.1735 +    PR_PL(("**************************************************************************\n"));
  1.1736 +#endif
  1.1737 +  }
  1.1738 +  
  1.1739 +  // If the frames got reconstructed and reflowed the number of pages might
  1.1740 +  // has changed.
  1.1741 +  if (didReconstruction) {
  1.1742 +    FirePrintPreviewUpdateEvent();
  1.1743 +  }
  1.1744 +  
  1.1745 +  DUMP_DOC_LIST(("\nAfter Reflow------------------------------------------"));
  1.1746 +  PR_PL(("\n"));
  1.1747 +  PR_PL(("-------------------------------------------------------\n"));
  1.1748 +  PR_PL(("\n"));
  1.1749 +
  1.1750 +  CalcNumPrintablePages(mPrt->mNumPrintablePages);
  1.1751 +
  1.1752 +  PR_PL(("--- Printing %d pages\n", mPrt->mNumPrintablePages));
  1.1753 +  DUMP_DOC_TREELAYOUT;
  1.1754 +
  1.1755 +  // Print listener setup...
  1.1756 +  if (mPrt != nullptr) {
  1.1757 +    mPrt->OnStartPrinting();    
  1.1758 +  }
  1.1759 +
  1.1760 +  char16_t* fileName = nullptr;
  1.1761 +  // check to see if we are printing to a file
  1.1762 +  bool isPrintToFile = false;
  1.1763 +  mPrt->mPrintSettings->GetPrintToFile(&isPrintToFile);
  1.1764 +  if (isPrintToFile) {
  1.1765 +  // On some platforms The BeginDocument needs to know the name of the file
  1.1766 +  // and it uses the PrintService to get it, so we need to set it into the PrintService here
  1.1767 +    mPrt->mPrintSettings->GetToFileName(&fileName);
  1.1768 +  }
  1.1769 +
  1.1770 +  nsAutoString docTitleStr;
  1.1771 +  nsAutoString docURLStr;
  1.1772 +  GetDisplayTitleAndURL(mPrt->mPrintObject, docTitleStr, docURLStr, eDocTitleDefURLDoc);
  1.1773 +
  1.1774 +  int32_t startPage = 1;
  1.1775 +  int32_t endPage   = mPrt->mNumPrintablePages;
  1.1776 +
  1.1777 +  int16_t printRangeType = nsIPrintSettings::kRangeAllPages;
  1.1778 +  mPrt->mPrintSettings->GetPrintRange(&printRangeType);
  1.1779 +  if (printRangeType == nsIPrintSettings::kRangeSpecifiedPageRange) {
  1.1780 +    mPrt->mPrintSettings->GetStartPageRange(&startPage);
  1.1781 +    mPrt->mPrintSettings->GetEndPageRange(&endPage);
  1.1782 +    if (endPage > mPrt->mNumPrintablePages) {
  1.1783 +      endPage = mPrt->mNumPrintablePages;
  1.1784 +    }
  1.1785 +  }
  1.1786 +
  1.1787 +  rv = NS_OK;
  1.1788 +  // BeginDocument may pass back a FAILURE code
  1.1789 +  // i.e. On Windows, if you are printing to a file and hit "Cancel" 
  1.1790 +  //      to the "File Name" dialog, this comes back as an error
  1.1791 +  // Don't start printing when regression test are executed  
  1.1792 +  if (!mPrt->mDebugFilePtr && mIsDoingPrinting) {
  1.1793 +    rv = mPrt->mPrintDC->BeginDocument(docTitleStr, fileName, startPage, endPage);
  1.1794 +  } 
  1.1795 +
  1.1796 +  if (mIsCreatingPrintPreview) {
  1.1797 +    // Copy docTitleStr and docURLStr to the pageSequenceFrame, to be displayed
  1.1798 +    // in the header
  1.1799 +    nsIPageSequenceFrame *seqFrame = mPrt->mPrintObject->mPresShell->GetPageSequenceFrame();
  1.1800 +    if (seqFrame) {
  1.1801 +      seqFrame->StartPrint(mPrt->mPrintObject->mPresContext, 
  1.1802 +                           mPrt->mPrintSettings, docTitleStr, docURLStr);
  1.1803 +    }
  1.1804 +  }
  1.1805 +
  1.1806 +  PR_PL(("****************** Begin Document ************************\n"));
  1.1807 +
  1.1808 +  NS_ENSURE_SUCCESS(rv, rv);
  1.1809 +
  1.1810 +  // This will print the docshell document
  1.1811 +  // when it completes asynchronously in the DonePrintingPages method
  1.1812 +  // it will check to see if there are more docshells to be printed and
  1.1813 +  // then PrintDocContent will be called again.
  1.1814 +
  1.1815 +  if (mIsDoingPrinting) {
  1.1816 +    PrintDocContent(mPrt->mPrintObject, rv); // ignore return value
  1.1817 +  }
  1.1818 +
  1.1819 +  return rv;
  1.1820 +}
  1.1821 +
  1.1822 +//-------------------------------------------------------
  1.1823 +// Recursively reflow each sub-doc and then calc
  1.1824 +// all the frame locations of the sub-docs
  1.1825 +nsresult
  1.1826 +nsPrintEngine::ReflowDocList(nsPrintObject* aPO, bool aSetPixelScale)
  1.1827 +{
  1.1828 +  NS_ENSURE_ARG_POINTER(aPO);
  1.1829 +
  1.1830 +  // Check to see if the subdocument's element has been hidden by the parent document
  1.1831 +  if (aPO->mParent && aPO->mParent->mPresShell) {
  1.1832 +    nsIFrame* frame = aPO->mContent ? aPO->mContent->GetPrimaryFrame() : nullptr;
  1.1833 +    if (!frame || !frame->StyleVisibility()->IsVisible()) {
  1.1834 +      SetPrintPO(aPO, false);
  1.1835 +      aPO->mInvisible = true;
  1.1836 +      return NS_OK;
  1.1837 +    }
  1.1838 +  }
  1.1839 +
  1.1840 +  UpdateZoomRatio(aPO, aSetPixelScale);
  1.1841 +
  1.1842 +  nsresult rv;
  1.1843 +  // Reflow the PO
  1.1844 +  rv = ReflowPrintObject(aPO);
  1.1845 +  NS_ENSURE_SUCCESS(rv, rv);
  1.1846 +
  1.1847 +  int32_t cnt = aPO->mKids.Length();
  1.1848 +  for (int32_t i=0;i<cnt;i++) {
  1.1849 +    rv = ReflowDocList(aPO->mKids[i], aSetPixelScale);
  1.1850 +    NS_ENSURE_SUCCESS(rv, rv);
  1.1851 +  }
  1.1852 +  return NS_OK;
  1.1853 +}
  1.1854 +
  1.1855 +void
  1.1856 +nsPrintEngine::FirePrintPreviewUpdateEvent()
  1.1857 +{
  1.1858 +  // Dispatch the event only while in PrintPreview. When printing, there is no
  1.1859 +  // listener bound to this event and therefore no need to dispatch it.
  1.1860 +  if (mIsDoingPrintPreview && !mIsDoingPrinting) {
  1.1861 +    nsCOMPtr<nsIContentViewer> cv = do_QueryInterface(mDocViewerPrint);
  1.1862 +    (new AsyncEventDispatcher(
  1.1863 +       cv->GetDocument(), NS_LITERAL_STRING("printPreviewUpdate"), true, true)
  1.1864 +    )->RunDOMEventWhenSafe();
  1.1865 +  }
  1.1866 +}
  1.1867 +
  1.1868 +nsresult
  1.1869 +nsPrintEngine::InitPrintDocConstruction(bool aHandleError)
  1.1870 +{
  1.1871 +  nsresult rv;
  1.1872 +  rv = ReflowDocList(mPrt->mPrintObject, DoSetPixelScale());
  1.1873 +  NS_ENSURE_SUCCESS(rv, rv);
  1.1874 +
  1.1875 +  FirePrintPreviewUpdateEvent();
  1.1876 +
  1.1877 +  if (mLoadCounter == 0) {
  1.1878 +    AfterNetworkPrint(aHandleError);
  1.1879 +  }
  1.1880 +  return rv;
  1.1881 +}
  1.1882 +
  1.1883 +nsresult
  1.1884 +nsPrintEngine::AfterNetworkPrint(bool aHandleError)
  1.1885 +{
  1.1886 +  nsCOMPtr<nsIWebProgress> webProgress = do_QueryInterface(mPrt->mPrintObject->mDocShell);
  1.1887 +
  1.1888 +  webProgress->RemoveProgressListener(
  1.1889 +    static_cast<nsIWebProgressListener*>(this));
  1.1890 +
  1.1891 +  nsresult rv;
  1.1892 +  if (mIsDoingPrinting) {
  1.1893 +    rv = DocumentReadyForPrinting();
  1.1894 +  } else {
  1.1895 +    rv = FinishPrintPreview();
  1.1896 +  }
  1.1897 +
  1.1898 +  /* cleaup on failure + notify user */
  1.1899 +  if (aHandleError && NS_FAILED(rv)) {
  1.1900 +    CleanupOnFailure(rv, !mIsDoingPrinting);
  1.1901 +  }
  1.1902 +
  1.1903 +  return rv;
  1.1904 +}
  1.1905 +
  1.1906 +////////////////////////////////////////////////////////////////////////////////
  1.1907 +// nsIWebProgressListener
  1.1908 +
  1.1909 +NS_IMETHODIMP
  1.1910 +nsPrintEngine::OnStateChange(nsIWebProgress* aWebProgress,
  1.1911 +                             nsIRequest* aRequest,
  1.1912 +                             uint32_t aStateFlags,
  1.1913 +                             nsresult aStatus)
  1.1914 +{
  1.1915 +  nsAutoCString name;
  1.1916 +  aRequest->GetName(name);
  1.1917 +  if (name.Equals("about:document-onload-blocker")) {
  1.1918 +    return NS_OK;
  1.1919 +  }
  1.1920 +  if (aStateFlags & STATE_START) {
  1.1921 +    nsCOMPtr<nsIChannel> channel = do_QueryInterface(aRequest);
  1.1922 +
  1.1923 +    ++mLoadCounter;
  1.1924 +  } else if (aStateFlags & STATE_STOP) {
  1.1925 +    mDidLoadDataForPrinting = true;
  1.1926 +    --mLoadCounter;
  1.1927 +   
  1.1928 +    // If all resources are loaded, then do a small timeout and if there
  1.1929 +    // are still no new requests, then another reflow.
  1.1930 +    if (mLoadCounter == 0) {
  1.1931 +      AfterNetworkPrint(true);
  1.1932 +    }
  1.1933 +  }
  1.1934 +  return NS_OK;
  1.1935 +}
  1.1936 +
  1.1937 +
  1.1938 +
  1.1939 +NS_IMETHODIMP
  1.1940 +nsPrintEngine::OnProgressChange(nsIWebProgress* aWebProgress,
  1.1941 +                                 nsIRequest* aRequest,
  1.1942 +                                 int32_t aCurSelfProgress,
  1.1943 +                                 int32_t aMaxSelfProgress,
  1.1944 +                                 int32_t aCurTotalProgress,
  1.1945 +                                 int32_t aMaxTotalProgress)
  1.1946 +{
  1.1947 +  NS_NOTREACHED("notification excluded in AddProgressListener(...)");
  1.1948 +  return NS_OK;
  1.1949 +}
  1.1950 +
  1.1951 +NS_IMETHODIMP
  1.1952 +nsPrintEngine::OnLocationChange(nsIWebProgress* aWebProgress,
  1.1953 +                                nsIRequest* aRequest,
  1.1954 +                                nsIURI* aLocation,
  1.1955 +                                uint32_t aFlags)
  1.1956 +{
  1.1957 +  NS_NOTREACHED("notification excluded in AddProgressListener(...)");
  1.1958 +  return NS_OK;
  1.1959 +}
  1.1960 +
  1.1961 +NS_IMETHODIMP
  1.1962 +nsPrintEngine::OnStatusChange(nsIWebProgress *aWebProgress,
  1.1963 +                              nsIRequest *aRequest,
  1.1964 +                              nsresult aStatus,
  1.1965 +                              const char16_t *aMessage)
  1.1966 +{
  1.1967 +  NS_NOTREACHED("notification excluded in AddProgressListener(...)");
  1.1968 +  return NS_OK;
  1.1969 +}
  1.1970 +
  1.1971 +NS_IMETHODIMP
  1.1972 +nsPrintEngine::OnSecurityChange(nsIWebProgress *aWebProgress,
  1.1973 +                                  nsIRequest *aRequest,
  1.1974 +                                  uint32_t aState)
  1.1975 +{
  1.1976 +  NS_NOTREACHED("notification excluded in AddProgressListener(...)");
  1.1977 +  return NS_OK;
  1.1978 +}
  1.1979 +
  1.1980 +//-------------------------------------------------------
  1.1981 +
  1.1982 +void
  1.1983 +nsPrintEngine::UpdateZoomRatio(nsPrintObject* aPO, bool aSetPixelScale)
  1.1984 +{
  1.1985 +  // Here is where we set the shrinkage value into the DC
  1.1986 +  // and this is what actually makes it shrink
  1.1987 +  if (aSetPixelScale && aPO->mFrameType != eIFrame) {
  1.1988 +    float ratio;
  1.1989 +    if (mPrt->mPrintFrameType == nsIPrintSettings::kFramesAsIs || mPrt->mPrintFrameType == nsIPrintSettings::kNoFrames) {
  1.1990 +      ratio = mPrt->mShrinkRatio - 0.005f; // round down
  1.1991 +    } else {
  1.1992 +      ratio = aPO->mShrinkRatio - 0.005f; // round down
  1.1993 +    }
  1.1994 +    aPO->mZoomRatio = ratio;
  1.1995 +  } else if (!mPrt->mShrinkToFit) {
  1.1996 +    double scaling;
  1.1997 +    mPrt->mPrintSettings->GetScaling(&scaling);
  1.1998 +    aPO->mZoomRatio = float(scaling);
  1.1999 +  } 
  1.2000 +}
  1.2001 +
  1.2002 +nsresult
  1.2003 +nsPrintEngine::UpdateSelectionAndShrinkPrintObject(nsPrintObject* aPO,
  1.2004 +                                                   bool aDocumentIsTopLevel)
  1.2005 +{
  1.2006 +  nsCOMPtr<nsIPresShell> displayShell = aPO->mDocShell->GetPresShell();
  1.2007 +  // Transfer Selection Ranges to the new Print PresShell
  1.2008 +  nsRefPtr<Selection> selection, selectionPS;
  1.2009 +  // It's okay if there is no display shell, just skip copying the selection
  1.2010 +  if (displayShell) {
  1.2011 +    selection = displayShell->GetCurrentSelection(nsISelectionController::SELECTION_NORMAL);
  1.2012 +  }
  1.2013 +  selectionPS = aPO->mPresShell->GetCurrentSelection(nsISelectionController::SELECTION_NORMAL);
  1.2014 +
  1.2015 +  // Reset all existing selection ranges that might have been added by calling
  1.2016 +  // this function before.
  1.2017 +  if (selectionPS) {
  1.2018 +    selectionPS->RemoveAllRanges();
  1.2019 +  }
  1.2020 +  if (selection && selectionPS) {
  1.2021 +    int32_t cnt = selection->GetRangeCount();
  1.2022 +    int32_t inx;
  1.2023 +    for (inx = 0; inx < cnt; ++inx) {
  1.2024 +        selectionPS->AddRange(selection->GetRangeAt(inx));
  1.2025 +    }
  1.2026 +  }
  1.2027 +
  1.2028 +  // If we are trying to shrink the contents to fit on the page
  1.2029 +  // we must first locate the "pageContent" frame
  1.2030 +  // Then we walk the frame tree and look for the "xmost" frame
  1.2031 +  // this is the frame where the right-hand side of the frame extends
  1.2032 +  // the furthest
  1.2033 +  if (mPrt->mShrinkToFit && aDocumentIsTopLevel) {
  1.2034 +    nsIPageSequenceFrame* pageSequence = aPO->mPresShell->GetPageSequenceFrame();
  1.2035 +    NS_ENSURE_STATE(pageSequence);
  1.2036 +    pageSequence->GetSTFPercent(aPO->mShrinkRatio);
  1.2037 +    // Limit the shrink-to-fit scaling for some text-ish type of documents.
  1.2038 +    nsAutoString contentType;
  1.2039 +    aPO->mPresShell->GetDocument()->GetContentType(contentType);
  1.2040 +    if (contentType.EqualsLiteral("application/xhtml+xml") ||
  1.2041 +        StringBeginsWith(contentType, NS_LITERAL_STRING("text/"))) {
  1.2042 +      int32_t limitPercent = 
  1.2043 +        Preferences::GetInt("print.shrink-to-fit.scale-limit-percent", 20);
  1.2044 +      limitPercent = std::max(0, limitPercent);
  1.2045 +      limitPercent = std::min(100, limitPercent);
  1.2046 +      float minShrinkRatio = float(limitPercent) / 100;
  1.2047 +      aPO->mShrinkRatio = std::max(aPO->mShrinkRatio, minShrinkRatio);
  1.2048 +    }
  1.2049 +  }
  1.2050 +  return NS_OK;
  1.2051 +}
  1.2052 +
  1.2053 +bool
  1.2054 +nsPrintEngine::DoSetPixelScale()
  1.2055 +{
  1.2056 +  // This is an Optimization
  1.2057 +  // If we are in PP then we already know all the shrinkage information
  1.2058 +  // so just transfer it to the PrintData and we will skip the extra shrinkage reflow
  1.2059 +  //
  1.2060 +  // doSetPixelScale tells Reflow whether to set the shrinkage value into the DC
  1.2061 +  // The first time we do not want to do this, the second time through we do
  1.2062 +  bool doSetPixelScale = false;
  1.2063 +  bool ppIsShrinkToFit = mPrtPreview && mPrtPreview->mShrinkToFit;
  1.2064 +  if (ppIsShrinkToFit) {
  1.2065 +    mPrt->mShrinkRatio = mPrtPreview->mShrinkRatio;
  1.2066 +    doSetPixelScale = true;
  1.2067 +  }
  1.2068 +  return doSetPixelScale;
  1.2069 +}
  1.2070 +
  1.2071 +nsView*
  1.2072 +nsPrintEngine::GetParentViewForRoot()
  1.2073 +{
  1.2074 +  if (mIsCreatingPrintPreview) {
  1.2075 +    nsCOMPtr<nsIContentViewer> cv = do_QueryInterface(mDocViewerPrint);
  1.2076 +    if (cv) {
  1.2077 +      return cv->FindContainerView();
  1.2078 +    }
  1.2079 +  }
  1.2080 +  return nullptr;
  1.2081 +}
  1.2082 +
  1.2083 +nsresult
  1.2084 +nsPrintEngine::SetRootView(
  1.2085 +    nsPrintObject* aPO, 
  1.2086 +    bool& doReturn, 
  1.2087 +    bool& documentIsTopLevel, 
  1.2088 +    nsSize& adjSize
  1.2089 +)
  1.2090 +{
  1.2091 +  bool canCreateScrollbars = true;
  1.2092 +
  1.2093 +  nsView* rootView;
  1.2094 +  nsView* parentView = nullptr;
  1.2095 +
  1.2096 +  doReturn = false;
  1.2097 +
  1.2098 +  if (aPO->mParent && aPO->mParent->IsPrintable()) {
  1.2099 +    nsIFrame* frame = aPO->mContent ? aPO->mContent->GetPrimaryFrame() : nullptr;
  1.2100 +    // Without a frame, this document can't be displayed; therefore, there is no
  1.2101 +    // point to reflowing it
  1.2102 +    if (!frame) {
  1.2103 +      SetPrintPO(aPO, false);
  1.2104 +      doReturn = true;
  1.2105 +      return NS_OK;
  1.2106 +    }
  1.2107 +
  1.2108 +    //XXX If printing supported printing document hierarchies with non-constant
  1.2109 +    // zoom this would be wrong as we use the same mPrt->mPrintDC for all
  1.2110 +    // subdocuments.
  1.2111 +    adjSize = frame->GetContentRect().Size();
  1.2112 +    documentIsTopLevel = false;
  1.2113 +    // presshell exists because parent is printable
  1.2114 +
  1.2115 +    // the top nsPrintObject's widget will always have scrollbars
  1.2116 +    if (frame && frame->GetType() == nsGkAtoms::subDocumentFrame) {
  1.2117 +      nsView* view = frame->GetView();
  1.2118 +      NS_ENSURE_TRUE(view, NS_ERROR_FAILURE);
  1.2119 +      view = view->GetFirstChild();
  1.2120 +      NS_ENSURE_TRUE(view, NS_ERROR_FAILURE);
  1.2121 +      parentView = view;
  1.2122 +      canCreateScrollbars = false;
  1.2123 +    }
  1.2124 +  } else {
  1.2125 +    nscoord pageWidth, pageHeight;
  1.2126 +    mPrt->mPrintDC->GetDeviceSurfaceDimensions(pageWidth, pageHeight);
  1.2127 +    adjSize = nsSize(pageWidth, pageHeight);
  1.2128 +    documentIsTopLevel = true;
  1.2129 +    parentView = GetParentViewForRoot();
  1.2130 +  }
  1.2131 +
  1.2132 +  if (aPO->mViewManager->GetRootView()) {
  1.2133 +    // Reuse the root view that is already on the root frame.
  1.2134 +    rootView = aPO->mViewManager->GetRootView();
  1.2135 +    // Remove it from its existing parent if necessary
  1.2136 +    aPO->mViewManager->RemoveChild(rootView);
  1.2137 +    rootView->SetParent(parentView);
  1.2138 +  } else {
  1.2139 +    // Create a child window of the parent that is our "root view/window"
  1.2140 +    nsRect tbounds = nsRect(nsPoint(0, 0), adjSize);
  1.2141 +    rootView = aPO->mViewManager->CreateView(tbounds, parentView);
  1.2142 +    NS_ENSURE_TRUE(rootView, NS_ERROR_OUT_OF_MEMORY);
  1.2143 +  }
  1.2144 +    
  1.2145 +  if (mIsCreatingPrintPreview && documentIsTopLevel) {
  1.2146 +    aPO->mPresContext->SetPaginatedScrolling(canCreateScrollbars);
  1.2147 +  }
  1.2148 +
  1.2149 +  // Setup hierarchical relationship in view manager
  1.2150 +  aPO->mViewManager->SetRootView(rootView);
  1.2151 +
  1.2152 +  return NS_OK;
  1.2153 +}
  1.2154 +
  1.2155 +// Reflow a nsPrintObject
  1.2156 +nsresult
  1.2157 +nsPrintEngine::ReflowPrintObject(nsPrintObject * aPO)
  1.2158 +{
  1.2159 +  NS_ENSURE_STATE(aPO);
  1.2160 +
  1.2161 +  if (!aPO->IsPrintable()) {
  1.2162 +    return NS_OK;
  1.2163 +  }
  1.2164 +  
  1.2165 +  NS_ASSERTION(!aPO->mPresContext, "Recreating prescontext");
  1.2166 +
  1.2167 +  // create the PresContext
  1.2168 +  nsPresContext::nsPresContextType type =
  1.2169 +      mIsCreatingPrintPreview ? nsPresContext::eContext_PrintPreview:
  1.2170 +                                nsPresContext::eContext_Print;
  1.2171 +  nsView* parentView =
  1.2172 +    aPO->mParent && aPO->mParent->IsPrintable() ? nullptr : GetParentViewForRoot();
  1.2173 +  aPO->mPresContext = parentView ?
  1.2174 +      new nsPresContext(aPO->mDocument, type) :
  1.2175 +      new nsRootPresContext(aPO->mDocument, type);
  1.2176 +  NS_ENSURE_TRUE(aPO->mPresContext, NS_ERROR_OUT_OF_MEMORY);
  1.2177 +  aPO->mPresContext->SetPrintSettings(mPrt->mPrintSettings);
  1.2178 +
  1.2179 +  // set the presentation context to the value in the print settings
  1.2180 +  bool printBGColors;
  1.2181 +  mPrt->mPrintSettings->GetPrintBGColors(&printBGColors);
  1.2182 +  aPO->mPresContext->SetBackgroundColorDraw(printBGColors);
  1.2183 +  mPrt->mPrintSettings->GetPrintBGImages(&printBGColors);
  1.2184 +  aPO->mPresContext->SetBackgroundImageDraw(printBGColors);
  1.2185 +
  1.2186 +  // init it with the DC
  1.2187 +  nsresult rv = aPO->mPresContext->Init(mPrt->mPrintDC);
  1.2188 +  NS_ENSURE_SUCCESS(rv, rv);
  1.2189 +
  1.2190 +  aPO->mViewManager = new nsViewManager();
  1.2191 +
  1.2192 +  rv = aPO->mViewManager->Init(mPrt->mPrintDC);
  1.2193 +  NS_ENSURE_SUCCESS(rv,rv);
  1.2194 +
  1.2195 +  nsStyleSet* styleSet;
  1.2196 +  rv = mDocViewerPrint->CreateStyleSet(aPO->mDocument, &styleSet);
  1.2197 +  NS_ENSURE_SUCCESS(rv, rv);
  1.2198 +
  1.2199 +  aPO->mPresShell = aPO->mDocument->CreateShell(aPO->mPresContext,
  1.2200 +                                                aPO->mViewManager, styleSet);
  1.2201 +  if (!aPO->mPresShell) {
  1.2202 +    delete styleSet;
  1.2203 +    return NS_ERROR_FAILURE;
  1.2204 +  }
  1.2205 +
  1.2206 +  styleSet->EndUpdate();
  1.2207 +  
  1.2208 +  // The pres shell now owns the style set object.
  1.2209 +
  1.2210 +
  1.2211 +  bool doReturn = false;;
  1.2212 +  bool documentIsTopLevel = false;
  1.2213 +  nsSize adjSize; 
  1.2214 +
  1.2215 +  rv = SetRootView(aPO, doReturn, documentIsTopLevel, adjSize);
  1.2216 +
  1.2217 +  if (NS_FAILED(rv) || doReturn) {
  1.2218 +    return rv; 
  1.2219 +  }
  1.2220 +
  1.2221 +  PR_PL(("In DV::ReflowPrintObject PO: %p pS: %p (%9s) Setting w,h to %d,%d\n", aPO, aPO->mPresShell.get(),
  1.2222 +         gFrameTypesStr[aPO->mFrameType], adjSize.width, adjSize.height));
  1.2223 +
  1.2224 +
  1.2225 +  // This docshell stuff is weird; will go away when we stop having multiple
  1.2226 +  // presentations per document
  1.2227 +  aPO->mPresContext->SetContainer(aPO->mDocShell);
  1.2228 +
  1.2229 +  aPO->mPresShell->BeginObservingDocument();
  1.2230 +
  1.2231 +  aPO->mPresContext->SetPageSize(adjSize);
  1.2232 +  aPO->mPresContext->SetIsRootPaginatedDocument(documentIsTopLevel);
  1.2233 +  aPO->mPresContext->SetPageScale(aPO->mZoomRatio);
  1.2234 +  // Calculate scale factor from printer to screen
  1.2235 +  float printDPI = float(mPrt->mPrintDC->AppUnitsPerCSSInch()) /
  1.2236 +                   float(mPrt->mPrintDC->AppUnitsPerDevPixel());
  1.2237 +  aPO->mPresContext->SetPrintPreviewScale(mScreenDPI / printDPI);
  1.2238 +
  1.2239 +  if (mIsCreatingPrintPreview && documentIsTopLevel) {
  1.2240 +    mDocViewerPrint->SetPrintPreviewPresentation(aPO->mViewManager,
  1.2241 +                                                 aPO->mPresContext,
  1.2242 +                                                 aPO->mPresShell);
  1.2243 +  }
  1.2244 +
  1.2245 +  rv = aPO->mPresShell->Initialize(adjSize.width, adjSize.height);
  1.2246 +
  1.2247 +  NS_ENSURE_SUCCESS(rv, rv);
  1.2248 +  NS_ASSERTION(aPO->mPresShell, "Presshell should still be here");
  1.2249 +
  1.2250 +  // Process the reflow event Initialize posted
  1.2251 +  aPO->mPresShell->FlushPendingNotifications(Flush_Layout);
  1.2252 +
  1.2253 +  rv = UpdateSelectionAndShrinkPrintObject(aPO, documentIsTopLevel);
  1.2254 +  NS_ENSURE_SUCCESS(rv, rv);
  1.2255 +
  1.2256 +#ifdef EXTENDED_DEBUG_PRINTING
  1.2257 +    if (kPrintingLogMod && kPrintingLogMod->level == DUMP_LAYOUT_LEVEL) {
  1.2258 +      nsAutoCString docStr;
  1.2259 +      nsAutoCString urlStr;
  1.2260 +      GetDocTitleAndURL(aPO, docStr, urlStr);
  1.2261 +      char filename[256];
  1.2262 +      sprintf(filename, "print_dump_%d.txt", gDumpFileNameCnt++);
  1.2263 +      // Dump all the frames and view to a a file
  1.2264 +      FILE * fd = fopen(filename, "w");
  1.2265 +      if (fd) {
  1.2266 +        nsIFrame *theRootFrame =
  1.2267 +          aPO->mPresShell->FrameManager()->GetRootFrame();
  1.2268 +        fprintf(fd, "Title: %s\n", docStr.get());
  1.2269 +        fprintf(fd, "URL:   %s\n", urlStr.get());
  1.2270 +        fprintf(fd, "--------------- Frames ----------------\n");
  1.2271 +        nsRefPtr<nsRenderingContext> renderingContext =
  1.2272 +          mPrt->mPrintDocDC->CreateRenderingContext();
  1.2273 +        RootFrameList(aPO->mPresContext, fd, 0);
  1.2274 +        //DumpFrames(fd, aPO->mPresContext, renderingContext, theRootFrame, 0);
  1.2275 +        fprintf(fd, "---------------------------------------\n\n");
  1.2276 +        fprintf(fd, "--------------- Views From Root Frame----------------\n");
  1.2277 +        nsView* v = theRootFrame->GetView();
  1.2278 +        if (v) {
  1.2279 +          v->List(fd);
  1.2280 +        } else {
  1.2281 +          printf("View is null!\n");
  1.2282 +        }
  1.2283 +        if (docShell) {
  1.2284 +          fprintf(fd, "--------------- All Views ----------------\n");
  1.2285 +          DumpViews(docShell, fd);
  1.2286 +          fprintf(fd, "---------------------------------------\n\n");
  1.2287 +        }
  1.2288 +        fclose(fd);
  1.2289 +      }
  1.2290 +    }
  1.2291 +#endif
  1.2292 +
  1.2293 +  return NS_OK;
  1.2294 +}
  1.2295 +
  1.2296 +//-------------------------------------------------------
  1.2297 +// Figure out how many documents and how many total pages we are printing
  1.2298 +void
  1.2299 +nsPrintEngine::CalcNumPrintablePages(int32_t& aNumPages)
  1.2300 +{
  1.2301 +  aNumPages = 0;
  1.2302 +  // Count the number of printable documents
  1.2303 +  // and printable pages
  1.2304 +  for (uint32_t i=0; i<mPrt->mPrintDocList.Length(); i++) {
  1.2305 +    nsPrintObject* po = mPrt->mPrintDocList.ElementAt(i);
  1.2306 +    NS_ASSERTION(po, "nsPrintObject can't be null!");
  1.2307 +    if (po->mPresContext && po->mPresContext->IsRootPaginatedDocument()) {
  1.2308 +      nsIPageSequenceFrame* pageSequence = po->mPresShell->GetPageSequenceFrame();
  1.2309 +      nsIFrame * seqFrame = do_QueryFrame(pageSequence);
  1.2310 +      if (seqFrame) {
  1.2311 +        nsIFrame* frame = seqFrame->GetFirstPrincipalChild();
  1.2312 +        while (frame) {
  1.2313 +          aNumPages++;
  1.2314 +          frame = frame->GetNextSibling();
  1.2315 +        }
  1.2316 +      }
  1.2317 +    }
  1.2318 +  }
  1.2319 +}
  1.2320 +
  1.2321 +//-----------------------------------------------------------------
  1.2322 +//-- Done: Reflow Methods
  1.2323 +//-----------------------------------------------------------------
  1.2324 +
  1.2325 +//-----------------------------------------------------------------
  1.2326 +//-- Section: Printing Methods
  1.2327 +//-----------------------------------------------------------------
  1.2328 +
  1.2329 +//-------------------------------------------------------
  1.2330 +// Called for each DocShell that needs to be printed
  1.2331 +bool
  1.2332 +nsPrintEngine::PrintDocContent(nsPrintObject* aPO, nsresult& aStatus)
  1.2333 +{
  1.2334 +  NS_ASSERTION(aPO, "Pointer is null!");
  1.2335 +  aStatus = NS_OK;
  1.2336 +
  1.2337 +  if (!aPO->mHasBeenPrinted && aPO->IsPrintable()) {
  1.2338 +    aStatus = DoPrint(aPO);
  1.2339 +    return true;
  1.2340 +  }
  1.2341 +
  1.2342 +  // If |aPO->mPrintAsIs| and |aPO->mHasBeenPrinted| are true,
  1.2343 +  // the kids frames are already processed in |PrintPage|.
  1.2344 +  if (!aPO->mInvisible && !(aPO->mPrintAsIs && aPO->mHasBeenPrinted)) {
  1.2345 +    for (uint32_t i=0;i<aPO->mKids.Length();i++) {
  1.2346 +      nsPrintObject* po = aPO->mKids[i];
  1.2347 +      bool printed = PrintDocContent(po, aStatus);
  1.2348 +      if (printed || NS_FAILED(aStatus)) {
  1.2349 +        return true;
  1.2350 +      }
  1.2351 +    }
  1.2352 +  }
  1.2353 +  return false;
  1.2354 +}
  1.2355 +
  1.2356 +static already_AddRefed<nsIDOMNode>
  1.2357 +GetEqualNodeInCloneTree(nsIDOMNode* aNode, nsIDocument* aDoc)
  1.2358 +{
  1.2359 +  nsCOMPtr<nsIContent> content = do_QueryInterface(aNode);
  1.2360 +  // Selections in anonymous subtrees aren't supported.
  1.2361 +  if (content && content->IsInAnonymousSubtree()) {
  1.2362 +    return nullptr;
  1.2363 +  }
  1.2364 +
  1.2365 +  nsCOMPtr<nsINode> node = do_QueryInterface(aNode);
  1.2366 +  NS_ENSURE_TRUE(node, nullptr);
  1.2367 +
  1.2368 +  nsTArray<int32_t> indexArray;
  1.2369 +  nsINode* current = node;
  1.2370 +  NS_ENSURE_TRUE(current, nullptr);
  1.2371 +  while (current) {
  1.2372 +    nsINode* parent = current->GetParentNode();
  1.2373 +    if (!parent) {
  1.2374 +     break;
  1.2375 +    }
  1.2376 +    int32_t index = parent->IndexOf(current);
  1.2377 +    NS_ENSURE_TRUE(index >= 0, nullptr);
  1.2378 +    indexArray.AppendElement(index);
  1.2379 +    current = parent;
  1.2380 +  }
  1.2381 +  NS_ENSURE_TRUE(current->IsNodeOfType(nsINode::eDOCUMENT), nullptr);
  1.2382 +
  1.2383 +  current = aDoc;
  1.2384 +  for (int32_t i = indexArray.Length() - 1; i >= 0; --i) {
  1.2385 +    current = current->GetChildAt(indexArray[i]);
  1.2386 +    NS_ENSURE_TRUE(current, nullptr);
  1.2387 +  }
  1.2388 +  nsCOMPtr<nsIDOMNode> result = do_QueryInterface(current);
  1.2389 +  return result.forget();
  1.2390 +}
  1.2391 +
  1.2392 +static void
  1.2393 +CloneRangeToSelection(nsRange* aRange, nsIDocument* aDoc,
  1.2394 +                      Selection* aSelection)
  1.2395 +{
  1.2396 +  if (aRange->Collapsed()) {
  1.2397 +    return;
  1.2398 +  }
  1.2399 +
  1.2400 +  nsCOMPtr<nsIDOMNode> startContainer, endContainer;
  1.2401 +  aRange->GetStartContainer(getter_AddRefs(startContainer));
  1.2402 +  int32_t startOffset = aRange->StartOffset();
  1.2403 +  aRange->GetEndContainer(getter_AddRefs(endContainer));
  1.2404 +  int32_t endOffset = aRange->EndOffset();
  1.2405 +  NS_ENSURE_TRUE_VOID(startContainer && endContainer);
  1.2406 +
  1.2407 +  nsCOMPtr<nsIDOMNode> newStart = GetEqualNodeInCloneTree(startContainer, aDoc);
  1.2408 +  nsCOMPtr<nsIDOMNode> newEnd = GetEqualNodeInCloneTree(endContainer, aDoc);
  1.2409 +  NS_ENSURE_TRUE_VOID(newStart && newEnd);
  1.2410 +
  1.2411 +  nsCOMPtr<nsINode> newStartNode = do_QueryInterface(newStart);
  1.2412 +  NS_ENSURE_TRUE_VOID(newStartNode);
  1.2413 +
  1.2414 +  nsRefPtr<nsRange> range = new nsRange(newStartNode);
  1.2415 +  nsresult rv = range->SetStart(newStartNode, startOffset);
  1.2416 +  NS_ENSURE_SUCCESS_VOID(rv);
  1.2417 +  rv = range->SetEnd(newEnd, endOffset);
  1.2418 +  NS_ENSURE_SUCCESS_VOID(rv);
  1.2419 +
  1.2420 +  aSelection->AddRange(range);
  1.2421 +}
  1.2422 +
  1.2423 +static nsresult CloneSelection(nsIDocument* aOrigDoc, nsIDocument* aDoc)
  1.2424 +{
  1.2425 +  nsIPresShell* origShell = aOrigDoc->GetShell();
  1.2426 +  nsIPresShell* shell = aDoc->GetShell();
  1.2427 +  NS_ENSURE_STATE(origShell && shell);
  1.2428 +
  1.2429 +  nsRefPtr<Selection> origSelection =
  1.2430 +    origShell->GetCurrentSelection(nsISelectionController::SELECTION_NORMAL);
  1.2431 +  nsRefPtr<Selection> selection =
  1.2432 +    shell->GetCurrentSelection(nsISelectionController::SELECTION_NORMAL);
  1.2433 +  NS_ENSURE_STATE(origSelection && selection);
  1.2434 +
  1.2435 +  int32_t rangeCount = origSelection->GetRangeCount();
  1.2436 +  for (int32_t i = 0; i < rangeCount; ++i) {
  1.2437 +      CloneRangeToSelection(origSelection->GetRangeAt(i), aDoc, selection);
  1.2438 +  }
  1.2439 +  return NS_OK;
  1.2440 +}
  1.2441 +
  1.2442 +//-------------------------------------------------------
  1.2443 +nsresult
  1.2444 +nsPrintEngine::DoPrint(nsPrintObject * aPO)
  1.2445 +{
  1.2446 +  PR_PL(("\n"));
  1.2447 +  PR_PL(("**************************** %s ****************************\n", gFrameTypesStr[aPO->mFrameType]));
  1.2448 +  PR_PL(("****** In DV::DoPrint   PO: %p \n", aPO));
  1.2449 +
  1.2450 +  nsIPresShell*   poPresShell   = aPO->mPresShell;
  1.2451 +  nsPresContext*  poPresContext = aPO->mPresContext;
  1.2452 +
  1.2453 +  NS_ASSERTION(poPresContext, "PrintObject has not been reflowed");
  1.2454 +  NS_ASSERTION(poPresContext->Type() != nsPresContext::eContext_PrintPreview,
  1.2455 +               "How did this context end up here?");
  1.2456 +
  1.2457 +  if (mPrt->mPrintProgressParams) {
  1.2458 +    SetDocAndURLIntoProgress(aPO, mPrt->mPrintProgressParams);
  1.2459 +  }
  1.2460 +
  1.2461 +  {
  1.2462 +    int16_t printRangeType = nsIPrintSettings::kRangeAllPages;
  1.2463 +    nsresult rv;
  1.2464 +    if (mPrt->mPrintSettings != nullptr) {
  1.2465 +      mPrt->mPrintSettings->GetPrintRange(&printRangeType);
  1.2466 +    }
  1.2467 +
  1.2468 +    // Ask the page sequence frame to print all the pages
  1.2469 +    nsIPageSequenceFrame* pageSequence = poPresShell->GetPageSequenceFrame();
  1.2470 +    NS_ASSERTION(nullptr != pageSequence, "no page sequence frame");
  1.2471 +
  1.2472 +    // We are done preparing for printing, so we can turn this off
  1.2473 +    mPrt->mPreparingForPrint = false;
  1.2474 +
  1.2475 +    // mPrt->mDebugFilePtr this is onlu non-null when compiled for debugging
  1.2476 +    if (nullptr != mPrt->mDebugFilePtr) {
  1.2477 +#ifdef DEBUG
  1.2478 +      // output the regression test
  1.2479 +      nsIFrame* root = poPresShell->FrameManager()->GetRootFrame();
  1.2480 +      root->DumpRegressionData(poPresContext, mPrt->mDebugFilePtr, 0);
  1.2481 +      fclose(mPrt->mDebugFilePtr);
  1.2482 +      SetIsPrinting(false);
  1.2483 +#endif
  1.2484 +    } else {
  1.2485 +#ifdef EXTENDED_DEBUG_PRINTING
  1.2486 +      nsIFrame* rootFrame = poPresShell->FrameManager()->GetRootFrame();
  1.2487 +      if (aPO->IsPrintable()) {
  1.2488 +        nsAutoCString docStr;
  1.2489 +        nsAutoCString urlStr;
  1.2490 +        GetDocTitleAndURL(aPO, docStr, urlStr);
  1.2491 +        DumpLayoutData(docStr.get(), urlStr.get(), poPresContext, mPrt->mPrintDocDC, rootFrame, docShell, nullptr);
  1.2492 +      }
  1.2493 +#endif
  1.2494 +
  1.2495 +      if (!mPrt->mPrintSettings) {
  1.2496 +        // not sure what to do here!
  1.2497 +        SetIsPrinting(false);
  1.2498 +        return NS_ERROR_FAILURE;
  1.2499 +      }
  1.2500 +
  1.2501 +      nsAutoString docTitleStr;
  1.2502 +      nsAutoString docURLStr;
  1.2503 +      GetDisplayTitleAndURL(aPO, docTitleStr, docURLStr, eDocTitleDefBlank);
  1.2504 +
  1.2505 +      if (nsIPrintSettings::kRangeSelection == printRangeType) {
  1.2506 +        CloneSelection(aPO->mDocument->GetOriginalDocument(), aPO->mDocument);
  1.2507 +
  1.2508 +        poPresContext->SetIsRenderingOnlySelection(true);
  1.2509 +        // temporarily creating rendering context
  1.2510 +        // which is needed to find the selection frames
  1.2511 +        nsRefPtr<nsRenderingContext> rc =
  1.2512 +          mPrt->mPrintDC->CreateRenderingContext();
  1.2513 +
  1.2514 +        // find the starting and ending page numbers
  1.2515 +        // via the selection
  1.2516 +        nsIFrame* startFrame;
  1.2517 +        nsIFrame* endFrame;
  1.2518 +        int32_t   startPageNum;
  1.2519 +        int32_t   endPageNum;
  1.2520 +        nsRect    startRect;
  1.2521 +        nsRect    endRect;
  1.2522 +
  1.2523 +        nsRefPtr<Selection> selectionPS =
  1.2524 +          poPresShell->GetCurrentSelection(nsISelectionController::SELECTION_NORMAL);
  1.2525 +
  1.2526 +        rv = GetPageRangeForSelection(poPresShell, poPresContext, *rc, selectionPS, pageSequence,
  1.2527 +                                      &startFrame, startPageNum, startRect,
  1.2528 +                                      &endFrame, endPageNum, endRect);
  1.2529 +        if (NS_SUCCEEDED(rv)) {
  1.2530 +          mPrt->mPrintSettings->SetStartPageRange(startPageNum);
  1.2531 +          mPrt->mPrintSettings->SetEndPageRange(endPageNum);
  1.2532 +          nsIntMargin marginTwips(0,0,0,0);
  1.2533 +          nsIntMargin unwrtMarginTwips(0,0,0,0);
  1.2534 +          mPrt->mPrintSettings->GetMarginInTwips(marginTwips);
  1.2535 +          mPrt->mPrintSettings->GetUnwriteableMarginInTwips(unwrtMarginTwips);
  1.2536 +          nsMargin totalMargin = poPresContext->CSSTwipsToAppUnits(marginTwips +
  1.2537 +                                                                   unwrtMarginTwips);
  1.2538 +          if (startPageNum == endPageNum) {
  1.2539 +            startRect.y -= totalMargin.top;
  1.2540 +            endRect.y   -= totalMargin.top;
  1.2541 +
  1.2542 +            // Clip out selection regions above the top of the first page
  1.2543 +            if (startRect.y < 0) {
  1.2544 +              // Reduce height to be the height of the positive-territory
  1.2545 +              // region of original rect
  1.2546 +              startRect.height = std::max(0, startRect.YMost());
  1.2547 +              startRect.y = 0;
  1.2548 +            }
  1.2549 +            if (endRect.y < 0) {
  1.2550 +              // Reduce height to be the height of the positive-territory
  1.2551 +              // region of original rect
  1.2552 +              endRect.height = std::max(0, endRect.YMost());
  1.2553 +              endRect.y = 0;
  1.2554 +            }
  1.2555 +            NS_ASSERTION(endRect.y >= startRect.y,
  1.2556 +                         "Selection end point should be after start point");
  1.2557 +            NS_ASSERTION(startRect.height >= 0,
  1.2558 +                         "rect should have non-negative height.");
  1.2559 +            NS_ASSERTION(endRect.height >= 0,
  1.2560 +                         "rect should have non-negative height.");
  1.2561 +
  1.2562 +            nscoord selectionHgt = endRect.y + endRect.height - startRect.y;
  1.2563 +            // XXX This is temporary fix for printing more than one page of a selection
  1.2564 +            pageSequence->SetSelectionHeight(startRect.y * aPO->mZoomRatio,
  1.2565 +                                             selectionHgt * aPO->mZoomRatio);
  1.2566 +
  1.2567 +            // calc total pages by getting calculating the selection's height
  1.2568 +            // and then dividing it by how page content frames will fit.
  1.2569 +            nscoord pageWidth, pageHeight;
  1.2570 +            mPrt->mPrintDC->GetDeviceSurfaceDimensions(pageWidth, pageHeight);
  1.2571 +            pageHeight -= totalMargin.top + totalMargin.bottom;
  1.2572 +            int32_t totalPages = NSToIntCeil(float(selectionHgt) * aPO->mZoomRatio / float(pageHeight));
  1.2573 +            pageSequence->SetTotalNumPages(totalPages);
  1.2574 +          }
  1.2575 +        }
  1.2576 +      }
  1.2577 +
  1.2578 +      nsIFrame * seqFrame = do_QueryFrame(pageSequence);
  1.2579 +      if (!seqFrame) {
  1.2580 +        SetIsPrinting(false);
  1.2581 +        return NS_ERROR_FAILURE;
  1.2582 +      }
  1.2583 +
  1.2584 +      mPageSeqFrame = pageSequence;
  1.2585 +      mPageSeqFrame->StartPrint(poPresContext, mPrt->mPrintSettings, docTitleStr, docURLStr);
  1.2586 +
  1.2587 +      // Schedule Page to Print
  1.2588 +      PR_PL(("Scheduling Print of PO: %p (%s) \n", aPO, gFrameTypesStr[aPO->mFrameType]));
  1.2589 +      StartPagePrintTimer(aPO);
  1.2590 +    }
  1.2591 +  }
  1.2592 +
  1.2593 +  return NS_OK;
  1.2594 +}
  1.2595 +
  1.2596 +//---------------------------------------------------------------------
  1.2597 +void
  1.2598 +nsPrintEngine::SetDocAndURLIntoProgress(nsPrintObject* aPO,
  1.2599 +                                        nsIPrintProgressParams* aParams)
  1.2600 +{
  1.2601 +  NS_ASSERTION(aPO, "Must have valid nsPrintObject");
  1.2602 +  NS_ASSERTION(aParams, "Must have valid nsIPrintProgressParams");
  1.2603 +
  1.2604 +  if (!aPO || !aPO->mDocShell || !aParams) {
  1.2605 +    return;
  1.2606 +  }
  1.2607 +  const uint32_t kTitleLength = 64;
  1.2608 +
  1.2609 +  nsAutoString docTitleStr;
  1.2610 +  nsAutoString docURLStr;
  1.2611 +  GetDisplayTitleAndURL(aPO, docTitleStr, docURLStr, eDocTitleDefURLDoc);
  1.2612 +
  1.2613 +  // Make sure the Titles & URLS don't get too long for the progress dialog
  1.2614 +  EllipseLongString(docTitleStr, kTitleLength, false);
  1.2615 +  EllipseLongString(docURLStr, kTitleLength, true);
  1.2616 +
  1.2617 +  aParams->SetDocTitle(docTitleStr.get());
  1.2618 +  aParams->SetDocURL(docURLStr.get());
  1.2619 +}
  1.2620 +
  1.2621 +//---------------------------------------------------------------------
  1.2622 +void
  1.2623 +nsPrintEngine::EllipseLongString(nsAString& aStr, const uint32_t aLen, bool aDoFront)
  1.2624 +{
  1.2625 +  // Make sure the URLS don't get too long for the progress dialog
  1.2626 +  if (aLen >= 3 && aStr.Length() > aLen) {
  1.2627 +    if (aDoFront) {
  1.2628 +      nsAutoString newStr;
  1.2629 +      newStr.AppendLiteral("...");
  1.2630 +      newStr += Substring(aStr, aStr.Length() - (aLen - 3), aLen - 3);
  1.2631 +      aStr = newStr;
  1.2632 +    } else {
  1.2633 +      aStr.SetLength(aLen - 3);
  1.2634 +      aStr.AppendLiteral("...");
  1.2635 +    }
  1.2636 +  }
  1.2637 +}
  1.2638 +
  1.2639 +static bool
  1.2640 +DocHasPrintCallbackCanvas(nsIDocument* aDoc, void* aData)
  1.2641 +{
  1.2642 +  if (!aDoc) {
  1.2643 +    return true;
  1.2644 +  }
  1.2645 +  Element* root = aDoc->GetRootElement();
  1.2646 +  if (!root) {
  1.2647 +    return true;
  1.2648 +  }
  1.2649 +  nsRefPtr<nsContentList> canvases = NS_GetContentList(root,
  1.2650 +                                                       kNameSpaceID_XHTML,
  1.2651 +                                                       NS_LITERAL_STRING("canvas"));
  1.2652 +  uint32_t canvasCount = canvases->Length(true);
  1.2653 +  for (uint32_t i = 0; i < canvasCount; ++i) {
  1.2654 +    HTMLCanvasElement* canvas = HTMLCanvasElement::FromContentOrNull(canvases->Item(i, false));
  1.2655 +    if (canvas && canvas->GetMozPrintCallback()) {
  1.2656 +      // This subdocument has a print callback. Set result and return false to
  1.2657 +      // stop iteration.
  1.2658 +      *static_cast<bool*>(aData) = true;
  1.2659 +      return false;
  1.2660 +    }
  1.2661 +  }
  1.2662 +  return true;
  1.2663 +}
  1.2664 +
  1.2665 +static bool
  1.2666 +DocHasPrintCallbackCanvas(nsIDocument* aDoc)
  1.2667 +{
  1.2668 +  bool result = false;
  1.2669 +  aDoc->EnumerateSubDocuments(&DocHasPrintCallbackCanvas, static_cast<void*>(&result));
  1.2670 +  return result;
  1.2671 +}
  1.2672 +
  1.2673 +/**
  1.2674 + * Checks to see if the document this print engine is associated with has any
  1.2675 + * canvases that have a mozPrintCallback.
  1.2676 + */
  1.2677 +bool
  1.2678 +nsPrintEngine::HasPrintCallbackCanvas()
  1.2679 +{
  1.2680 +  if (!mDocument) {
  1.2681 +    return false;
  1.2682 +  }
  1.2683 +  // First check this mDocument.
  1.2684 +  bool result = false;
  1.2685 +  DocHasPrintCallbackCanvas(mDocument, static_cast<void*>(&result));
  1.2686 +  // Also check the sub documents.
  1.2687 +  return result || DocHasPrintCallbackCanvas(mDocument);
  1.2688 +}
  1.2689 +
  1.2690 +//-------------------------------------------------------
  1.2691 +bool
  1.2692 +nsPrintEngine::PrePrintPage()
  1.2693 +{
  1.2694 +  NS_ASSERTION(mPageSeqFrame,  "mPageSeqFrame is null!");
  1.2695 +  NS_ASSERTION(mPrt,           "mPrt is null!");
  1.2696 +
  1.2697 +  // Although these should NEVER be nullptr
  1.2698 +  // This is added insurance, to make sure we don't crash in optimized builds
  1.2699 +  if (!mPrt || !mPageSeqFrame) {
  1.2700 +    return true; // means we are done preparing the page.
  1.2701 +  }
  1.2702 +
  1.2703 +  // Check setting to see if someone request it be cancelled
  1.2704 +  bool isCancelled = false;
  1.2705 +  mPrt->mPrintSettings->GetIsCancelled(&isCancelled);
  1.2706 +  if (isCancelled)
  1.2707 +    return true;
  1.2708 +
  1.2709 +  // Ask mPageSeqFrame if the page is ready to be printed.
  1.2710 +  // If the page doesn't get printed at all, the |done| will be |true|.
  1.2711 +  bool done = false;
  1.2712 +  nsresult rv = mPageSeqFrame->PrePrintNextPage(mPagePrintTimer, &done);
  1.2713 +  if (NS_FAILED(rv)) {
  1.2714 +    // ??? ::PrintPage doesn't set |mPrt->mIsAborted = true| if rv != NS_ERROR_ABORT,
  1.2715 +    // but I don't really understand why this should be the right thing to do?
  1.2716 +    // Shouldn't |mPrt->mIsAborted| set to true all the time if something
  1.2717 +    // wents wrong?
  1.2718 +    if (rv != NS_ERROR_ABORT) {
  1.2719 +      ShowPrintErrorDialog(rv);
  1.2720 +      mPrt->mIsAborted = true;
  1.2721 +    }
  1.2722 +    done = true;
  1.2723 +  }
  1.2724 +  return done;
  1.2725 +}
  1.2726 +
  1.2727 +bool
  1.2728 +nsPrintEngine::PrintPage(nsPrintObject*    aPO,
  1.2729 +                         bool&           aInRange)
  1.2730 +{
  1.2731 +  NS_ASSERTION(aPO,            "aPO is null!");
  1.2732 +  NS_ASSERTION(mPageSeqFrame,  "mPageSeqFrame is null!");
  1.2733 +  NS_ASSERTION(mPrt,           "mPrt is null!");
  1.2734 +
  1.2735 +  // Although these should NEVER be nullptr
  1.2736 +  // This is added insurance, to make sure we don't crash in optimized builds
  1.2737 +  if (!mPrt || !aPO || !mPageSeqFrame) {
  1.2738 +    ShowPrintErrorDialog(NS_ERROR_FAILURE);
  1.2739 +    return true; // means we are done printing
  1.2740 +  }
  1.2741 +
  1.2742 +  PR_PL(("-----------------------------------\n"));
  1.2743 +  PR_PL(("------ In DV::PrintPage PO: %p (%s)\n", aPO, gFrameTypesStr[aPO->mFrameType]));
  1.2744 +
  1.2745 +  // Check setting to see if someone request it be cancelled
  1.2746 +  bool isCancelled = false;
  1.2747 +  mPrt->mPrintSettings->GetIsCancelled(&isCancelled);
  1.2748 +  if (isCancelled || mPrt->mIsAborted)
  1.2749 +    return true;
  1.2750 +
  1.2751 +  int32_t pageNum, numPages, endPage;
  1.2752 +  mPageSeqFrame->GetCurrentPageNum(&pageNum);
  1.2753 +  mPageSeqFrame->GetNumPages(&numPages);
  1.2754 +
  1.2755 +  bool donePrinting;
  1.2756 +  bool isDoingPrintRange;
  1.2757 +  mPageSeqFrame->IsDoingPrintRange(&isDoingPrintRange);
  1.2758 +  if (isDoingPrintRange) {
  1.2759 +    int32_t fromPage;
  1.2760 +    int32_t toPage;
  1.2761 +    mPageSeqFrame->GetPrintRange(&fromPage, &toPage);
  1.2762 +
  1.2763 +    if (fromPage > numPages) {
  1.2764 +      return true;
  1.2765 +    }
  1.2766 +    if (toPage > numPages) {
  1.2767 +      toPage = numPages;
  1.2768 +    }
  1.2769 +
  1.2770 +    PR_PL(("****** Printing Page %d printing from %d to page %d\n", pageNum, fromPage, toPage));
  1.2771 +
  1.2772 +    donePrinting = pageNum >= toPage;
  1.2773 +    aInRange = pageNum >= fromPage && pageNum <= toPage;
  1.2774 +    endPage = (toPage - fromPage)+1;
  1.2775 +  } else {
  1.2776 +    PR_PL(("****** Printing Page %d of %d page(s)\n", pageNum, numPages));
  1.2777 +
  1.2778 +    donePrinting = pageNum >= numPages;
  1.2779 +    endPage = numPages;
  1.2780 +    aInRange = true;
  1.2781 +  }
  1.2782 +
  1.2783 +  // XXX This is wrong, but the actual behavior in the presence of a print
  1.2784 +  // range sucks.
  1.2785 +  if (mPrt->mPrintFrameType == nsIPrintSettings::kEachFrameSep)
  1.2786 +    endPage = mPrt->mNumPrintablePages;
  1.2787 +  
  1.2788 +  mPrt->DoOnProgressChange(++mPrt->mNumPagesPrinted, endPage, false, 0);
  1.2789 +
  1.2790 +  // Print the Page
  1.2791 +  // if a print job was cancelled externally, an EndPage or BeginPage may
  1.2792 +  // fail and the failure is passed back here.
  1.2793 +  // Returning true means we are done printing.
  1.2794 +  //
  1.2795 +  // When rv == NS_ERROR_ABORT, it means we want out of the
  1.2796 +  // print job without displaying any error messages
  1.2797 +  nsresult rv = mPageSeqFrame->PrintNextPage();
  1.2798 +  if (NS_FAILED(rv)) {
  1.2799 +    if (rv != NS_ERROR_ABORT) {
  1.2800 +      ShowPrintErrorDialog(rv);
  1.2801 +      mPrt->mIsAborted = true;
  1.2802 +    }
  1.2803 +    return true;
  1.2804 +  }
  1.2805 +
  1.2806 +  mPageSeqFrame->DoPageEnd();
  1.2807 +
  1.2808 +  return donePrinting;
  1.2809 +}
  1.2810 +
  1.2811 +/** ---------------------------------------------------
  1.2812 + *  Find by checking frames type
  1.2813 + */
  1.2814 +nsresult 
  1.2815 +nsPrintEngine::FindSelectionBoundsWithList(nsPresContext* aPresContext,
  1.2816 +                                           nsRenderingContext& aRC,
  1.2817 +                                           nsFrameList::Enumerator& aChildFrames,
  1.2818 +                                           nsIFrame *      aParentFrame,
  1.2819 +                                           nsRect&         aRect,
  1.2820 +                                           nsIFrame *&     aStartFrame,
  1.2821 +                                           nsRect&         aStartRect,
  1.2822 +                                           nsIFrame *&     aEndFrame,
  1.2823 +                                           nsRect&         aEndRect)
  1.2824 +{
  1.2825 +  NS_ASSERTION(aPresContext, "Pointer is null!");
  1.2826 +  NS_ASSERTION(aParentFrame, "Pointer is null!");
  1.2827 +
  1.2828 +  aRect += aParentFrame->GetPosition();
  1.2829 +  for (; !aChildFrames.AtEnd(); aChildFrames.Next()) {
  1.2830 +    nsIFrame* child = aChildFrames.get();
  1.2831 +    if (child->IsSelected() && child->IsVisibleForPainting()) {
  1.2832 +      nsRect r = child->GetRect();
  1.2833 +      if (aStartFrame == nullptr) {
  1.2834 +        aStartFrame = child;
  1.2835 +        aStartRect.SetRect(aRect.x + r.x, aRect.y + r.y, r.width, r.height);
  1.2836 +      } else {
  1.2837 +        aEndFrame = child;
  1.2838 +        aEndRect.SetRect(aRect.x + r.x, aRect.y + r.y, r.width, r.height);
  1.2839 +      }
  1.2840 +    }
  1.2841 +    FindSelectionBounds(aPresContext, aRC, child, aRect, aStartFrame, aStartRect, aEndFrame, aEndRect);
  1.2842 +    child = child->GetNextSibling();
  1.2843 +  }
  1.2844 +  aRect -= aParentFrame->GetPosition();
  1.2845 +  return NS_OK;
  1.2846 +}
  1.2847 +
  1.2848 +//-------------------------------------------------------
  1.2849 +// Find the Frame that is XMost
  1.2850 +nsresult 
  1.2851 +nsPrintEngine::FindSelectionBounds(nsPresContext* aPresContext,
  1.2852 +                                   nsRenderingContext& aRC,
  1.2853 +                                   nsIFrame *      aParentFrame,
  1.2854 +                                   nsRect&         aRect,
  1.2855 +                                   nsIFrame *&     aStartFrame,
  1.2856 +                                   nsRect&         aStartRect,
  1.2857 +                                   nsIFrame *&     aEndFrame,
  1.2858 +                                   nsRect&         aEndRect)
  1.2859 +{
  1.2860 +  NS_ASSERTION(aPresContext, "Pointer is null!");
  1.2861 +  NS_ASSERTION(aParentFrame, "Pointer is null!");
  1.2862 +
  1.2863 +  // loop through named child lists
  1.2864 +  nsIFrame::ChildListIterator lists(aParentFrame);
  1.2865 +  for (; !lists.IsDone(); lists.Next()) {
  1.2866 +    nsFrameList::Enumerator childFrames(lists.CurrentList());
  1.2867 +    nsresult rv = FindSelectionBoundsWithList(aPresContext, aRC, childFrames, aParentFrame, aRect, aStartFrame, aStartRect, aEndFrame, aEndRect);
  1.2868 +    NS_ENSURE_SUCCESS(rv, rv);
  1.2869 +  }
  1.2870 +  return NS_OK;
  1.2871 +}
  1.2872 +
  1.2873 +/** ---------------------------------------------------
  1.2874 + *  This method finds the starting and ending page numbers
  1.2875 + *  of the selection and also returns rect for each where
  1.2876 + *  the x,y of the rect is relative to the very top of the
  1.2877 + *  frame tree (absolutely positioned)
  1.2878 + */
  1.2879 +nsresult 
  1.2880 +nsPrintEngine::GetPageRangeForSelection(nsIPresShell *        aPresShell,
  1.2881 +                                        nsPresContext*       aPresContext,
  1.2882 +                                        nsRenderingContext&  aRC,
  1.2883 +                                        nsISelection*         aSelection,
  1.2884 +                                        nsIPageSequenceFrame* aPageSeqFrame,
  1.2885 +                                        nsIFrame**            aStartFrame,
  1.2886 +                                        int32_t&              aStartPageNum,
  1.2887 +                                        nsRect&               aStartRect,
  1.2888 +                                        nsIFrame**            aEndFrame,
  1.2889 +                                        int32_t&              aEndPageNum,
  1.2890 +                                        nsRect&               aEndRect)
  1.2891 +{
  1.2892 +  NS_ASSERTION(aPresShell, "Pointer is null!");
  1.2893 +  NS_ASSERTION(aPresContext, "Pointer is null!");
  1.2894 +  NS_ASSERTION(aSelection, "Pointer is null!");
  1.2895 +  NS_ASSERTION(aPageSeqFrame, "Pointer is null!");
  1.2896 +  NS_ASSERTION(aStartFrame, "Pointer is null!");
  1.2897 +  NS_ASSERTION(aEndFrame, "Pointer is null!");
  1.2898 +
  1.2899 +  nsIFrame * seqFrame = do_QueryFrame(aPageSeqFrame);
  1.2900 +  if (!seqFrame) {
  1.2901 +    return NS_ERROR_FAILURE;
  1.2902 +  }
  1.2903 +
  1.2904 +  nsIFrame * startFrame = nullptr;
  1.2905 +  nsIFrame * endFrame   = nullptr;
  1.2906 +
  1.2907 +  // start out with the sequence frame and search the entire frame tree
  1.2908 +  // capturing the starting and ending child frames of the selection
  1.2909 +  // and their rects
  1.2910 +  nsRect r = seqFrame->GetRect();
  1.2911 +  FindSelectionBounds(aPresContext, aRC, seqFrame, r,
  1.2912 +                      startFrame, aStartRect, endFrame, aEndRect);
  1.2913 +
  1.2914 +#ifdef DEBUG_rodsX
  1.2915 +  printf("Start Frame: %p\n", startFrame);
  1.2916 +  printf("End Frame:   %p\n", endFrame);
  1.2917 +#endif
  1.2918 +
  1.2919 +  // initial the page numbers here
  1.2920 +  // in case we don't find and frames
  1.2921 +  aStartPageNum = -1;
  1.2922 +  aEndPageNum   = -1;
  1.2923 +
  1.2924 +  nsIFrame * startPageFrame;
  1.2925 +  nsIFrame * endPageFrame;
  1.2926 +
  1.2927 +  // check to make sure we found a starting frame
  1.2928 +  if (startFrame != nullptr) {
  1.2929 +    // Now search up the tree to find what page the
  1.2930 +    // start/ending selections frames are on
  1.2931 +    //
  1.2932 +    // Check to see if start should be same as end if
  1.2933 +    // the end frame comes back null
  1.2934 +    if (endFrame == nullptr) {
  1.2935 +      // XXX the "GetPageFrame" step could be integrated into
  1.2936 +      // the FindSelectionBounds step, but walking up to find
  1.2937 +      // the parent of a child frame isn't expensive and it makes
  1.2938 +      // FindSelectionBounds a little easier to understand
  1.2939 +      startPageFrame = nsLayoutUtils::GetPageFrame(startFrame);
  1.2940 +      endPageFrame   = startPageFrame;
  1.2941 +      aEndRect       = aStartRect;
  1.2942 +    } else {
  1.2943 +      startPageFrame = nsLayoutUtils::GetPageFrame(startFrame);
  1.2944 +      endPageFrame   = nsLayoutUtils::GetPageFrame(endFrame);
  1.2945 +    }
  1.2946 +  } else {
  1.2947 +    return NS_ERROR_FAILURE;
  1.2948 +  }
  1.2949 +
  1.2950 +#ifdef DEBUG_rodsX
  1.2951 +  printf("Start Page: %p\n", startPageFrame);
  1.2952 +  printf("End Page:   %p\n", endPageFrame);
  1.2953 +
  1.2954 +  // dump all the pages and their pointers
  1.2955 +  {
  1.2956 +  int32_t pageNum = 1;
  1.2957 +  nsIFrame* child = seqFrame->GetFirstPrincipalChild();
  1.2958 +  while (child != nullptr) {
  1.2959 +    printf("Page: %d - %p\n", pageNum, child);
  1.2960 +    pageNum++;
  1.2961 +    child = child->GetNextSibling();
  1.2962 +  }
  1.2963 +  }
  1.2964 +#endif
  1.2965 +
  1.2966 +  // Now that we have the page frames
  1.2967 +  // find out what the page numbers are for each frame
  1.2968 +  int32_t pageNum = 1;
  1.2969 +  nsIFrame* page = seqFrame->GetFirstPrincipalChild();
  1.2970 +  while (page != nullptr) {
  1.2971 +    if (page == startPageFrame) {
  1.2972 +      aStartPageNum = pageNum;
  1.2973 +    }
  1.2974 +    if (page == endPageFrame) {
  1.2975 +      aEndPageNum = pageNum;
  1.2976 +    }
  1.2977 +    pageNum++;
  1.2978 +    page = page->GetNextSibling();
  1.2979 +  }
  1.2980 +
  1.2981 +#ifdef DEBUG_rodsX
  1.2982 +  printf("Start Page No: %d\n", aStartPageNum);
  1.2983 +  printf("End Page No:   %d\n", aEndPageNum);
  1.2984 +#endif
  1.2985 +
  1.2986 +  *aStartFrame = startPageFrame;
  1.2987 +  *aEndFrame   = endPageFrame;
  1.2988 +
  1.2989 +  return NS_OK;
  1.2990 +}
  1.2991 +
  1.2992 +//-----------------------------------------------------------------
  1.2993 +//-- Done: Printing Methods
  1.2994 +//-----------------------------------------------------------------
  1.2995 +
  1.2996 +
  1.2997 +//-----------------------------------------------------------------
  1.2998 +//-- Section: Misc Support Methods
  1.2999 +//-----------------------------------------------------------------
  1.3000 +
  1.3001 +//---------------------------------------------------------------------
  1.3002 +void nsPrintEngine::SetIsPrinting(bool aIsPrinting)
  1.3003 +{ 
  1.3004 +  mIsDoingPrinting = aIsPrinting;
  1.3005 +  // Calling SetIsPrinting while in print preview confuses the document viewer
  1.3006 +  // This is safe because we prevent exiting print preview while printing
  1.3007 +  if (!mIsDoingPrintPreview && mDocViewerPrint) {
  1.3008 +    mDocViewerPrint->SetIsPrinting(aIsPrinting);
  1.3009 +  }
  1.3010 +  if (mPrt && aIsPrinting) {
  1.3011 +    mPrt->mPreparingForPrint = true;
  1.3012 +  }
  1.3013 +}
  1.3014 +
  1.3015 +//---------------------------------------------------------------------
  1.3016 +void nsPrintEngine::SetIsPrintPreview(bool aIsPrintPreview) 
  1.3017 +{ 
  1.3018 +  mIsDoingPrintPreview = aIsPrintPreview; 
  1.3019 +
  1.3020 +  if (mDocViewerPrint) {
  1.3021 +    mDocViewerPrint->SetIsPrintPreview(aIsPrintPreview);
  1.3022 +  }
  1.3023 +}
  1.3024 +
  1.3025 +//---------------------------------------------------------------------
  1.3026 +void
  1.3027 +nsPrintEngine::CleanupDocTitleArray(char16_t**& aArray, int32_t& aCount)
  1.3028 +{
  1.3029 +  for (int32_t i = aCount - 1; i >= 0; i--) {
  1.3030 +    nsMemory::Free(aArray[i]);
  1.3031 +  }
  1.3032 +  nsMemory::Free(aArray);
  1.3033 +  aArray = nullptr;
  1.3034 +  aCount = 0;
  1.3035 +}
  1.3036 +
  1.3037 +//---------------------------------------------------------------------
  1.3038 +// static
  1.3039 +bool nsPrintEngine::HasFramesetChild(nsIContent* aContent)
  1.3040 +{
  1.3041 +  if (!aContent) {
  1.3042 +    return false;
  1.3043 +  }
  1.3044 +
  1.3045 +  // do a breadth search across all siblings
  1.3046 +  for (nsIContent* child = aContent->GetFirstChild();
  1.3047 +       child;
  1.3048 +       child = child->GetNextSibling()) {
  1.3049 +    if (child->IsHTML(nsGkAtoms::frameset)) {
  1.3050 +      return true;
  1.3051 +    }
  1.3052 +  }
  1.3053 +
  1.3054 +  return false;
  1.3055 +}
  1.3056 + 
  1.3057 +
  1.3058 +
  1.3059 +/** ---------------------------------------------------
  1.3060 + *  Get the Focused Frame for a documentviewer
  1.3061 + */
  1.3062 +already_AddRefed<nsIDOMWindow>
  1.3063 +nsPrintEngine::FindFocusedDOMWindow()
  1.3064 +{
  1.3065 +  nsIFocusManager* fm = nsFocusManager::GetFocusManager();
  1.3066 +  NS_ENSURE_TRUE(fm, nullptr);
  1.3067 +
  1.3068 +  nsCOMPtr<nsPIDOMWindow> window(mDocument->GetWindow());
  1.3069 +  NS_ENSURE_TRUE(window, nullptr);
  1.3070 +
  1.3071 +  nsCOMPtr<nsPIDOMWindow> rootWindow = window->GetPrivateRoot();
  1.3072 +  NS_ENSURE_TRUE(rootWindow, nullptr);
  1.3073 +
  1.3074 +  nsCOMPtr<nsPIDOMWindow> focusedWindow;
  1.3075 +  nsFocusManager::GetFocusedDescendant(rootWindow, true,
  1.3076 +                                       getter_AddRefs(focusedWindow));
  1.3077 +  NS_ENSURE_TRUE(focusedWindow, nullptr);
  1.3078 +
  1.3079 +  if (IsWindowsInOurSubTree(focusedWindow)) {
  1.3080 +    return focusedWindow.forget();
  1.3081 +  }
  1.3082 +
  1.3083 +  return nullptr;
  1.3084 +}
  1.3085 +
  1.3086 +//---------------------------------------------------------------------
  1.3087 +bool
  1.3088 +nsPrintEngine::IsWindowsInOurSubTree(nsPIDOMWindow * window)
  1.3089 +{
  1.3090 +  bool found = false;
  1.3091 +
  1.3092 +  // now check to make sure it is in "our" tree of docshells
  1.3093 +  if (window) {
  1.3094 +    nsCOMPtr<nsIDocShell> docShell = window->GetDocShell();
  1.3095 +
  1.3096 +    if (docShell) {
  1.3097 +      // get this DocViewer docshell
  1.3098 +      nsCOMPtr<nsIDocShell> thisDVDocShell(do_QueryReferent(mContainer));
  1.3099 +      while (!found) {
  1.3100 +        if (docShell) {
  1.3101 +          if (docShell == thisDVDocShell) {
  1.3102 +            found = true;
  1.3103 +            break;
  1.3104 +          }
  1.3105 +        } else {
  1.3106 +          break; // at top of tree
  1.3107 +        }
  1.3108 +        nsCOMPtr<nsIDocShellTreeItem> docShellItemParent;
  1.3109 +        docShell->GetSameTypeParent(getter_AddRefs(docShellItemParent));
  1.3110 +        docShell = do_QueryInterface(docShellItemParent);
  1.3111 +      } // while
  1.3112 +    }
  1.3113 +  } // scriptobj
  1.3114 +
  1.3115 +  return found;
  1.3116 +}
  1.3117 +
  1.3118 +//-------------------------------------------------------
  1.3119 +bool
  1.3120 +nsPrintEngine::DonePrintingPages(nsPrintObject* aPO, nsresult aResult)
  1.3121 +{
  1.3122 +  //NS_ASSERTION(aPO, "Pointer is null!");
  1.3123 +  PR_PL(("****** In DV::DonePrintingPages PO: %p (%s)\n", aPO, aPO?gFrameTypesStr[aPO->mFrameType]:""));
  1.3124 +
  1.3125 +  // If there is a pageSeqFrame, make sure there are no more printCanvas active
  1.3126 +  // that might call |Notify| on the pagePrintTimer after things are cleaned up
  1.3127 +  // and printing was marked as being done.
  1.3128 +  if (mPageSeqFrame) {
  1.3129 +    mPageSeqFrame->ResetPrintCanvasList();
  1.3130 +  }
  1.3131 +
  1.3132 +  if (aPO && !mPrt->mIsAborted) {
  1.3133 +    aPO->mHasBeenPrinted = true;
  1.3134 +    nsresult rv;
  1.3135 +    bool didPrint = PrintDocContent(mPrt->mPrintObject, rv);
  1.3136 +    if (NS_SUCCEEDED(rv) && didPrint) {
  1.3137 +      PR_PL(("****** In DV::DonePrintingPages PO: %p (%s) didPrint:%s (Not Done Printing)\n", aPO, gFrameTypesStr[aPO->mFrameType], PRT_YESNO(didPrint)));
  1.3138 +      return false;
  1.3139 +    }
  1.3140 +  }
  1.3141 +
  1.3142 +  if (NS_SUCCEEDED(aResult)) {
  1.3143 +    FirePrintCompletionEvent();
  1.3144 +  }
  1.3145 +
  1.3146 +  TurnScriptingOn(true);
  1.3147 +  SetIsPrinting(false);
  1.3148 +
  1.3149 +  // Release reference to mPagePrintTimer; the timer object destroys itself
  1.3150 +  // after this returns true
  1.3151 +  NS_IF_RELEASE(mPagePrintTimer);
  1.3152 +
  1.3153 +  return true;
  1.3154 +}
  1.3155 +
  1.3156 +//-------------------------------------------------------
  1.3157 +// Recursively sets the PO items to be printed "As Is"
  1.3158 +// from the given item down into the tree
  1.3159 +void
  1.3160 +nsPrintEngine::SetPrintAsIs(nsPrintObject* aPO, bool aAsIs)
  1.3161 +{
  1.3162 +  NS_ASSERTION(aPO, "Pointer is null!");
  1.3163 +
  1.3164 +  aPO->mPrintAsIs = aAsIs;
  1.3165 +  for (uint32_t i=0;i<aPO->mKids.Length();i++) {
  1.3166 +    SetPrintAsIs(aPO->mKids[i], aAsIs);
  1.3167 +  }
  1.3168 +}
  1.3169 +
  1.3170 +//-------------------------------------------------------
  1.3171 +// Given a DOMWindow it recursively finds the PO object that matches
  1.3172 +nsPrintObject*
  1.3173 +nsPrintEngine::FindPrintObjectByDOMWin(nsPrintObject* aPO,
  1.3174 +                                       nsIDOMWindow* aDOMWin)
  1.3175 +{
  1.3176 +  NS_ASSERTION(aPO, "Pointer is null!");
  1.3177 +
  1.3178 +  // Often the CurFocused DOMWindow is passed in
  1.3179 +  // andit is valid for it to be null, so short circut
  1.3180 +  if (!aDOMWin) {
  1.3181 +    return nullptr;
  1.3182 +  }
  1.3183 +
  1.3184 +  nsCOMPtr<nsIDOMDocument> domDoc;
  1.3185 +  aDOMWin->GetDocument(getter_AddRefs(domDoc));
  1.3186 +  nsCOMPtr<nsIDocument> doc = do_QueryInterface(domDoc);
  1.3187 +  if (aPO->mDocument && aPO->mDocument->GetOriginalDocument() == doc) {
  1.3188 +    return aPO;
  1.3189 +  }
  1.3190 +
  1.3191 +  int32_t cnt = aPO->mKids.Length();
  1.3192 +  for (int32_t i = 0; i < cnt; ++i) {
  1.3193 +    nsPrintObject* po = FindPrintObjectByDOMWin(aPO->mKids[i], aDOMWin);
  1.3194 +    if (po) {
  1.3195 +      return po;
  1.3196 +    }
  1.3197 +  }
  1.3198 +
  1.3199 +  return nullptr;
  1.3200 +}
  1.3201 +
  1.3202 +//-------------------------------------------------------
  1.3203 +nsresult
  1.3204 +nsPrintEngine::EnablePOsForPrinting()
  1.3205 +{
  1.3206 +  // NOTE: All POs have been "turned off" for printing
  1.3207 +  // this is where we decided which POs get printed.
  1.3208 +  mPrt->mSelectedPO = nullptr;
  1.3209 +
  1.3210 +  if (mPrt->mPrintSettings == nullptr) {
  1.3211 +    return NS_ERROR_FAILURE;
  1.3212 +  }
  1.3213 +
  1.3214 +  mPrt->mPrintFrameType = nsIPrintSettings::kNoFrames;
  1.3215 +  mPrt->mPrintSettings->GetPrintFrameType(&mPrt->mPrintFrameType);
  1.3216 +
  1.3217 +  int16_t printHowEnable = nsIPrintSettings::kFrameEnableNone;
  1.3218 +  mPrt->mPrintSettings->GetHowToEnableFrameUI(&printHowEnable);
  1.3219 +
  1.3220 +  int16_t printRangeType = nsIPrintSettings::kRangeAllPages;
  1.3221 +  mPrt->mPrintSettings->GetPrintRange(&printRangeType);
  1.3222 +
  1.3223 +  PR_PL(("\n"));
  1.3224 +  PR_PL(("********* nsPrintEngine::EnablePOsForPrinting *********\n"));
  1.3225 +  PR_PL(("PrintFrameType:     %s \n", gPrintFrameTypeStr[mPrt->mPrintFrameType]));
  1.3226 +  PR_PL(("HowToEnableFrameUI: %s \n", gFrameHowToEnableStr[printHowEnable]));
  1.3227 +  PR_PL(("PrintRange:         %s \n", gPrintRangeStr[printRangeType]));
  1.3228 +  PR_PL(("----\n"));
  1.3229 +
  1.3230 +  // ***** This is the ultimate override *****
  1.3231 +  // if we are printing the selection (either an IFrame or selection range)
  1.3232 +  // then set the mPrintFrameType as if it were the selected frame
  1.3233 +  if (printRangeType == nsIPrintSettings::kRangeSelection) {
  1.3234 +    mPrt->mPrintFrameType = nsIPrintSettings::kSelectedFrame;
  1.3235 +    printHowEnable        = nsIPrintSettings::kFrameEnableNone;
  1.3236 +  }
  1.3237 +
  1.3238 +  // This tells us that the "Frame" UI has turned off,
  1.3239 +  // so therefore there are no FrameSets/Frames/IFrames to be printed
  1.3240 +  //
  1.3241 +  // This means there are not FrameSets,
  1.3242 +  // but the document could contain an IFrame
  1.3243 +  if (printHowEnable == nsIPrintSettings::kFrameEnableNone) {
  1.3244 +
  1.3245 +    // Print all the pages or a sub range of pages
  1.3246 +    if (printRangeType == nsIPrintSettings::kRangeAllPages ||
  1.3247 +        printRangeType == nsIPrintSettings::kRangeSpecifiedPageRange) {
  1.3248 +      SetPrintPO(mPrt->mPrintObject, true);
  1.3249 +
  1.3250 +      // Set the children so they are PrinAsIs
  1.3251 +      // In this case, the children are probably IFrames
  1.3252 +      if (mPrt->mPrintObject->mKids.Length() > 0) {
  1.3253 +        for (uint32_t i=0;i<mPrt->mPrintObject->mKids.Length();i++) {
  1.3254 +          nsPrintObject* po = mPrt->mPrintObject->mKids[i];
  1.3255 +          NS_ASSERTION(po, "nsPrintObject can't be null!");
  1.3256 +          SetPrintAsIs(po);
  1.3257 +        }
  1.3258 +
  1.3259 +        // ***** Another override *****
  1.3260 +        mPrt->mPrintFrameType = nsIPrintSettings::kFramesAsIs;
  1.3261 +      }
  1.3262 +      PR_PL(("PrintFrameType:     %s \n", gPrintFrameTypeStr[mPrt->mPrintFrameType]));
  1.3263 +      PR_PL(("HowToEnableFrameUI: %s \n", gFrameHowToEnableStr[printHowEnable]));
  1.3264 +      PR_PL(("PrintRange:         %s \n", gPrintRangeStr[printRangeType]));
  1.3265 +      return NS_OK;
  1.3266 +    }
  1.3267 +
  1.3268 +    // This means we are either printed a selected IFrame or
  1.3269 +    // we are printing the current selection
  1.3270 +    if (printRangeType == nsIPrintSettings::kRangeSelection) {
  1.3271 +
  1.3272 +      // If the currentFocusDOMWin can'r be null if something is selected
  1.3273 +      if (mPrt->mCurrentFocusWin) {
  1.3274 +        // Find the selected IFrame
  1.3275 +        nsPrintObject * po = FindPrintObjectByDOMWin(mPrt->mPrintObject, mPrt->mCurrentFocusWin);
  1.3276 +        if (po != nullptr) {
  1.3277 +          mPrt->mSelectedPO = po;
  1.3278 +          // Makes sure all of its children are be printed "AsIs"
  1.3279 +          SetPrintAsIs(po);
  1.3280 +
  1.3281 +          // Now, only enable this POs (the selected PO) and all of its children
  1.3282 +          SetPrintPO(po, true);
  1.3283 +
  1.3284 +          // check to see if we have a range selection,
  1.3285 +          // as oppose to a insert selection
  1.3286 +          // this means if the user just clicked on the IFrame then
  1.3287 +          // there will not be a selection so we want the entire page to print
  1.3288 +          //
  1.3289 +          // XXX this is sort of a hack right here to make the page
  1.3290 +          // not try to reposition itself when printing selection
  1.3291 +          nsCOMPtr<nsIDOMWindow> domWin =
  1.3292 +            do_QueryInterface(po->mDocument->GetOriginalDocument()->GetWindow());
  1.3293 +          if (!IsThereARangeSelection(domWin)) {
  1.3294 +            printRangeType = nsIPrintSettings::kRangeAllPages;
  1.3295 +            mPrt->mPrintSettings->SetPrintRange(printRangeType);
  1.3296 +          }
  1.3297 +          PR_PL(("PrintFrameType:     %s \n", gPrintFrameTypeStr[mPrt->mPrintFrameType]));
  1.3298 +          PR_PL(("HowToEnableFrameUI: %s \n", gFrameHowToEnableStr[printHowEnable]));
  1.3299 +          PR_PL(("PrintRange:         %s \n", gPrintRangeStr[printRangeType]));
  1.3300 +          return NS_OK;
  1.3301 +        }
  1.3302 +      } else {
  1.3303 +        for (uint32_t i=0;i<mPrt->mPrintDocList.Length();i++) {
  1.3304 +          nsPrintObject* po = mPrt->mPrintDocList.ElementAt(i);
  1.3305 +          NS_ASSERTION(po, "nsPrintObject can't be null!");
  1.3306 +          nsCOMPtr<nsIDOMWindow> domWin = do_GetInterface(po->mDocShell);
  1.3307 +          if (IsThereARangeSelection(domWin)) {
  1.3308 +            mPrt->mCurrentFocusWin = domWin;
  1.3309 +            SetPrintPO(po, true);
  1.3310 +            break;
  1.3311 +          }
  1.3312 +        }
  1.3313 +        return NS_OK;
  1.3314 +      }
  1.3315 +    }
  1.3316 +  }
  1.3317 +
  1.3318 +  // check to see if there is a selection when a FrameSet is present
  1.3319 +  if (printRangeType == nsIPrintSettings::kRangeSelection) {
  1.3320 +    // If the currentFocusDOMWin can'r be null if something is selected
  1.3321 +    if (mPrt->mCurrentFocusWin) {
  1.3322 +      // Find the selected IFrame
  1.3323 +      nsPrintObject * po = FindPrintObjectByDOMWin(mPrt->mPrintObject, mPrt->mCurrentFocusWin);
  1.3324 +      if (po != nullptr) {
  1.3325 +        mPrt->mSelectedPO = po;
  1.3326 +        // Makes sure all of its children are be printed "AsIs"
  1.3327 +        SetPrintAsIs(po);
  1.3328 +
  1.3329 +        // Now, only enable this POs (the selected PO) and all of its children
  1.3330 +        SetPrintPO(po, true);
  1.3331 +
  1.3332 +        // check to see if we have a range selection,
  1.3333 +        // as oppose to a insert selection
  1.3334 +        // this means if the user just clicked on the IFrame then
  1.3335 +        // there will not be a selection so we want the entire page to print
  1.3336 +        //
  1.3337 +        // XXX this is sort of a hack right here to make the page
  1.3338 +        // not try to reposition itself when printing selection
  1.3339 +        nsCOMPtr<nsIDOMWindow> domWin =
  1.3340 +          do_QueryInterface(po->mDocument->GetOriginalDocument()->GetWindow());
  1.3341 +        if (!IsThereARangeSelection(domWin)) {
  1.3342 +          printRangeType = nsIPrintSettings::kRangeAllPages;
  1.3343 +          mPrt->mPrintSettings->SetPrintRange(printRangeType);
  1.3344 +        }
  1.3345 +        PR_PL(("PrintFrameType:     %s \n", gPrintFrameTypeStr[mPrt->mPrintFrameType]));
  1.3346 +        PR_PL(("HowToEnableFrameUI: %s \n", gFrameHowToEnableStr[printHowEnable]));
  1.3347 +        PR_PL(("PrintRange:         %s \n", gPrintRangeStr[printRangeType]));
  1.3348 +        return NS_OK;
  1.3349 +      }
  1.3350 +    }
  1.3351 +  }
  1.3352 +
  1.3353 +  // If we are printing "AsIs" then sets all the POs to be printed as is
  1.3354 +  if (mPrt->mPrintFrameType == nsIPrintSettings::kFramesAsIs) {
  1.3355 +    SetPrintAsIs(mPrt->mPrintObject);
  1.3356 +    SetPrintPO(mPrt->mPrintObject, true);
  1.3357 +    return NS_OK;
  1.3358 +  }
  1.3359 +
  1.3360 +  // If we are printing the selected Frame then
  1.3361 +  // find that PO for that selected DOMWin and set it all of its
  1.3362 +  // children to be printed
  1.3363 +  if (mPrt->mPrintFrameType == nsIPrintSettings::kSelectedFrame) {
  1.3364 +
  1.3365 +    if ((mPrt->mIsParentAFrameSet && mPrt->mCurrentFocusWin) || mPrt->mIsIFrameSelected) {
  1.3366 +      nsPrintObject * po = FindPrintObjectByDOMWin(mPrt->mPrintObject, mPrt->mCurrentFocusWin);
  1.3367 +      if (po != nullptr) {
  1.3368 +        mPrt->mSelectedPO = po;
  1.3369 +        // NOTE: Calling this sets the "po" and
  1.3370 +        // we don't want to do this for documents that have no children,
  1.3371 +        // because then the "DoEndPage" gets called and it shouldn't
  1.3372 +        if (po->mKids.Length() > 0) {
  1.3373 +          // Makes sure that itself, and all of its children are printed "AsIs"
  1.3374 +          SetPrintAsIs(po);
  1.3375 +        }
  1.3376 +
  1.3377 +        // Now, only enable this POs (the selected PO) and all of its children
  1.3378 +        SetPrintPO(po, true);
  1.3379 +      }
  1.3380 +    }
  1.3381 +    return NS_OK;
  1.3382 +  }
  1.3383 +
  1.3384 +  // If we are print each subdoc separately,
  1.3385 +  // then don't print any of the FraneSet Docs
  1.3386 +  if (mPrt->mPrintFrameType == nsIPrintSettings::kEachFrameSep) {
  1.3387 +    SetPrintPO(mPrt->mPrintObject, true);
  1.3388 +    int32_t cnt = mPrt->mPrintDocList.Length();
  1.3389 +    for (int32_t i=0;i<cnt;i++) {
  1.3390 +      nsPrintObject* po = mPrt->mPrintDocList.ElementAt(i);
  1.3391 +      NS_ASSERTION(po, "nsPrintObject can't be null!");
  1.3392 +      if (po->mFrameType == eFrameSet) {
  1.3393 +        po->mDontPrint = true;
  1.3394 +      }
  1.3395 +    }
  1.3396 +  }
  1.3397 +
  1.3398 +  return NS_OK;
  1.3399 +}
  1.3400 +
  1.3401 +//-------------------------------------------------------
  1.3402 +// Return the nsPrintObject with that is XMost (The widest frameset frame) AND
  1.3403 +// contains the XMost (widest) layout frame
  1.3404 +nsPrintObject*
  1.3405 +nsPrintEngine::FindSmallestSTF()
  1.3406 +{
  1.3407 +  float smallestRatio = 1.0f;
  1.3408 +  nsPrintObject* smallestPO = nullptr;
  1.3409 +
  1.3410 +  for (uint32_t i=0;i<mPrt->mPrintDocList.Length();i++) {
  1.3411 +    nsPrintObject* po = mPrt->mPrintDocList.ElementAt(i);
  1.3412 +    NS_ASSERTION(po, "nsPrintObject can't be null!");
  1.3413 +    if (po->mFrameType != eFrameSet && po->mFrameType != eIFrame) {
  1.3414 +      if (po->mShrinkRatio < smallestRatio) {
  1.3415 +        smallestRatio = po->mShrinkRatio;
  1.3416 +        smallestPO    = po;
  1.3417 +      }
  1.3418 +    }
  1.3419 +  }
  1.3420 +
  1.3421 +#ifdef EXTENDED_DEBUG_PRINTING
  1.3422 +  if (smallestPO) printf("*PO: %p  Type: %d  %10.3f\n", smallestPO, smallestPO->mFrameType, smallestPO->mShrinkRatio);
  1.3423 +#endif
  1.3424 +  return smallestPO;
  1.3425 +}
  1.3426 +
  1.3427 +//-------------------------------------------------------
  1.3428 +void
  1.3429 +nsPrintEngine::TurnScriptingOn(bool aDoTurnOn)
  1.3430 +{
  1.3431 +  if (mIsDoingPrinting && aDoTurnOn && mDocViewerPrint &&
  1.3432 +      mDocViewerPrint->GetIsPrintPreview()) {
  1.3433 +    // We don't want to turn scripting on if print preview is shown still after
  1.3434 +    // printing.
  1.3435 +    return;
  1.3436 +  }
  1.3437 +
  1.3438 +  nsPrintData* prt = mPrt;
  1.3439 +#ifdef NS_PRINT_PREVIEW
  1.3440 +  if (!prt) {
  1.3441 +    prt = mPrtPreview;
  1.3442 +  }
  1.3443 +#endif
  1.3444 +  if (!prt) {
  1.3445 +    return;
  1.3446 +  }
  1.3447 +
  1.3448 +  NS_ASSERTION(mDocument, "We MUST have a document.");
  1.3449 +  // First, get the script global object from the document...
  1.3450 +
  1.3451 +  for (uint32_t i=0;i<prt->mPrintDocList.Length();i++) {
  1.3452 +    nsPrintObject* po = prt->mPrintDocList.ElementAt(i);
  1.3453 +    NS_ASSERTION(po, "nsPrintObject can't be null!");
  1.3454 +
  1.3455 +    nsIDocument* doc = po->mDocument;
  1.3456 +    if (!doc) {
  1.3457 +      continue;
  1.3458 +    }
  1.3459 +
  1.3460 +    if (nsCOMPtr<nsPIDOMWindow> window = doc->GetInnerWindow()) {
  1.3461 +      nsCOMPtr<nsIGlobalObject> go = do_QueryInterface(window);
  1.3462 +      NS_WARN_IF_FALSE(go && go->GetGlobalJSObject(), "Can't get global");
  1.3463 +      nsresult propThere = NS_PROPTABLE_PROP_NOT_THERE;
  1.3464 +      doc->GetProperty(nsGkAtoms::scriptEnabledBeforePrintOrPreview,
  1.3465 +                       &propThere);
  1.3466 +      if (aDoTurnOn) {
  1.3467 +        if (propThere != NS_PROPTABLE_PROP_NOT_THERE) {
  1.3468 +          doc->DeleteProperty(nsGkAtoms::scriptEnabledBeforePrintOrPreview);
  1.3469 +          if (go && go->GetGlobalJSObject()) {
  1.3470 +            xpc::Scriptability::Get(go->GetGlobalJSObject()).Unblock();
  1.3471 +          }
  1.3472 +          window->ResumeTimeouts(false);
  1.3473 +        }
  1.3474 +      } else {
  1.3475 +        // Have to be careful, because people call us over and over again with
  1.3476 +        // aDoTurnOn == false.  So don't set the property if it's already
  1.3477 +        // set, since in that case we'd set it to the wrong value.
  1.3478 +        if (propThere == NS_PROPTABLE_PROP_NOT_THERE) {
  1.3479 +          // Stash the current value of IsScriptEnabled on the document, so
  1.3480 +          // that layout code running in print preview doesn't get confused.
  1.3481 +          doc->SetProperty(nsGkAtoms::scriptEnabledBeforePrintOrPreview,
  1.3482 +                           NS_INT32_TO_PTR(doc->IsScriptEnabled()));
  1.3483 +          if (go && go->GetGlobalJSObject()) {
  1.3484 +            xpc::Scriptability::Get(go->GetGlobalJSObject()).Block();
  1.3485 +          }
  1.3486 +          window->SuspendTimeouts(1, false);
  1.3487 +        }
  1.3488 +      }
  1.3489 +    }
  1.3490 +  }
  1.3491 +}
  1.3492 +
  1.3493 +//-----------------------------------------------------------------
  1.3494 +//-- Done: Misc Support Methods
  1.3495 +//-----------------------------------------------------------------
  1.3496 +
  1.3497 +
  1.3498 +//-----------------------------------------------------------------
  1.3499 +//-- Section: Finishing up or Cleaning up
  1.3500 +//-----------------------------------------------------------------
  1.3501 +
  1.3502 +//-----------------------------------------------------------------
  1.3503 +void
  1.3504 +nsPrintEngine::CloseProgressDialog(nsIWebProgressListener* aWebProgressListener)
  1.3505 +{
  1.3506 +  if (aWebProgressListener) {
  1.3507 +    aWebProgressListener->OnStateChange(nullptr, nullptr, nsIWebProgressListener::STATE_STOP|nsIWebProgressListener::STATE_IS_DOCUMENT, NS_OK);
  1.3508 +  }
  1.3509 +}
  1.3510 +
  1.3511 +//-----------------------------------------------------------------
  1.3512 +nsresult
  1.3513 +nsPrintEngine::FinishPrintPreview()
  1.3514 +{
  1.3515 +  nsresult rv = NS_OK;
  1.3516 +
  1.3517 +#ifdef NS_PRINT_PREVIEW
  1.3518 +
  1.3519 +  if (!mPrt) {
  1.3520 +    /* we're already finished with print preview */
  1.3521 +    return rv;
  1.3522 +  }
  1.3523 +
  1.3524 +  rv = DocumentReadyForPrinting();
  1.3525 +
  1.3526 +  SetIsCreatingPrintPreview(false);
  1.3527 +
  1.3528 +  /* cleaup on failure + notify user */
  1.3529 +  if (NS_FAILED(rv)) {
  1.3530 +    /* cleanup done, let's fire-up an error dialog to notify the user
  1.3531 +     * what went wrong...
  1.3532 +     */
  1.3533 +    mPrt->OnEndPrinting();
  1.3534 +    TurnScriptingOn(true);
  1.3535 +
  1.3536 +    return rv;
  1.3537 +  }
  1.3538 +
  1.3539 +  // At this point we are done preparing everything
  1.3540 +  // before it is to be created
  1.3541 +
  1.3542 +
  1.3543 +  if (mIsDoingPrintPreview && mOldPrtPreview) {
  1.3544 +    delete mOldPrtPreview;
  1.3545 +    mOldPrtPreview = nullptr;
  1.3546 +  }
  1.3547 +
  1.3548 +
  1.3549 +  mPrt->OnEndPrinting();
  1.3550 +
  1.3551 +  // PrintPreview was built using the mPrt (code reuse)
  1.3552 +  // then we assign it over
  1.3553 +  mPrtPreview = mPrt;
  1.3554 +  mPrt        = nullptr;
  1.3555 +
  1.3556 +#endif // NS_PRINT_PREVIEW
  1.3557 +
  1.3558 +  return NS_OK;
  1.3559 +}
  1.3560 +
  1.3561 +//-----------------------------------------------------------------
  1.3562 +//-- Done: Finishing up or Cleaning up
  1.3563 +//-----------------------------------------------------------------
  1.3564 +
  1.3565 +
  1.3566 +/*=============== Timer Related Code ======================*/
  1.3567 +nsresult
  1.3568 +nsPrintEngine::StartPagePrintTimer(nsPrintObject* aPO)
  1.3569 +{
  1.3570 +  if (!mPagePrintTimer) {
  1.3571 +    // Get the delay time in between the printing of each page
  1.3572 +    // this gives the user more time to press cancel
  1.3573 +    int32_t printPageDelay = 50;
  1.3574 +    mPrt->mPrintSettings->GetPrintPageDelay(&printPageDelay);
  1.3575 +
  1.3576 +    nsRefPtr<nsPagePrintTimer> timer =
  1.3577 +      new nsPagePrintTimer(this, mDocViewerPrint, printPageDelay);
  1.3578 +    timer.forget(&mPagePrintTimer);
  1.3579 +  }
  1.3580 +
  1.3581 +  return mPagePrintTimer->Start(aPO);
  1.3582 +}
  1.3583 +
  1.3584 +/*=============== nsIObserver Interface ======================*/
  1.3585 +NS_IMETHODIMP 
  1.3586 +nsPrintEngine::Observe(nsISupports *aSubject, const char *aTopic, const char16_t *aData)
  1.3587 +{
  1.3588 +  nsresult rv = NS_ERROR_FAILURE;
  1.3589 +
  1.3590 +  rv = InitPrintDocConstruction(true);
  1.3591 +  if (!mIsDoingPrinting && mPrtPreview) {
  1.3592 +      mPrtPreview->OnEndPrinting();
  1.3593 +  }
  1.3594 +
  1.3595 +  return rv;
  1.3596 +
  1.3597 +}
  1.3598 +
  1.3599 +//---------------------------------------------------------------
  1.3600 +//-- PLEvent Notification
  1.3601 +//---------------------------------------------------------------
  1.3602 +class nsPrintCompletionEvent : public nsRunnable {
  1.3603 +public:
  1.3604 +  nsPrintCompletionEvent(nsIDocumentViewerPrint *docViewerPrint)
  1.3605 +    : mDocViewerPrint(docViewerPrint) {
  1.3606 +    NS_ASSERTION(mDocViewerPrint, "mDocViewerPrint is null.");
  1.3607 +  }
  1.3608 +
  1.3609 +  NS_IMETHOD Run() MOZ_OVERRIDE {
  1.3610 +    if (mDocViewerPrint)
  1.3611 +      mDocViewerPrint->OnDonePrinting();
  1.3612 +    return NS_OK;
  1.3613 +  }
  1.3614 +
  1.3615 +private:
  1.3616 +  nsCOMPtr<nsIDocumentViewerPrint> mDocViewerPrint;
  1.3617 +};
  1.3618 +
  1.3619 +//-----------------------------------------------------------
  1.3620 +void
  1.3621 +nsPrintEngine::FirePrintCompletionEvent()
  1.3622 +{
  1.3623 +  nsCOMPtr<nsIRunnable> event = new nsPrintCompletionEvent(mDocViewerPrint);
  1.3624 +  if (NS_FAILED(NS_DispatchToCurrentThread(event)))
  1.3625 +    NS_WARNING("failed to dispatch print completion event");
  1.3626 +}
  1.3627 +
  1.3628 +//---------------------------------------------------------------
  1.3629 +//---------------------------------------------------------------
  1.3630 +//-- Debug helper routines
  1.3631 +//---------------------------------------------------------------
  1.3632 +//---------------------------------------------------------------
  1.3633 +#if defined(XP_WIN) && defined(EXTENDED_DEBUG_PRINTING)
  1.3634 +#include "windows.h"
  1.3635 +#include "process.h"
  1.3636 +#include "direct.h"
  1.3637 +
  1.3638 +#define MY_FINDFIRST(a,b) FindFirstFile(a,b)
  1.3639 +#define MY_FINDNEXT(a,b) FindNextFile(a,b)
  1.3640 +#define ISDIR(a) (a.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
  1.3641 +#define MY_FINDCLOSE(a) FindClose(a)
  1.3642 +#define MY_FILENAME(a) a.cFileName
  1.3643 +#define MY_FILESIZE(a) (a.nFileSizeHigh * MAXDWORD) + a.nFileSizeLow
  1.3644 +
  1.3645 +int RemoveFilesInDir(const char * aDir)
  1.3646 +{
  1.3647 +	WIN32_FIND_DATA data_ptr;
  1.3648 +	HANDLE find_handle;
  1.3649 +
  1.3650 +  char path[MAX_PATH];
  1.3651 +
  1.3652 +  strcpy(path, aDir);
  1.3653 +
  1.3654 +	// Append slash to the end of the directory names if not there
  1.3655 +	if (path[strlen(path)-1] != '\\')
  1.3656 +    strcat(path, "\\");
  1.3657 +
  1.3658 +  char findPath[MAX_PATH];
  1.3659 +  strcpy(findPath, path);
  1.3660 +  strcat(findPath, "*.*");
  1.3661 +
  1.3662 +	find_handle = MY_FINDFIRST(findPath, &data_ptr);
  1.3663 +
  1.3664 +	if (find_handle != INVALID_HANDLE_VALUE) {
  1.3665 +		do  {
  1.3666 +			if (ISDIR(data_ptr)
  1.3667 +				&& (stricmp(MY_FILENAME(data_ptr),"."))
  1.3668 +				&& (stricmp(MY_FILENAME(data_ptr),".."))) {
  1.3669 +					// skip
  1.3670 +			}
  1.3671 +			else if (!ISDIR(data_ptr)) {
  1.3672 +        if (!strncmp(MY_FILENAME(data_ptr), "print_dump", 10)) {
  1.3673 +          char fileName[MAX_PATH];
  1.3674 +          strcpy(fileName, aDir);
  1.3675 +          strcat(fileName, "\\");
  1.3676 +          strcat(fileName, MY_FILENAME(data_ptr));
  1.3677 +				  printf("Removing %s\n", fileName);
  1.3678 +          remove(fileName);
  1.3679 +        }
  1.3680 +			}
  1.3681 +		} while(MY_FINDNEXT(find_handle,&data_ptr));
  1.3682 +		MY_FINDCLOSE(find_handle);
  1.3683 +	}
  1.3684 +	return TRUE;
  1.3685 +}
  1.3686 +#endif
  1.3687 +
  1.3688 +#ifdef EXTENDED_DEBUG_PRINTING
  1.3689 +
  1.3690 +/** ---------------------------------------------------
  1.3691 + *  Dumps Frames for Printing
  1.3692 + */
  1.3693 +static void RootFrameList(nsPresContext* aPresContext, FILE* out, int32_t aIndent)
  1.3694 +{
  1.3695 +  if (!aPresContext || !out)
  1.3696 +    return;
  1.3697 +
  1.3698 +  nsIPresShell *shell = aPresContext->GetPresShell();
  1.3699 +  if (shell) {
  1.3700 +    nsIFrame* frame = shell->FrameManager()->GetRootFrame();
  1.3701 +    if (frame) {
  1.3702 +      frame->List(aPresContext, out, aIndent);
  1.3703 +    }
  1.3704 +  }
  1.3705 +}
  1.3706 +
  1.3707 +/** ---------------------------------------------------
  1.3708 + *  Dumps Frames for Printing
  1.3709 + */
  1.3710 +static void DumpFrames(FILE*                 out,
  1.3711 +                       nsPresContext*       aPresContext,
  1.3712 +                       nsRenderingContext * aRendContext,
  1.3713 +                       nsIFrame *            aFrame,
  1.3714 +                       int32_t               aLevel)
  1.3715 +{
  1.3716 +  NS_ASSERTION(out, "Pointer is null!");
  1.3717 +  NS_ASSERTION(aPresContext, "Pointer is null!");
  1.3718 +  NS_ASSERTION(aRendContext, "Pointer is null!");
  1.3719 +  NS_ASSERTION(aFrame, "Pointer is null!");
  1.3720 +
  1.3721 +  nsIFrame* child = aFrame->GetFirstPrincipalChild();
  1.3722 +  while (child != nullptr) {
  1.3723 +    for (int32_t i=0;i<aLevel;i++) {
  1.3724 +     fprintf(out, "  ");
  1.3725 +    }
  1.3726 +    nsAutoString tmp;
  1.3727 +    child->GetFrameName(tmp);
  1.3728 +    fputs(NS_LossyConvertUTF16toASCII(tmp).get(), out);
  1.3729 +    bool isSelected;
  1.3730 +    if (NS_SUCCEEDED(child->IsVisibleForPainting(aPresContext, *aRendContext, true, &isSelected))) {
  1.3731 +      fprintf(out, " %p %s", child, isSelected?"VIS":"UVS");
  1.3732 +      nsRect rect = child->GetRect();
  1.3733 +      fprintf(out, "[%d,%d,%d,%d] ", rect.x, rect.y, rect.width, rect.height);
  1.3734 +      fprintf(out, "v: %p ", (void*)child->GetView());
  1.3735 +      fprintf(out, "\n");
  1.3736 +      DumpFrames(out, aPresContext, aRendContext, child, aLevel+1);
  1.3737 +      child = child->GetNextSibling();
  1.3738 +    }
  1.3739 +  }
  1.3740 +}
  1.3741 +
  1.3742 +
  1.3743 +/** ---------------------------------------------------
  1.3744 + *  Dumps the Views from the DocShell
  1.3745 + */
  1.3746 +static void
  1.3747 +DumpViews(nsIDocShell* aDocShell, FILE* out)
  1.3748 +{
  1.3749 +  NS_ASSERTION(aDocShell, "Pointer is null!");
  1.3750 +  NS_ASSERTION(out, "Pointer is null!");
  1.3751 +
  1.3752 +  if (nullptr != aDocShell) {
  1.3753 +    fprintf(out, "docshell=%p \n", aDocShell);
  1.3754 +    nsIPresShell* shell = nsPrintEngine::GetPresShellFor(aDocShell);
  1.3755 +    if (shell) {
  1.3756 +      nsViewManager* vm = shell->GetViewManager();
  1.3757 +      if (vm) {
  1.3758 +        nsView* root = vm->GetRootView();
  1.3759 +        if (root) {
  1.3760 +          root->List(out);
  1.3761 +        }
  1.3762 +      }
  1.3763 +    }
  1.3764 +    else {
  1.3765 +      fputs("null pres shell\n", out);
  1.3766 +    }
  1.3767 +
  1.3768 +    // dump the views of the sub documents
  1.3769 +    int32_t i, n;
  1.3770 +    aDocShell->GetChildCount(&n);
  1.3771 +    for (i = 0; i < n; i++) {
  1.3772 +      nsCOMPtr<nsIDocShellTreeItem> child;
  1.3773 +      aDocShell->GetChildAt(i, getter_AddRefs(child));
  1.3774 +      nsCOMPtr<nsIDocShell> childAsShell(do_QueryInterface(child));
  1.3775 +      if (childAsShell) {
  1.3776 +        DumpViews(childAsShell, out);
  1.3777 +      }
  1.3778 +    }
  1.3779 +  }
  1.3780 +}
  1.3781 +
  1.3782 +/** ---------------------------------------------------
  1.3783 + *  Dumps the Views and Frames
  1.3784 + */
  1.3785 +void DumpLayoutData(char*              aTitleStr,
  1.3786 +                    char*              aURLStr,
  1.3787 +                    nsPresContext*    aPresContext,
  1.3788 +                    nsDeviceContext * aDC,
  1.3789 +                    nsIFrame *         aRootFrame,
  1.3790 +                    nsIDocShekk *      aDocShell,
  1.3791 +                    FILE*              aFD = nullptr)
  1.3792 +{
  1.3793 +  if (!kPrintingLogMod || kPrintingLogMod->level != DUMP_LAYOUT_LEVEL) return;
  1.3794 +
  1.3795 +  if (aPresContext == nullptr || aDC == nullptr) {
  1.3796 +    return;
  1.3797 +  }
  1.3798 +
  1.3799 +#ifdef NS_PRINT_PREVIEW
  1.3800 +  if (aPresContext->Type() == nsPresContext::eContext_PrintPreview) {
  1.3801 +    return;
  1.3802 +  }
  1.3803 +#endif
  1.3804 +
  1.3805 +  NS_ASSERTION(aRootFrame, "Pointer is null!");
  1.3806 +  NS_ASSERTION(aDocShell, "Pointer is null!");
  1.3807 +
  1.3808 +  // Dump all the frames and view to a a file
  1.3809 +  char filename[256];
  1.3810 +  sprintf(filename, "print_dump_layout_%d.txt", gDumpLOFileNameCnt++);
  1.3811 +  FILE * fd = aFD?aFD:fopen(filename, "w");
  1.3812 +  if (fd) {
  1.3813 +    fprintf(fd, "Title: %s\n", aTitleStr?aTitleStr:"");
  1.3814 +    fprintf(fd, "URL:   %s\n", aURLStr?aURLStr:"");
  1.3815 +    fprintf(fd, "--------------- Frames ----------------\n");
  1.3816 +    fprintf(fd, "--------------- Frames ----------------\n");
  1.3817 +    nsRefPtr<nsRenderingContext> renderingContext =
  1.3818 +      aDC->CreateRenderingContext();
  1.3819 +    RootFrameList(aPresContext, fd, 0);
  1.3820 +    //DumpFrames(fd, aPresContext, renderingContext, aRootFrame, 0);
  1.3821 +    fprintf(fd, "---------------------------------------\n\n");
  1.3822 +    fprintf(fd, "--------------- Views From Root Frame----------------\n");
  1.3823 +    nsView* v = aRootFrame->GetView();
  1.3824 +    if (v) {
  1.3825 +      v->List(fd);
  1.3826 +    } else {
  1.3827 +      printf("View is null!\n");
  1.3828 +    }
  1.3829 +    if (aDocShell) {
  1.3830 +      fprintf(fd, "--------------- All Views ----------------\n");
  1.3831 +      DumpViews(aDocShell, fd);
  1.3832 +      fprintf(fd, "---------------------------------------\n\n");
  1.3833 +    }
  1.3834 +    if (aFD == nullptr) {
  1.3835 +      fclose(fd);
  1.3836 +    }
  1.3837 +  }
  1.3838 +}
  1.3839 +
  1.3840 +//-------------------------------------------------------------
  1.3841 +static void DumpPrintObjectsList(nsTArray<nsPrintObject*> * aDocList)
  1.3842 +{
  1.3843 +  if (!kPrintingLogMod || kPrintingLogMod->level != DUMP_LAYOUT_LEVEL) return;
  1.3844 +
  1.3845 +  NS_ASSERTION(aDocList, "Pointer is null!");
  1.3846 +
  1.3847 +  const char types[][3] = {"DC", "FR", "IF", "FS"};
  1.3848 +  PR_PL(("Doc List\n***************************************************\n"));
  1.3849 +  PR_PL(("T  P A H    PO    DocShell   Seq     Page      Root     Page#    Rect\n"));
  1.3850 +  int32_t cnt = aDocList->Length();
  1.3851 +  for (int32_t i=0;i<cnt;i++) {
  1.3852 +    nsPrintObject* po = aDocList->ElementAt(i);
  1.3853 +    NS_ASSERTION(po, "nsPrintObject can't be null!");
  1.3854 +    nsIFrame* rootFrame = nullptr;
  1.3855 +    if (po->mPresShell) {
  1.3856 +      rootFrame = po->mPresShell->FrameManager()->GetRootFrame();
  1.3857 +      while (rootFrame != nullptr) {
  1.3858 +        nsIPageSequenceFrame * sqf = do_QueryFrame(rootFrame);
  1.3859 +        if (sqf) {
  1.3860 +          break;
  1.3861 +        }
  1.3862 +        rootFrame = rootFrame->GetFirstPrincipalChild();
  1.3863 +      }
  1.3864 +    }
  1.3865 +
  1.3866 +    PR_PL(("%s %d %d %d %p %p %p %p %p   %d   %d,%d,%d,%d\n", types[po->mFrameType],
  1.3867 +            po->IsPrintable(), po->mPrintAsIs, po->mHasBeenPrinted, po, po->mDocShell.get(), po->mSeqFrame,
  1.3868 +            po->mPageFrame, rootFrame, po->mPageNum, po->mRect.x, po->mRect.y, po->mRect.width, po->mRect.height));
  1.3869 +  }
  1.3870 +}
  1.3871 +
  1.3872 +//-------------------------------------------------------------
  1.3873 +static void DumpPrintObjectsTree(nsPrintObject * aPO, int aLevel, FILE* aFD)
  1.3874 +{
  1.3875 +  if (!kPrintingLogMod || kPrintingLogMod->level != DUMP_LAYOUT_LEVEL) return;
  1.3876 +
  1.3877 +  NS_ASSERTION(aPO, "Pointer is null!");
  1.3878 +
  1.3879 +  FILE * fd = aFD?aFD:stdout;
  1.3880 +  const char types[][3] = {"DC", "FR", "IF", "FS"};
  1.3881 +  if (aLevel == 0) {
  1.3882 +    fprintf(fd, "DocTree\n***************************************************\n");
  1.3883 +    fprintf(fd, "T     PO    DocShell   Seq      Page     Page#    Rect\n");
  1.3884 +  }
  1.3885 +  int32_t cnt = aPO->mKids.Length();
  1.3886 +  for (int32_t i=0;i<cnt;i++) {
  1.3887 +    nsPrintObject* po = aPO->mKids.ElementAt(i);
  1.3888 +    NS_ASSERTION(po, "nsPrintObject can't be null!");
  1.3889 +    for (int32_t k=0;k<aLevel;k++) fprintf(fd, "  ");
  1.3890 +    fprintf(fd, "%s %p %p %p %p %d %d,%d,%d,%d\n", types[po->mFrameType], po, po->mDocShell.get(), po->mSeqFrame,
  1.3891 +           po->mPageFrame, po->mPageNum, po->mRect.x, po->mRect.y, po->mRect.width, po->mRect.height);
  1.3892 +  }
  1.3893 +}
  1.3894 +
  1.3895 +//-------------------------------------------------------------
  1.3896 +static void GetDocTitleAndURL(nsPrintObject* aPO, nsACString& aDocStr, nsACString& aURLStr)
  1.3897 +{
  1.3898 +  nsAutoString docTitleStr;
  1.3899 +  nsAutoString docURLStr;
  1.3900 +  nsPrintEngine::GetDisplayTitleAndURL(aPO,
  1.3901 +                                       docTitleStr, docURLStr,
  1.3902 +                                       nsPrintEngine::eDocTitleDefURLDoc);
  1.3903 +  aDocStr = NS_ConvertUTF16toUTF8(docTitleStr);
  1.3904 +  aURLStr = NS_ConvertUTF16toUTF8(docURLStr);
  1.3905 +}
  1.3906 +
  1.3907 +//-------------------------------------------------------------
  1.3908 +static void DumpPrintObjectsTreeLayout(nsPrintObject * aPO,
  1.3909 +                                       nsDeviceContext * aDC,
  1.3910 +                                       int aLevel, FILE * aFD)
  1.3911 +{
  1.3912 +  if (!kPrintingLogMod || kPrintingLogMod->level != DUMP_LAYOUT_LEVEL) return;
  1.3913 +
  1.3914 +  NS_ASSERTION(aPO, "Pointer is null!");
  1.3915 +  NS_ASSERTION(aDC, "Pointer is null!");
  1.3916 +
  1.3917 +  const char types[][3] = {"DC", "FR", "IF", "FS"};
  1.3918 +  FILE * fd = nullptr;
  1.3919 +  if (aLevel == 0) {
  1.3920 +    fd = fopen("tree_layout.txt", "w");
  1.3921 +    fprintf(fd, "DocTree\n***************************************************\n");
  1.3922 +    fprintf(fd, "***************************************************\n");
  1.3923 +    fprintf(fd, "T     PO    DocShell   Seq      Page     Page#    Rect\n");
  1.3924 +  } else {
  1.3925 +    fd = aFD;
  1.3926 +  }
  1.3927 +  if (fd) {
  1.3928 +    nsIFrame* rootFrame = nullptr;
  1.3929 +    if (aPO->mPresShell) {
  1.3930 +      rootFrame = aPO->mPresShell->FrameManager()->GetRootFrame();
  1.3931 +    }
  1.3932 +    for (int32_t k=0;k<aLevel;k++) fprintf(fd, "  ");
  1.3933 +    fprintf(fd, "%s %p %p %p %p %d %d,%d,%d,%d\n", types[aPO->mFrameType], aPO, aPO->mDocShell.get(), aPO->mSeqFrame,
  1.3934 +           aPO->mPageFrame, aPO->mPageNum, aPO->mRect.x, aPO->mRect.y, aPO->mRect.width, aPO->mRect.height);
  1.3935 +    if (aPO->IsPrintable()) {
  1.3936 +      nsAutoCString docStr;
  1.3937 +      nsAutoCString urlStr;
  1.3938 +      GetDocTitleAndURL(aPO, docStr, urlStr);
  1.3939 +      DumpLayoutData(docStr.get(), urlStr.get(), aPO->mPresContext, aDC, rootFrame, aPO->mDocShell, fd);
  1.3940 +    }
  1.3941 +    fprintf(fd, "<***************************************************>\n");
  1.3942 +
  1.3943 +    int32_t cnt = aPO->mKids.Length();
  1.3944 +    for (int32_t i=0;i<cnt;i++) {
  1.3945 +      nsPrintObject* po = aPO->mKids.ElementAt(i);
  1.3946 +      NS_ASSERTION(po, "nsPrintObject can't be null!");
  1.3947 +      DumpPrintObjectsTreeLayout(po, aDC, aLevel+1, fd);
  1.3948 +    }
  1.3949 +  }
  1.3950 +  if (aLevel == 0 && fd) {
  1.3951 +    fclose(fd);
  1.3952 +  }
  1.3953 +}
  1.3954 +
  1.3955 +//-------------------------------------------------------------
  1.3956 +static void DumpPrintObjectsListStart(const char * aStr, nsTArray<nsPrintObject*> * aDocList)
  1.3957 +{
  1.3958 +  if (!kPrintingLogMod || kPrintingLogMod->level != DUMP_LAYOUT_LEVEL) return;
  1.3959 +
  1.3960 +  NS_ASSERTION(aStr, "Pointer is null!");
  1.3961 +  NS_ASSERTION(aDocList, "Pointer is null!");
  1.3962 +
  1.3963 +  PR_PL(("%s\n", aStr));
  1.3964 +  DumpPrintObjectsList(aDocList);
  1.3965 +}
  1.3966 +
  1.3967 +#define DUMP_DOC_LIST(_title) DumpPrintObjectsListStart((_title), mPrt->mPrintDocList);
  1.3968 +#define DUMP_DOC_TREE DumpPrintObjectsTree(mPrt->mPrintObject);
  1.3969 +#define DUMP_DOC_TREELAYOUT DumpPrintObjectsTreeLayout(mPrt->mPrintObject, mPrt->mPrintDC);
  1.3970 +
  1.3971 +#else
  1.3972 +#define DUMP_DOC_LIST(_title)
  1.3973 +#define DUMP_DOC_TREE
  1.3974 +#define DUMP_DOC_TREELAYOUT
  1.3975 +#endif
  1.3976 +
  1.3977 +//---------------------------------------------------------------
  1.3978 +//---------------------------------------------------------------
  1.3979 +//-- End of debug helper routines
  1.3980 +//---------------------------------------------------------------

mercurial