Tue, 06 Jan 2015 21:39:09 +0100
Conditionally force memory storage according to privacy.thirdparty.isolate;
This solves Tor bug #9701, complying with disk avoidance documented in
https://www.torproject.org/projects/torbrowser/design/#disk-avoidance.
michael@0 | 1 | /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ |
michael@0 | 2 | /* This Source Code Form is subject to the terms of the Mozilla Public |
michael@0 | 3 | * License, v. 2.0. If a copy of the MPL was not distributed with this |
michael@0 | 4 | * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ |
michael@0 | 5 | |
michael@0 | 6 | #include "nsPrintEngine.h" |
michael@0 | 7 | |
michael@0 | 8 | #include "nsIStringBundle.h" |
michael@0 | 9 | #include "nsReadableUtils.h" |
michael@0 | 10 | #include "nsCRT.h" |
michael@0 | 11 | |
michael@0 | 12 | #include "mozilla/AsyncEventDispatcher.h" |
michael@0 | 13 | #include "mozilla/dom/Selection.h" |
michael@0 | 14 | #include "nsIScriptGlobalObject.h" |
michael@0 | 15 | #include "nsPIDOMWindow.h" |
michael@0 | 16 | #include "nsIDocShell.h" |
michael@0 | 17 | #include "nsIFrame.h" |
michael@0 | 18 | #include "nsIURI.h" |
michael@0 | 19 | #include "nsITextToSubURI.h" |
michael@0 | 20 | #include "nsError.h" |
michael@0 | 21 | |
michael@0 | 22 | #include "nsView.h" |
michael@0 | 23 | #include <algorithm> |
michael@0 | 24 | |
michael@0 | 25 | // Print Options |
michael@0 | 26 | #include "nsIPrintSettings.h" |
michael@0 | 27 | #include "nsIPrintSettingsService.h" |
michael@0 | 28 | #include "nsIPrintOptions.h" |
michael@0 | 29 | #include "nsIPrintSession.h" |
michael@0 | 30 | #include "nsGfxCIID.h" |
michael@0 | 31 | #include "nsIServiceManager.h" |
michael@0 | 32 | #include "nsGkAtoms.h" |
michael@0 | 33 | #include "nsXPCOM.h" |
michael@0 | 34 | #include "nsISupportsPrimitives.h" |
michael@0 | 35 | |
michael@0 | 36 | static const char sPrintSettingsServiceContractID[] = "@mozilla.org/gfx/printsettings-service;1"; |
michael@0 | 37 | |
michael@0 | 38 | // Printing Events |
michael@0 | 39 | #include "nsPrintPreviewListener.h" |
michael@0 | 40 | #include "nsThreadUtils.h" |
michael@0 | 41 | |
michael@0 | 42 | // Printing |
michael@0 | 43 | #include "nsIWebBrowserPrint.h" |
michael@0 | 44 | #include "nsIDOMHTMLFrameElement.h" |
michael@0 | 45 | #include "nsIDOMHTMLFrameSetElement.h" |
michael@0 | 46 | #include "nsIDOMHTMLIFrameElement.h" |
michael@0 | 47 | #include "nsIDOMHTMLObjectElement.h" |
michael@0 | 48 | #include "nsIDOMHTMLEmbedElement.h" |
michael@0 | 49 | |
michael@0 | 50 | // Print Preview |
michael@0 | 51 | #include "imgIContainer.h" // image animation mode constants |
michael@0 | 52 | #include "nsIWebBrowserPrint.h" // needed for PrintPreview Navigation constants |
michael@0 | 53 | |
michael@0 | 54 | // Print Progress |
michael@0 | 55 | #include "nsIPrintProgress.h" |
michael@0 | 56 | #include "nsIPrintProgressParams.h" |
michael@0 | 57 | #include "nsIObserver.h" |
michael@0 | 58 | |
michael@0 | 59 | // Print error dialog |
michael@0 | 60 | #include "nsIPrompt.h" |
michael@0 | 61 | #include "nsIWindowWatcher.h" |
michael@0 | 62 | |
michael@0 | 63 | // Printing Prompts |
michael@0 | 64 | #include "nsIPrintingPromptService.h" |
michael@0 | 65 | static const char kPrintingPromptService[] = "@mozilla.org/embedcomp/printingprompt-service;1"; |
michael@0 | 66 | |
michael@0 | 67 | // Printing Timer |
michael@0 | 68 | #include "nsPagePrintTimer.h" |
michael@0 | 69 | |
michael@0 | 70 | // FrameSet |
michael@0 | 71 | #include "nsIDocument.h" |
michael@0 | 72 | |
michael@0 | 73 | // Focus |
michael@0 | 74 | #include "nsISelectionController.h" |
michael@0 | 75 | |
michael@0 | 76 | // Misc |
michael@0 | 77 | #include "nsISupportsUtils.h" |
michael@0 | 78 | #include "nsIScriptContext.h" |
michael@0 | 79 | #include "nsIDOMDocument.h" |
michael@0 | 80 | #include "nsISelectionListener.h" |
michael@0 | 81 | #include "nsISelectionPrivate.h" |
michael@0 | 82 | #include "nsIDOMRange.h" |
michael@0 | 83 | #include "nsContentCID.h" |
michael@0 | 84 | #include "nsLayoutCID.h" |
michael@0 | 85 | #include "nsContentUtils.h" |
michael@0 | 86 | #include "nsIPresShell.h" |
michael@0 | 87 | #include "nsLayoutUtils.h" |
michael@0 | 88 | #include "mozilla/Preferences.h" |
michael@0 | 89 | |
michael@0 | 90 | #include "nsWidgetsCID.h" |
michael@0 | 91 | #include "nsIDeviceContextSpec.h" |
michael@0 | 92 | #include "nsViewManager.h" |
michael@0 | 93 | #include "nsView.h" |
michael@0 | 94 | #include "nsRenderingContext.h" |
michael@0 | 95 | |
michael@0 | 96 | #include "nsIPageSequenceFrame.h" |
michael@0 | 97 | #include "nsIURL.h" |
michael@0 | 98 | #include "nsIContentViewerEdit.h" |
michael@0 | 99 | #include "nsIContentViewerFile.h" |
michael@0 | 100 | #include "nsIMarkupDocumentViewer.h" |
michael@0 | 101 | #include "nsIInterfaceRequestor.h" |
michael@0 | 102 | #include "nsIInterfaceRequestorUtils.h" |
michael@0 | 103 | #include "nsIDocShellTreeOwner.h" |
michael@0 | 104 | #include "nsIWebBrowserChrome.h" |
michael@0 | 105 | #include "nsIBaseWindow.h" |
michael@0 | 106 | #include "nsILayoutHistoryState.h" |
michael@0 | 107 | #include "nsFrameManager.h" |
michael@0 | 108 | #include "nsHTMLReflowState.h" |
michael@0 | 109 | #include "nsIDOMHTMLAnchorElement.h" |
michael@0 | 110 | #include "nsIDOMHTMLAreaElement.h" |
michael@0 | 111 | #include "nsIDOMHTMLLinkElement.h" |
michael@0 | 112 | #include "nsIDOMHTMLImageElement.h" |
michael@0 | 113 | #include "nsIContentViewerContainer.h" |
michael@0 | 114 | #include "nsIContentViewer.h" |
michael@0 | 115 | #include "nsIDocumentViewerPrint.h" |
michael@0 | 116 | |
michael@0 | 117 | #include "nsFocusManager.h" |
michael@0 | 118 | #include "nsRange.h" |
michael@0 | 119 | #include "nsCDefaultURIFixup.h" |
michael@0 | 120 | #include "nsIURIFixup.h" |
michael@0 | 121 | #include "mozilla/dom/Element.h" |
michael@0 | 122 | #include "nsContentList.h" |
michael@0 | 123 | #include "nsIChannel.h" |
michael@0 | 124 | #include "xpcpublic.h" |
michael@0 | 125 | |
michael@0 | 126 | using namespace mozilla; |
michael@0 | 127 | using namespace mozilla::dom; |
michael@0 | 128 | |
michael@0 | 129 | //----------------------------------------------------- |
michael@0 | 130 | // PR LOGGING |
michael@0 | 131 | #ifdef MOZ_LOGGING |
michael@0 | 132 | #define FORCE_PR_LOG /* Allow logging in the release build */ |
michael@0 | 133 | #endif |
michael@0 | 134 | |
michael@0 | 135 | #include "prlog.h" |
michael@0 | 136 | |
michael@0 | 137 | #ifdef PR_LOGGING |
michael@0 | 138 | |
michael@0 | 139 | #ifdef DEBUG |
michael@0 | 140 | // PR_LOGGING is force to always be on (even in release builds) |
michael@0 | 141 | // but we only want some of it on, |
michael@0 | 142 | //#define EXTENDED_DEBUG_PRINTING |
michael@0 | 143 | #endif |
michael@0 | 144 | |
michael@0 | 145 | #define DUMP_LAYOUT_LEVEL 9 // this turns on the dumping of each doucment's layout info |
michael@0 | 146 | |
michael@0 | 147 | #ifndef PR_PL |
michael@0 | 148 | static PRLogModuleInfo * |
michael@0 | 149 | GetPrintingLog() |
michael@0 | 150 | { |
michael@0 | 151 | static PRLogModuleInfo *sLog; |
michael@0 | 152 | if (!sLog) |
michael@0 | 153 | sLog = PR_NewLogModule("printing"); |
michael@0 | 154 | return sLog; |
michael@0 | 155 | } |
michael@0 | 156 | #define PR_PL(_p1) PR_LOG(GetPrintingLog(), PR_LOG_DEBUG, _p1); |
michael@0 | 157 | #endif |
michael@0 | 158 | |
michael@0 | 159 | #ifdef EXTENDED_DEBUG_PRINTING |
michael@0 | 160 | static uint32_t gDumpFileNameCnt = 0; |
michael@0 | 161 | static uint32_t gDumpLOFileNameCnt = 0; |
michael@0 | 162 | #endif |
michael@0 | 163 | |
michael@0 | 164 | #define PRT_YESNO(_p) ((_p)?"YES":"NO") |
michael@0 | 165 | static const char * gFrameTypesStr[] = {"eDoc", "eFrame", "eIFrame", "eFrameSet"}; |
michael@0 | 166 | static const char * gPrintFrameTypeStr[] = {"kNoFrames", "kFramesAsIs", "kSelectedFrame", "kEachFrameSep"}; |
michael@0 | 167 | static const char * gFrameHowToEnableStr[] = {"kFrameEnableNone", "kFrameEnableAll", "kFrameEnableAsIsAndEach"}; |
michael@0 | 168 | static const char * gPrintRangeStr[] = {"kRangeAllPages", "kRangeSpecifiedPageRange", "kRangeSelection", "kRangeFocusFrame"}; |
michael@0 | 169 | #else |
michael@0 | 170 | #define PRT_YESNO(_p) |
michael@0 | 171 | #define PR_PL(_p1) |
michael@0 | 172 | #endif |
michael@0 | 173 | |
michael@0 | 174 | #ifdef EXTENDED_DEBUG_PRINTING |
michael@0 | 175 | // Forward Declarations |
michael@0 | 176 | static void DumpPrintObjectsListStart(const char * aStr, nsTArray<nsPrintObject*> * aDocList); |
michael@0 | 177 | static void DumpPrintObjectsTree(nsPrintObject * aPO, int aLevel= 0, FILE* aFD = nullptr); |
michael@0 | 178 | static void DumpPrintObjectsTreeLayout(nsPrintObject * aPO,nsDeviceContext * aDC, int aLevel= 0, FILE * aFD = nullptr); |
michael@0 | 179 | |
michael@0 | 180 | #define DUMP_DOC_LIST(_title) DumpPrintObjectsListStart((_title), mPrt->mPrintDocList); |
michael@0 | 181 | #define DUMP_DOC_TREE DumpPrintObjectsTree(mPrt->mPrintObject); |
michael@0 | 182 | #define DUMP_DOC_TREELAYOUT DumpPrintObjectsTreeLayout(mPrt->mPrintObject, mPrt->mPrintDC); |
michael@0 | 183 | #else |
michael@0 | 184 | #define DUMP_DOC_LIST(_title) |
michael@0 | 185 | #define DUMP_DOC_TREE |
michael@0 | 186 | #define DUMP_DOC_TREELAYOUT |
michael@0 | 187 | #endif |
michael@0 | 188 | |
michael@0 | 189 | class nsScriptSuppressor |
michael@0 | 190 | { |
michael@0 | 191 | public: |
michael@0 | 192 | nsScriptSuppressor(nsPrintEngine* aPrintEngine) |
michael@0 | 193 | : mPrintEngine(aPrintEngine), mSuppressed(false) {} |
michael@0 | 194 | |
michael@0 | 195 | ~nsScriptSuppressor() { Unsuppress(); } |
michael@0 | 196 | |
michael@0 | 197 | void Suppress() |
michael@0 | 198 | { |
michael@0 | 199 | if (mPrintEngine) { |
michael@0 | 200 | mSuppressed = true; |
michael@0 | 201 | mPrintEngine->TurnScriptingOn(false); |
michael@0 | 202 | } |
michael@0 | 203 | } |
michael@0 | 204 | |
michael@0 | 205 | void Unsuppress() |
michael@0 | 206 | { |
michael@0 | 207 | if (mPrintEngine && mSuppressed) { |
michael@0 | 208 | mPrintEngine->TurnScriptingOn(true); |
michael@0 | 209 | } |
michael@0 | 210 | mSuppressed = false; |
michael@0 | 211 | } |
michael@0 | 212 | |
michael@0 | 213 | void Disconnect() { mPrintEngine = nullptr; } |
michael@0 | 214 | protected: |
michael@0 | 215 | nsRefPtr<nsPrintEngine> mPrintEngine; |
michael@0 | 216 | bool mSuppressed; |
michael@0 | 217 | }; |
michael@0 | 218 | |
michael@0 | 219 | NS_IMPL_ISUPPORTS(nsPrintEngine, nsIWebProgressListener, |
michael@0 | 220 | nsISupportsWeakReference, nsIObserver) |
michael@0 | 221 | |
michael@0 | 222 | //--------------------------------------------------- |
michael@0 | 223 | //-- nsPrintEngine Class Impl |
michael@0 | 224 | //--------------------------------------------------- |
michael@0 | 225 | nsPrintEngine::nsPrintEngine() : |
michael@0 | 226 | mIsCreatingPrintPreview(false), |
michael@0 | 227 | mIsDoingPrinting(false), |
michael@0 | 228 | mIsDoingPrintPreview(false), |
michael@0 | 229 | mProgressDialogIsShown(false), |
michael@0 | 230 | mScreenDPI(115.0f), |
michael@0 | 231 | mPrt(nullptr), |
michael@0 | 232 | mPagePrintTimer(nullptr), |
michael@0 | 233 | mPageSeqFrame(nullptr), |
michael@0 | 234 | mPrtPreview(nullptr), |
michael@0 | 235 | mOldPrtPreview(nullptr), |
michael@0 | 236 | mDebugFile(nullptr), |
michael@0 | 237 | mLoadCounter(0), |
michael@0 | 238 | mDidLoadDataForPrinting(false), |
michael@0 | 239 | mIsDestroying(false), |
michael@0 | 240 | mDisallowSelectionPrint(false), |
michael@0 | 241 | mNoMarginBoxes(false) |
michael@0 | 242 | { |
michael@0 | 243 | } |
michael@0 | 244 | |
michael@0 | 245 | //------------------------------------------------------- |
michael@0 | 246 | nsPrintEngine::~nsPrintEngine() |
michael@0 | 247 | { |
michael@0 | 248 | Destroy(); // for insurance |
michael@0 | 249 | } |
michael@0 | 250 | |
michael@0 | 251 | //------------------------------------------------------- |
michael@0 | 252 | void nsPrintEngine::Destroy() |
michael@0 | 253 | { |
michael@0 | 254 | if (mIsDestroying) { |
michael@0 | 255 | return; |
michael@0 | 256 | } |
michael@0 | 257 | mIsDestroying = true; |
michael@0 | 258 | |
michael@0 | 259 | if (mPrt) { |
michael@0 | 260 | delete mPrt; |
michael@0 | 261 | mPrt = nullptr; |
michael@0 | 262 | } |
michael@0 | 263 | |
michael@0 | 264 | #ifdef NS_PRINT_PREVIEW |
michael@0 | 265 | if (mPrtPreview) { |
michael@0 | 266 | delete mPrtPreview; |
michael@0 | 267 | mPrtPreview = nullptr; |
michael@0 | 268 | } |
michael@0 | 269 | |
michael@0 | 270 | // This is insruance |
michael@0 | 271 | if (mOldPrtPreview) { |
michael@0 | 272 | delete mOldPrtPreview; |
michael@0 | 273 | mOldPrtPreview = nullptr; |
michael@0 | 274 | } |
michael@0 | 275 | |
michael@0 | 276 | #endif |
michael@0 | 277 | mDocViewerPrint = nullptr; |
michael@0 | 278 | } |
michael@0 | 279 | |
michael@0 | 280 | //------------------------------------------------------- |
michael@0 | 281 | void nsPrintEngine::DestroyPrintingData() |
michael@0 | 282 | { |
michael@0 | 283 | if (mPrt) { |
michael@0 | 284 | nsPrintData* data = mPrt; |
michael@0 | 285 | mPrt = nullptr; |
michael@0 | 286 | delete data; |
michael@0 | 287 | } |
michael@0 | 288 | } |
michael@0 | 289 | |
michael@0 | 290 | //--------------------------------------------------------------------------------- |
michael@0 | 291 | //-- Section: Methods needed by the DocViewer |
michael@0 | 292 | //--------------------------------------------------------------------------------- |
michael@0 | 293 | |
michael@0 | 294 | //-------------------------------------------------------- |
michael@0 | 295 | nsresult nsPrintEngine::Initialize(nsIDocumentViewerPrint* aDocViewerPrint, |
michael@0 | 296 | nsIDocShell* aContainer, |
michael@0 | 297 | nsIDocument* aDocument, |
michael@0 | 298 | float aScreenDPI, |
michael@0 | 299 | FILE* aDebugFile) |
michael@0 | 300 | { |
michael@0 | 301 | NS_ENSURE_ARG_POINTER(aDocViewerPrint); |
michael@0 | 302 | NS_ENSURE_ARG_POINTER(aContainer); |
michael@0 | 303 | NS_ENSURE_ARG_POINTER(aDocument); |
michael@0 | 304 | |
michael@0 | 305 | mDocViewerPrint = aDocViewerPrint; |
michael@0 | 306 | mContainer = do_GetWeakReference(aContainer); |
michael@0 | 307 | mDocument = aDocument; |
michael@0 | 308 | mScreenDPI = aScreenDPI; |
michael@0 | 309 | |
michael@0 | 310 | mDebugFile = aDebugFile; // ok to be nullptr |
michael@0 | 311 | |
michael@0 | 312 | return NS_OK; |
michael@0 | 313 | } |
michael@0 | 314 | |
michael@0 | 315 | //------------------------------------------------------- |
michael@0 | 316 | bool |
michael@0 | 317 | nsPrintEngine::CheckBeforeDestroy() |
michael@0 | 318 | { |
michael@0 | 319 | if (mPrt && mPrt->mPreparingForPrint) { |
michael@0 | 320 | mPrt->mDocWasToBeDestroyed = true; |
michael@0 | 321 | return true; |
michael@0 | 322 | } |
michael@0 | 323 | return false; |
michael@0 | 324 | } |
michael@0 | 325 | |
michael@0 | 326 | //------------------------------------------------------- |
michael@0 | 327 | nsresult |
michael@0 | 328 | nsPrintEngine::Cancelled() |
michael@0 | 329 | { |
michael@0 | 330 | if (mPrt && mPrt->mPrintSettings) { |
michael@0 | 331 | return mPrt->mPrintSettings->SetIsCancelled(true); |
michael@0 | 332 | } |
michael@0 | 333 | return NS_ERROR_FAILURE; |
michael@0 | 334 | } |
michael@0 | 335 | |
michael@0 | 336 | //------------------------------------------------------- |
michael@0 | 337 | // Install our event listeners on the document to prevent |
michael@0 | 338 | // some events from being processed while in PrintPreview |
michael@0 | 339 | // |
michael@0 | 340 | // No return code - if this fails, there isn't much we can do |
michael@0 | 341 | void |
michael@0 | 342 | nsPrintEngine::InstallPrintPreviewListener() |
michael@0 | 343 | { |
michael@0 | 344 | if (!mPrt->mPPEventListeners) { |
michael@0 | 345 | nsCOMPtr<nsIDocShell> docShell = do_QueryReferent(mContainer); |
michael@0 | 346 | nsCOMPtr<nsPIDOMWindow> win(do_GetInterface(docShell)); |
michael@0 | 347 | if (win) { |
michael@0 | 348 | nsCOMPtr<EventTarget> target = do_QueryInterface(win->GetFrameElementInternal()); |
michael@0 | 349 | mPrt->mPPEventListeners = new nsPrintPreviewListener(target); |
michael@0 | 350 | mPrt->mPPEventListeners->AddListeners(); |
michael@0 | 351 | } |
michael@0 | 352 | } |
michael@0 | 353 | } |
michael@0 | 354 | |
michael@0 | 355 | //---------------------------------------------------------------------- |
michael@0 | 356 | nsresult |
michael@0 | 357 | nsPrintEngine::GetSeqFrameAndCountPagesInternal(nsPrintObject* aPO, |
michael@0 | 358 | nsIFrame*& aSeqFrame, |
michael@0 | 359 | int32_t& aCount) |
michael@0 | 360 | { |
michael@0 | 361 | NS_ENSURE_ARG_POINTER(aPO); |
michael@0 | 362 | |
michael@0 | 363 | // Finds the SimplePageSequencer frame |
michael@0 | 364 | nsIPageSequenceFrame* seqFrame = aPO->mPresShell->GetPageSequenceFrame(); |
michael@0 | 365 | aSeqFrame = do_QueryFrame(seqFrame); |
michael@0 | 366 | if (!aSeqFrame) { |
michael@0 | 367 | return NS_ERROR_FAILURE; |
michael@0 | 368 | } |
michael@0 | 369 | |
michael@0 | 370 | // first count the total number of pages |
michael@0 | 371 | aCount = 0; |
michael@0 | 372 | nsIFrame* pageFrame = aSeqFrame->GetFirstPrincipalChild(); |
michael@0 | 373 | while (pageFrame != nullptr) { |
michael@0 | 374 | aCount++; |
michael@0 | 375 | pageFrame = pageFrame->GetNextSibling(); |
michael@0 | 376 | } |
michael@0 | 377 | |
michael@0 | 378 | return NS_OK; |
michael@0 | 379 | |
michael@0 | 380 | } |
michael@0 | 381 | |
michael@0 | 382 | //----------------------------------------------------------------- |
michael@0 | 383 | nsresult nsPrintEngine::GetSeqFrameAndCountPages(nsIFrame*& aSeqFrame, int32_t& aCount) |
michael@0 | 384 | { |
michael@0 | 385 | NS_ASSERTION(mPrtPreview, "mPrtPreview can't be null!"); |
michael@0 | 386 | return GetSeqFrameAndCountPagesInternal(mPrtPreview->mPrintObject, aSeqFrame, aCount); |
michael@0 | 387 | } |
michael@0 | 388 | //--------------------------------------------------------------------------------- |
michael@0 | 389 | //-- Done: Methods needed by the DocViewer |
michael@0 | 390 | //--------------------------------------------------------------------------------- |
michael@0 | 391 | |
michael@0 | 392 | |
michael@0 | 393 | //--------------------------------------------------------------------------------- |
michael@0 | 394 | //-- Section: nsIWebBrowserPrint |
michael@0 | 395 | //--------------------------------------------------------------------------------- |
michael@0 | 396 | |
michael@0 | 397 | // Foward decl for Debug Helper Functions |
michael@0 | 398 | #ifdef EXTENDED_DEBUG_PRINTING |
michael@0 | 399 | static int RemoveFilesInDir(const char * aDir); |
michael@0 | 400 | static void GetDocTitleAndURL(nsPrintObject* aPO, char *& aDocStr, char *& aURLStr); |
michael@0 | 401 | static void DumpPrintObjectsTree(nsPrintObject * aPO, int aLevel, FILE* aFD); |
michael@0 | 402 | static void DumpPrintObjectsList(nsTArray<nsPrintObject*> * aDocList); |
michael@0 | 403 | static void RootFrameList(nsPresContext* aPresContext, FILE* out, int32_t aIndent); |
michael@0 | 404 | static void DumpViews(nsIDocShell* aDocShell, FILE* out); |
michael@0 | 405 | static void DumpLayoutData(char* aTitleStr, char* aURLStr, |
michael@0 | 406 | nsPresContext* aPresContext, |
michael@0 | 407 | nsDeviceContext * aDC, nsIFrame * aRootFrame, |
michael@0 | 408 | nsIDocShell * aDocShell, FILE* aFD); |
michael@0 | 409 | #endif |
michael@0 | 410 | |
michael@0 | 411 | //-------------------------------------------------------------------------------- |
michael@0 | 412 | |
michael@0 | 413 | nsresult |
michael@0 | 414 | nsPrintEngine::CommonPrint(bool aIsPrintPreview, |
michael@0 | 415 | nsIPrintSettings* aPrintSettings, |
michael@0 | 416 | nsIWebProgressListener* aWebProgressListener, |
michael@0 | 417 | nsIDOMDocument* aDoc) { |
michael@0 | 418 | nsRefPtr<nsPrintEngine> kungfuDeathGrip = this; |
michael@0 | 419 | nsresult rv = DoCommonPrint(aIsPrintPreview, aPrintSettings, |
michael@0 | 420 | aWebProgressListener, aDoc); |
michael@0 | 421 | if (NS_FAILED(rv)) { |
michael@0 | 422 | if (aIsPrintPreview) { |
michael@0 | 423 | SetIsCreatingPrintPreview(false); |
michael@0 | 424 | SetIsPrintPreview(false); |
michael@0 | 425 | } else { |
michael@0 | 426 | SetIsPrinting(false); |
michael@0 | 427 | } |
michael@0 | 428 | if (mProgressDialogIsShown) |
michael@0 | 429 | CloseProgressDialog(aWebProgressListener); |
michael@0 | 430 | if (rv != NS_ERROR_ABORT && rv != NS_ERROR_OUT_OF_MEMORY) |
michael@0 | 431 | ShowPrintErrorDialog(rv, !aIsPrintPreview); |
michael@0 | 432 | delete mPrt; |
michael@0 | 433 | mPrt = nullptr; |
michael@0 | 434 | } |
michael@0 | 435 | |
michael@0 | 436 | return rv; |
michael@0 | 437 | } |
michael@0 | 438 | |
michael@0 | 439 | nsresult |
michael@0 | 440 | nsPrintEngine::DoCommonPrint(bool aIsPrintPreview, |
michael@0 | 441 | nsIPrintSettings* aPrintSettings, |
michael@0 | 442 | nsIWebProgressListener* aWebProgressListener, |
michael@0 | 443 | nsIDOMDocument* aDoc) |
michael@0 | 444 | { |
michael@0 | 445 | nsresult rv; |
michael@0 | 446 | |
michael@0 | 447 | if (aIsPrintPreview) { |
michael@0 | 448 | // The WebProgressListener can be QI'ed to nsIPrintingPromptService |
michael@0 | 449 | // then that means the progress dialog is already being shown. |
michael@0 | 450 | nsCOMPtr<nsIPrintingPromptService> pps(do_QueryInterface(aWebProgressListener)); |
michael@0 | 451 | mProgressDialogIsShown = pps != nullptr; |
michael@0 | 452 | |
michael@0 | 453 | if (mIsDoingPrintPreview) { |
michael@0 | 454 | mOldPrtPreview = mPrtPreview; |
michael@0 | 455 | mPrtPreview = nullptr; |
michael@0 | 456 | } |
michael@0 | 457 | } else { |
michael@0 | 458 | mProgressDialogIsShown = false; |
michael@0 | 459 | } |
michael@0 | 460 | |
michael@0 | 461 | mPrt = new nsPrintData(aIsPrintPreview ? nsPrintData::eIsPrintPreview : |
michael@0 | 462 | nsPrintData::eIsPrinting); |
michael@0 | 463 | NS_ENSURE_TRUE(mPrt, NS_ERROR_OUT_OF_MEMORY); |
michael@0 | 464 | |
michael@0 | 465 | // if they don't pass in a PrintSettings, then get the Global PS |
michael@0 | 466 | mPrt->mPrintSettings = aPrintSettings; |
michael@0 | 467 | if (!mPrt->mPrintSettings) { |
michael@0 | 468 | rv = GetGlobalPrintSettings(getter_AddRefs(mPrt->mPrintSettings)); |
michael@0 | 469 | NS_ENSURE_SUCCESS(rv, rv); |
michael@0 | 470 | } |
michael@0 | 471 | |
michael@0 | 472 | rv = CheckForPrinters(mPrt->mPrintSettings); |
michael@0 | 473 | NS_ENSURE_SUCCESS(rv, rv); |
michael@0 | 474 | |
michael@0 | 475 | mPrt->mPrintSettings->SetIsCancelled(false); |
michael@0 | 476 | mPrt->mPrintSettings->GetShrinkToFit(&mPrt->mShrinkToFit); |
michael@0 | 477 | |
michael@0 | 478 | // In the case the margin boxes are not printed store the print settings for |
michael@0 | 479 | // the footer/header to be used as default print setting for follow up prints. |
michael@0 | 480 | mPrt->mPrintSettings->SetPersistMarginBoxSettings(!mNoMarginBoxes); |
michael@0 | 481 | |
michael@0 | 482 | if (mNoMarginBoxes) { |
michael@0 | 483 | // Set the footer/header to blank. |
michael@0 | 484 | const char16_t* emptyString = EmptyString().get(); |
michael@0 | 485 | mPrt->mPrintSettings->SetHeaderStrLeft(emptyString); |
michael@0 | 486 | mPrt->mPrintSettings->SetHeaderStrCenter(emptyString); |
michael@0 | 487 | mPrt->mPrintSettings->SetHeaderStrRight(emptyString); |
michael@0 | 488 | mPrt->mPrintSettings->SetFooterStrLeft(emptyString); |
michael@0 | 489 | mPrt->mPrintSettings->SetFooterStrCenter(emptyString); |
michael@0 | 490 | mPrt->mPrintSettings->SetFooterStrRight(emptyString); |
michael@0 | 491 | } |
michael@0 | 492 | |
michael@0 | 493 | if (aIsPrintPreview) { |
michael@0 | 494 | SetIsCreatingPrintPreview(true); |
michael@0 | 495 | SetIsPrintPreview(true); |
michael@0 | 496 | nsCOMPtr<nsIMarkupDocumentViewer> viewer = |
michael@0 | 497 | do_QueryInterface(mDocViewerPrint); |
michael@0 | 498 | if (viewer) { |
michael@0 | 499 | viewer->SetTextZoom(1.0f); |
michael@0 | 500 | viewer->SetFullZoom(1.0f); |
michael@0 | 501 | viewer->SetMinFontSize(0); |
michael@0 | 502 | } |
michael@0 | 503 | } |
michael@0 | 504 | |
michael@0 | 505 | // Create a print session and let the print settings know about it. |
michael@0 | 506 | // The print settings hold an nsWeakPtr to the session so it does not |
michael@0 | 507 | // need to be cleared from the settings at the end of the job. |
michael@0 | 508 | // XXX What lifetime does the printSession need to have? |
michael@0 | 509 | nsCOMPtr<nsIPrintSession> printSession; |
michael@0 | 510 | if (!aIsPrintPreview) { |
michael@0 | 511 | printSession = do_CreateInstance("@mozilla.org/gfx/printsession;1", &rv); |
michael@0 | 512 | NS_ENSURE_SUCCESS(rv, rv); |
michael@0 | 513 | mPrt->mPrintSettings->SetPrintSession(printSession); |
michael@0 | 514 | } |
michael@0 | 515 | |
michael@0 | 516 | if (aWebProgressListener != nullptr) { |
michael@0 | 517 | mPrt->mPrintProgressListeners.AppendObject(aWebProgressListener); |
michael@0 | 518 | } |
michael@0 | 519 | |
michael@0 | 520 | // Get the currently focused window and cache it |
michael@0 | 521 | // because the Print Dialog will "steal" focus and later when you try |
michael@0 | 522 | // to get the currently focused windows it will be nullptr |
michael@0 | 523 | mPrt->mCurrentFocusWin = FindFocusedDOMWindow(); |
michael@0 | 524 | |
michael@0 | 525 | // Check to see if there is a "regular" selection |
michael@0 | 526 | bool isSelection = IsThereARangeSelection(mPrt->mCurrentFocusWin); |
michael@0 | 527 | |
michael@0 | 528 | // Get the docshell for this documentviewer |
michael@0 | 529 | nsCOMPtr<nsIDocShell> webContainer(do_QueryReferent(mContainer, &rv)); |
michael@0 | 530 | NS_ENSURE_SUCCESS(rv, rv); |
michael@0 | 531 | |
michael@0 | 532 | { |
michael@0 | 533 | if (aIsPrintPreview) { |
michael@0 | 534 | nsCOMPtr<nsIContentViewer> viewer; |
michael@0 | 535 | webContainer->GetContentViewer(getter_AddRefs(viewer)); |
michael@0 | 536 | if (viewer && viewer->GetDocument() && viewer->GetDocument()->IsShowing()) { |
michael@0 | 537 | viewer->GetDocument()->OnPageHide(false, nullptr); |
michael@0 | 538 | } |
michael@0 | 539 | } |
michael@0 | 540 | |
michael@0 | 541 | nsAutoScriptBlocker scriptBlocker; |
michael@0 | 542 | mPrt->mPrintObject = new nsPrintObject(); |
michael@0 | 543 | NS_ENSURE_TRUE(mPrt->mPrintObject, NS_ERROR_OUT_OF_MEMORY); |
michael@0 | 544 | rv = mPrt->mPrintObject->Init(webContainer, aDoc, aIsPrintPreview); |
michael@0 | 545 | NS_ENSURE_SUCCESS(rv, rv); |
michael@0 | 546 | |
michael@0 | 547 | NS_ENSURE_TRUE(mPrt->mPrintDocList.AppendElement(mPrt->mPrintObject), |
michael@0 | 548 | NS_ERROR_OUT_OF_MEMORY); |
michael@0 | 549 | |
michael@0 | 550 | mPrt->mIsParentAFrameSet = IsParentAFrameSet(webContainer); |
michael@0 | 551 | mPrt->mPrintObject->mFrameType = mPrt->mIsParentAFrameSet ? eFrameSet : eDoc; |
michael@0 | 552 | |
michael@0 | 553 | // Build the "tree" of PrintObjects |
michael@0 | 554 | BuildDocTree(mPrt->mPrintObject->mDocShell, &mPrt->mPrintDocList, |
michael@0 | 555 | mPrt->mPrintObject); |
michael@0 | 556 | } |
michael@0 | 557 | |
michael@0 | 558 | if (!aIsPrintPreview) { |
michael@0 | 559 | SetIsPrinting(true); |
michael@0 | 560 | } |
michael@0 | 561 | |
michael@0 | 562 | // XXX This isn't really correct... |
michael@0 | 563 | if (!mPrt->mPrintObject->mDocument || |
michael@0 | 564 | !mPrt->mPrintObject->mDocument->GetRootElement()) |
michael@0 | 565 | return NS_ERROR_GFX_PRINTER_STARTDOC; |
michael@0 | 566 | |
michael@0 | 567 | // Create the linkage from the sub-docs back to the content element |
michael@0 | 568 | // in the parent document |
michael@0 | 569 | MapContentToWebShells(mPrt->mPrintObject, mPrt->mPrintObject); |
michael@0 | 570 | |
michael@0 | 571 | mPrt->mIsIFrameSelected = IsThereAnIFrameSelected(webContainer, mPrt->mCurrentFocusWin, mPrt->mIsParentAFrameSet); |
michael@0 | 572 | |
michael@0 | 573 | // Setup print options for UI |
michael@0 | 574 | if (mPrt->mIsParentAFrameSet) { |
michael@0 | 575 | if (mPrt->mCurrentFocusWin) { |
michael@0 | 576 | mPrt->mPrintSettings->SetHowToEnableFrameUI(nsIPrintSettings::kFrameEnableAll); |
michael@0 | 577 | } else { |
michael@0 | 578 | mPrt->mPrintSettings->SetHowToEnableFrameUI(nsIPrintSettings::kFrameEnableAsIsAndEach); |
michael@0 | 579 | } |
michael@0 | 580 | } else { |
michael@0 | 581 | mPrt->mPrintSettings->SetHowToEnableFrameUI(nsIPrintSettings::kFrameEnableNone); |
michael@0 | 582 | } |
michael@0 | 583 | // Now determine how to set up the Frame print UI |
michael@0 | 584 | mPrt->mPrintSettings->SetPrintOptions(nsIPrintSettings::kEnableSelectionRB, |
michael@0 | 585 | isSelection || mPrt->mIsIFrameSelected); |
michael@0 | 586 | |
michael@0 | 587 | nsCOMPtr<nsIDeviceContextSpec> devspec |
michael@0 | 588 | (do_CreateInstance("@mozilla.org/gfx/devicecontextspec;1", &rv)); |
michael@0 | 589 | NS_ENSURE_SUCCESS(rv, rv); |
michael@0 | 590 | |
michael@0 | 591 | nsScriptSuppressor scriptSuppressor(this); |
michael@0 | 592 | if (!aIsPrintPreview) { |
michael@0 | 593 | #ifdef DEBUG |
michael@0 | 594 | mPrt->mDebugFilePtr = mDebugFile; |
michael@0 | 595 | #endif |
michael@0 | 596 | |
michael@0 | 597 | scriptSuppressor.Suppress(); |
michael@0 | 598 | bool printSilently; |
michael@0 | 599 | mPrt->mPrintSettings->GetPrintSilent(&printSilently); |
michael@0 | 600 | |
michael@0 | 601 | // Check prefs for a default setting as to whether we should print silently |
michael@0 | 602 | printSilently = |
michael@0 | 603 | Preferences::GetBool("print.always_print_silent", printSilently); |
michael@0 | 604 | |
michael@0 | 605 | // Ask dialog to be Print Shown via the Plugable Printing Dialog Service |
michael@0 | 606 | // This service is for the Print Dialog and the Print Progress Dialog |
michael@0 | 607 | // If printing silently or you can't get the service continue on |
michael@0 | 608 | if (!printSilently) { |
michael@0 | 609 | nsCOMPtr<nsIPrintingPromptService> printPromptService(do_GetService(kPrintingPromptService)); |
michael@0 | 610 | if (printPromptService) { |
michael@0 | 611 | nsIDOMWindow *domWin = mDocument->GetWindow(); |
michael@0 | 612 | NS_ENSURE_TRUE(domWin, NS_ERROR_FAILURE); |
michael@0 | 613 | |
michael@0 | 614 | // Platforms not implementing a given dialog for the service may |
michael@0 | 615 | // return NS_ERROR_NOT_IMPLEMENTED or an error code. |
michael@0 | 616 | // |
michael@0 | 617 | // NS_ERROR_NOT_IMPLEMENTED indicates they want default behavior |
michael@0 | 618 | // Any other error code means we must bail out |
michael@0 | 619 | // |
michael@0 | 620 | nsCOMPtr<nsIWebBrowserPrint> wbp(do_QueryInterface(mDocViewerPrint)); |
michael@0 | 621 | rv = printPromptService->ShowPrintDialog(domWin, wbp, |
michael@0 | 622 | mPrt->mPrintSettings); |
michael@0 | 623 | // |
michael@0 | 624 | // ShowPrintDialog triggers an event loop which means we can't assume |
michael@0 | 625 | // that the state of this->{anything} matches the state we've checked |
michael@0 | 626 | // above. Including that a given {thing} is non null. |
michael@0 | 627 | if (!mPrt) { |
michael@0 | 628 | return NS_ERROR_FAILURE; |
michael@0 | 629 | } |
michael@0 | 630 | |
michael@0 | 631 | if (NS_SUCCEEDED(rv)) { |
michael@0 | 632 | // since we got the dialog and it worked then make sure we |
michael@0 | 633 | // are telling GFX we want to print silent |
michael@0 | 634 | printSilently = true; |
michael@0 | 635 | |
michael@0 | 636 | if (mPrt->mPrintSettings) { |
michael@0 | 637 | // The user might have changed shrink-to-fit in the print dialog, so update our copy of its state |
michael@0 | 638 | mPrt->mPrintSettings->GetShrinkToFit(&mPrt->mShrinkToFit); |
michael@0 | 639 | } |
michael@0 | 640 | } else if (rv == NS_ERROR_NOT_IMPLEMENTED) { |
michael@0 | 641 | // This means the Dialog service was there, |
michael@0 | 642 | // but they choose not to implement this dialog and |
michael@0 | 643 | // are looking for default behavior from the toolkit |
michael@0 | 644 | rv = NS_OK; |
michael@0 | 645 | } |
michael@0 | 646 | } else { |
michael@0 | 647 | // No dialog service available |
michael@0 | 648 | rv = NS_ERROR_NOT_IMPLEMENTED; |
michael@0 | 649 | } |
michael@0 | 650 | } else { |
michael@0 | 651 | // Call any code that requires a run of the event loop. |
michael@0 | 652 | rv = mPrt->mPrintSettings->SetupSilentPrinting(); |
michael@0 | 653 | } |
michael@0 | 654 | // Check explicitly for abort because it's expected |
michael@0 | 655 | if (rv == NS_ERROR_ABORT) |
michael@0 | 656 | return rv; |
michael@0 | 657 | NS_ENSURE_SUCCESS(rv, rv); |
michael@0 | 658 | } |
michael@0 | 659 | |
michael@0 | 660 | rv = devspec->Init(nullptr, mPrt->mPrintSettings, aIsPrintPreview); |
michael@0 | 661 | NS_ENSURE_SUCCESS(rv, rv); |
michael@0 | 662 | |
michael@0 | 663 | mPrt->mPrintDC = new nsDeviceContext(); |
michael@0 | 664 | rv = mPrt->mPrintDC->InitForPrinting(devspec); |
michael@0 | 665 | NS_ENSURE_SUCCESS(rv, rv); |
michael@0 | 666 | |
michael@0 | 667 | if (aIsPrintPreview) { |
michael@0 | 668 | mPrt->mPrintSettings->SetPrintFrameType(nsIPrintSettings::kFramesAsIs); |
michael@0 | 669 | |
michael@0 | 670 | // override any UI that wants to PrintPreview any selection or page range |
michael@0 | 671 | // we want to view every page in PrintPreview each time |
michael@0 | 672 | mPrt->mPrintSettings->SetPrintRange(nsIPrintSettings::kRangeAllPages); |
michael@0 | 673 | } else { |
michael@0 | 674 | // Always check and set the print settings first and then fall back |
michael@0 | 675 | // onto the PrintService if there isn't a PrintSettings |
michael@0 | 676 | // |
michael@0 | 677 | // Posiible Usage values: |
michael@0 | 678 | // nsIPrintSettings::kUseInternalDefault |
michael@0 | 679 | // nsIPrintSettings::kUseSettingWhenPossible |
michael@0 | 680 | // |
michael@0 | 681 | // NOTE: The consts are the same for PrintSettings and PrintSettings |
michael@0 | 682 | int16_t printFrameTypeUsage = nsIPrintSettings::kUseSettingWhenPossible; |
michael@0 | 683 | mPrt->mPrintSettings->GetPrintFrameTypeUsage(&printFrameTypeUsage); |
michael@0 | 684 | |
michael@0 | 685 | // Ok, see if we are going to use our value and override the default |
michael@0 | 686 | if (printFrameTypeUsage == nsIPrintSettings::kUseSettingWhenPossible) { |
michael@0 | 687 | // Get the Print Options/Settings PrintFrameType to see what is preferred |
michael@0 | 688 | int16_t printFrameType = nsIPrintSettings::kEachFrameSep; |
michael@0 | 689 | mPrt->mPrintSettings->GetPrintFrameType(&printFrameType); |
michael@0 | 690 | |
michael@0 | 691 | // Don't let anybody do something stupid like try to set it to |
michael@0 | 692 | // kNoFrames when we are printing a FrameSet |
michael@0 | 693 | if (printFrameType == nsIPrintSettings::kNoFrames) { |
michael@0 | 694 | mPrt->mPrintFrameType = nsIPrintSettings::kEachFrameSep; |
michael@0 | 695 | mPrt->mPrintSettings->SetPrintFrameType(mPrt->mPrintFrameType); |
michael@0 | 696 | } else { |
michael@0 | 697 | // First find out from the PrinService what options are available |
michael@0 | 698 | // to us for Printing FrameSets |
michael@0 | 699 | int16_t howToEnableFrameUI; |
michael@0 | 700 | mPrt->mPrintSettings->GetHowToEnableFrameUI(&howToEnableFrameUI); |
michael@0 | 701 | if (howToEnableFrameUI != nsIPrintSettings::kFrameEnableNone) { |
michael@0 | 702 | switch (howToEnableFrameUI) { |
michael@0 | 703 | case nsIPrintSettings::kFrameEnableAll: |
michael@0 | 704 | mPrt->mPrintFrameType = printFrameType; |
michael@0 | 705 | break; |
michael@0 | 706 | |
michael@0 | 707 | case nsIPrintSettings::kFrameEnableAsIsAndEach: |
michael@0 | 708 | if (printFrameType != nsIPrintSettings::kSelectedFrame) { |
michael@0 | 709 | mPrt->mPrintFrameType = printFrameType; |
michael@0 | 710 | } else { // revert back to a good value |
michael@0 | 711 | mPrt->mPrintFrameType = nsIPrintSettings::kEachFrameSep; |
michael@0 | 712 | } |
michael@0 | 713 | break; |
michael@0 | 714 | } // switch |
michael@0 | 715 | mPrt->mPrintSettings->SetPrintFrameType(mPrt->mPrintFrameType); |
michael@0 | 716 | } |
michael@0 | 717 | } |
michael@0 | 718 | } else { |
michael@0 | 719 | mPrt->mPrintSettings->GetPrintFrameType(&mPrt->mPrintFrameType); |
michael@0 | 720 | } |
michael@0 | 721 | } |
michael@0 | 722 | |
michael@0 | 723 | if (mPrt->mPrintFrameType == nsIPrintSettings::kEachFrameSep) { |
michael@0 | 724 | CheckForChildFrameSets(mPrt->mPrintObject); |
michael@0 | 725 | } |
michael@0 | 726 | |
michael@0 | 727 | if (NS_FAILED(EnablePOsForPrinting())) { |
michael@0 | 728 | return NS_ERROR_FAILURE; |
michael@0 | 729 | } |
michael@0 | 730 | |
michael@0 | 731 | // Attach progressListener to catch network requests. |
michael@0 | 732 | nsCOMPtr<nsIWebProgress> webProgress = do_QueryInterface(mPrt->mPrintObject->mDocShell); |
michael@0 | 733 | webProgress->AddProgressListener( |
michael@0 | 734 | static_cast<nsIWebProgressListener*>(this), |
michael@0 | 735 | nsIWebProgress::NOTIFY_STATE_REQUEST); |
michael@0 | 736 | |
michael@0 | 737 | mLoadCounter = 0; |
michael@0 | 738 | mDidLoadDataForPrinting = false; |
michael@0 | 739 | |
michael@0 | 740 | if (aIsPrintPreview) { |
michael@0 | 741 | bool notifyOnInit = false; |
michael@0 | 742 | ShowPrintProgress(false, notifyOnInit); |
michael@0 | 743 | |
michael@0 | 744 | // Very important! Turn Off scripting |
michael@0 | 745 | TurnScriptingOn(false); |
michael@0 | 746 | |
michael@0 | 747 | if (!notifyOnInit) { |
michael@0 | 748 | InstallPrintPreviewListener(); |
michael@0 | 749 | rv = InitPrintDocConstruction(false); |
michael@0 | 750 | } else { |
michael@0 | 751 | rv = NS_OK; |
michael@0 | 752 | } |
michael@0 | 753 | } else { |
michael@0 | 754 | bool doNotify; |
michael@0 | 755 | ShowPrintProgress(true, doNotify); |
michael@0 | 756 | if (!doNotify) { |
michael@0 | 757 | // Print listener setup... |
michael@0 | 758 | mPrt->OnStartPrinting(); |
michael@0 | 759 | |
michael@0 | 760 | rv = InitPrintDocConstruction(false); |
michael@0 | 761 | } |
michael@0 | 762 | } |
michael@0 | 763 | |
michael@0 | 764 | // We will enable scripting later after printing has finished. |
michael@0 | 765 | scriptSuppressor.Disconnect(); |
michael@0 | 766 | |
michael@0 | 767 | return NS_OK; |
michael@0 | 768 | } |
michael@0 | 769 | |
michael@0 | 770 | //--------------------------------------------------------------------------------- |
michael@0 | 771 | NS_IMETHODIMP |
michael@0 | 772 | nsPrintEngine::Print(nsIPrintSettings* aPrintSettings, |
michael@0 | 773 | nsIWebProgressListener* aWebProgressListener) |
michael@0 | 774 | { |
michael@0 | 775 | // If we have a print preview document, use that instead of the original |
michael@0 | 776 | // mDocument. That way animated images etc. get printed using the same state |
michael@0 | 777 | // as in print preview. |
michael@0 | 778 | nsCOMPtr<nsIDOMDocument> doc = |
michael@0 | 779 | do_QueryInterface(mPrtPreview && mPrtPreview->mPrintObject ? |
michael@0 | 780 | mPrtPreview->mPrintObject->mDocument : mDocument); |
michael@0 | 781 | |
michael@0 | 782 | return CommonPrint(false, aPrintSettings, aWebProgressListener, doc); |
michael@0 | 783 | } |
michael@0 | 784 | |
michael@0 | 785 | NS_IMETHODIMP |
michael@0 | 786 | nsPrintEngine::PrintPreview(nsIPrintSettings* aPrintSettings, |
michael@0 | 787 | nsIDOMWindow *aChildDOMWin, |
michael@0 | 788 | nsIWebProgressListener* aWebProgressListener) |
michael@0 | 789 | { |
michael@0 | 790 | // Get the DocShell and see if it is busy |
michael@0 | 791 | // (We can't Print Preview this document if it is still busy) |
michael@0 | 792 | nsCOMPtr<nsIDocShell> docShell(do_QueryReferent(mContainer)); |
michael@0 | 793 | NS_ENSURE_STATE(docShell); |
michael@0 | 794 | |
michael@0 | 795 | uint32_t busyFlags = nsIDocShell::BUSY_FLAGS_NONE; |
michael@0 | 796 | if (NS_FAILED(docShell->GetBusyFlags(&busyFlags)) || |
michael@0 | 797 | busyFlags != nsIDocShell::BUSY_FLAGS_NONE) { |
michael@0 | 798 | CloseProgressDialog(aWebProgressListener); |
michael@0 | 799 | ShowPrintErrorDialog(NS_ERROR_GFX_PRINTER_DOC_IS_BUSY, false); |
michael@0 | 800 | return NS_ERROR_FAILURE; |
michael@0 | 801 | } |
michael@0 | 802 | |
michael@0 | 803 | NS_ENSURE_STATE(aChildDOMWin); |
michael@0 | 804 | nsCOMPtr<nsIDOMDocument> doc; |
michael@0 | 805 | aChildDOMWin->GetDocument(getter_AddRefs(doc)); |
michael@0 | 806 | NS_ENSURE_STATE(doc); |
michael@0 | 807 | |
michael@0 | 808 | // Document is not busy -- go ahead with the Print Preview |
michael@0 | 809 | return CommonPrint(true, aPrintSettings, aWebProgressListener, doc); |
michael@0 | 810 | } |
michael@0 | 811 | |
michael@0 | 812 | //---------------------------------------------------------------------------------- |
michael@0 | 813 | /* readonly attribute boolean isFramesetDocument; */ |
michael@0 | 814 | NS_IMETHODIMP |
michael@0 | 815 | nsPrintEngine::GetIsFramesetDocument(bool *aIsFramesetDocument) |
michael@0 | 816 | { |
michael@0 | 817 | nsCOMPtr<nsIDocShell> webContainer(do_QueryReferent(mContainer)); |
michael@0 | 818 | *aIsFramesetDocument = IsParentAFrameSet(webContainer); |
michael@0 | 819 | return NS_OK; |
michael@0 | 820 | } |
michael@0 | 821 | |
michael@0 | 822 | //---------------------------------------------------------------------------------- |
michael@0 | 823 | /* readonly attribute boolean isIFrameSelected; */ |
michael@0 | 824 | NS_IMETHODIMP |
michael@0 | 825 | nsPrintEngine::GetIsIFrameSelected(bool *aIsIFrameSelected) |
michael@0 | 826 | { |
michael@0 | 827 | *aIsIFrameSelected = false; |
michael@0 | 828 | |
michael@0 | 829 | // Get the docshell for this documentviewer |
michael@0 | 830 | nsCOMPtr<nsIDocShell> webContainer(do_QueryReferent(mContainer)); |
michael@0 | 831 | // Get the currently focused window |
michael@0 | 832 | nsCOMPtr<nsIDOMWindow> currentFocusWin = FindFocusedDOMWindow(); |
michael@0 | 833 | if (currentFocusWin && webContainer) { |
michael@0 | 834 | // Get whether the doc contains a frameset |
michael@0 | 835 | // Also, check to see if the currently focus docshell |
michael@0 | 836 | // is a child of this docshell |
michael@0 | 837 | bool isParentFrameSet; |
michael@0 | 838 | *aIsIFrameSelected = IsThereAnIFrameSelected(webContainer, currentFocusWin, isParentFrameSet); |
michael@0 | 839 | } |
michael@0 | 840 | return NS_OK; |
michael@0 | 841 | } |
michael@0 | 842 | |
michael@0 | 843 | //---------------------------------------------------------------------------------- |
michael@0 | 844 | /* readonly attribute boolean isRangeSelection; */ |
michael@0 | 845 | NS_IMETHODIMP |
michael@0 | 846 | nsPrintEngine::GetIsRangeSelection(bool *aIsRangeSelection) |
michael@0 | 847 | { |
michael@0 | 848 | // Get the currently focused window |
michael@0 | 849 | nsCOMPtr<nsIDOMWindow> currentFocusWin = FindFocusedDOMWindow(); |
michael@0 | 850 | *aIsRangeSelection = IsThereARangeSelection(currentFocusWin); |
michael@0 | 851 | return NS_OK; |
michael@0 | 852 | } |
michael@0 | 853 | |
michael@0 | 854 | //---------------------------------------------------------------------------------- |
michael@0 | 855 | /* readonly attribute boolean isFramesetFrameSelected; */ |
michael@0 | 856 | NS_IMETHODIMP |
michael@0 | 857 | nsPrintEngine::GetIsFramesetFrameSelected(bool *aIsFramesetFrameSelected) |
michael@0 | 858 | { |
michael@0 | 859 | // Get the currently focused window |
michael@0 | 860 | nsCOMPtr<nsIDOMWindow> currentFocusWin = FindFocusedDOMWindow(); |
michael@0 | 861 | *aIsFramesetFrameSelected = currentFocusWin != nullptr; |
michael@0 | 862 | return NS_OK; |
michael@0 | 863 | } |
michael@0 | 864 | |
michael@0 | 865 | //---------------------------------------------------------------------------------- |
michael@0 | 866 | /* readonly attribute long printPreviewNumPages; */ |
michael@0 | 867 | NS_IMETHODIMP |
michael@0 | 868 | nsPrintEngine::GetPrintPreviewNumPages(int32_t *aPrintPreviewNumPages) |
michael@0 | 869 | { |
michael@0 | 870 | NS_ENSURE_ARG_POINTER(aPrintPreviewNumPages); |
michael@0 | 871 | |
michael@0 | 872 | nsPrintData* prt = nullptr; |
michael@0 | 873 | nsIFrame* seqFrame = nullptr; |
michael@0 | 874 | *aPrintPreviewNumPages = 0; |
michael@0 | 875 | |
michael@0 | 876 | // When calling this function, the FinishPrintPreview() function might not |
michael@0 | 877 | // been called as there are still some |
michael@0 | 878 | if (mPrtPreview) { |
michael@0 | 879 | prt = mPrtPreview; |
michael@0 | 880 | } else { |
michael@0 | 881 | prt = mPrt; |
michael@0 | 882 | } |
michael@0 | 883 | if ((!prt) || |
michael@0 | 884 | NS_FAILED(GetSeqFrameAndCountPagesInternal(prt->mPrintObject, seqFrame, *aPrintPreviewNumPages))) { |
michael@0 | 885 | return NS_ERROR_FAILURE; |
michael@0 | 886 | } |
michael@0 | 887 | return NS_OK; |
michael@0 | 888 | } |
michael@0 | 889 | |
michael@0 | 890 | //---------------------------------------------------------------------------------- |
michael@0 | 891 | // Enumerate all the documents for their titles |
michael@0 | 892 | NS_IMETHODIMP |
michael@0 | 893 | nsPrintEngine::EnumerateDocumentNames(uint32_t* aCount, |
michael@0 | 894 | char16_t*** aResult) |
michael@0 | 895 | { |
michael@0 | 896 | NS_ENSURE_ARG(aCount); |
michael@0 | 897 | NS_ENSURE_ARG_POINTER(aResult); |
michael@0 | 898 | |
michael@0 | 899 | *aCount = 0; |
michael@0 | 900 | *aResult = nullptr; |
michael@0 | 901 | |
michael@0 | 902 | int32_t numDocs = mPrt->mPrintDocList.Length(); |
michael@0 | 903 | char16_t** array = (char16_t**) nsMemory::Alloc(numDocs * sizeof(char16_t*)); |
michael@0 | 904 | if (!array) |
michael@0 | 905 | return NS_ERROR_OUT_OF_MEMORY; |
michael@0 | 906 | |
michael@0 | 907 | for (int32_t i=0;i<numDocs;i++) { |
michael@0 | 908 | nsPrintObject* po = mPrt->mPrintDocList.ElementAt(i); |
michael@0 | 909 | NS_ASSERTION(po, "nsPrintObject can't be null!"); |
michael@0 | 910 | nsAutoString docTitleStr; |
michael@0 | 911 | nsAutoString docURLStr; |
michael@0 | 912 | GetDocumentTitleAndURL(po->mDocument, docTitleStr, docURLStr); |
michael@0 | 913 | |
michael@0 | 914 | // Use the URL if the doc is empty |
michael@0 | 915 | if (docTitleStr.IsEmpty() && !docURLStr.IsEmpty()) { |
michael@0 | 916 | docTitleStr = docURLStr; |
michael@0 | 917 | } |
michael@0 | 918 | array[i] = ToNewUnicode(docTitleStr); |
michael@0 | 919 | } |
michael@0 | 920 | *aCount = numDocs; |
michael@0 | 921 | *aResult = array; |
michael@0 | 922 | |
michael@0 | 923 | return NS_OK; |
michael@0 | 924 | |
michael@0 | 925 | } |
michael@0 | 926 | |
michael@0 | 927 | //---------------------------------------------------------------------------------- |
michael@0 | 928 | /* readonly attribute nsIPrintSettings globalPrintSettings; */ |
michael@0 | 929 | nsresult |
michael@0 | 930 | nsPrintEngine::GetGlobalPrintSettings(nsIPrintSettings **aGlobalPrintSettings) |
michael@0 | 931 | { |
michael@0 | 932 | NS_ENSURE_ARG_POINTER(aGlobalPrintSettings); |
michael@0 | 933 | |
michael@0 | 934 | nsresult rv = NS_ERROR_FAILURE; |
michael@0 | 935 | nsCOMPtr<nsIPrintSettingsService> printSettingsService = |
michael@0 | 936 | do_GetService(sPrintSettingsServiceContractID, &rv); |
michael@0 | 937 | if (NS_SUCCEEDED(rv)) { |
michael@0 | 938 | rv = printSettingsService->GetGlobalPrintSettings(aGlobalPrintSettings); |
michael@0 | 939 | } |
michael@0 | 940 | return rv; |
michael@0 | 941 | } |
michael@0 | 942 | |
michael@0 | 943 | //---------------------------------------------------------------------------------- |
michael@0 | 944 | /* readonly attribute boolean doingPrint; */ |
michael@0 | 945 | NS_IMETHODIMP |
michael@0 | 946 | nsPrintEngine::GetDoingPrint(bool *aDoingPrint) |
michael@0 | 947 | { |
michael@0 | 948 | NS_ENSURE_ARG_POINTER(aDoingPrint); |
michael@0 | 949 | *aDoingPrint = mIsDoingPrinting; |
michael@0 | 950 | return NS_OK; |
michael@0 | 951 | } |
michael@0 | 952 | |
michael@0 | 953 | //---------------------------------------------------------------------------------- |
michael@0 | 954 | /* readonly attribute boolean doingPrintPreview; */ |
michael@0 | 955 | NS_IMETHODIMP |
michael@0 | 956 | nsPrintEngine::GetDoingPrintPreview(bool *aDoingPrintPreview) |
michael@0 | 957 | { |
michael@0 | 958 | NS_ENSURE_ARG_POINTER(aDoingPrintPreview); |
michael@0 | 959 | *aDoingPrintPreview = mIsDoingPrintPreview; |
michael@0 | 960 | return NS_OK; |
michael@0 | 961 | } |
michael@0 | 962 | |
michael@0 | 963 | //---------------------------------------------------------------------------------- |
michael@0 | 964 | /* readonly attribute nsIPrintSettings currentPrintSettings; */ |
michael@0 | 965 | NS_IMETHODIMP |
michael@0 | 966 | nsPrintEngine::GetCurrentPrintSettings(nsIPrintSettings * *aCurrentPrintSettings) |
michael@0 | 967 | { |
michael@0 | 968 | NS_ENSURE_ARG_POINTER(aCurrentPrintSettings); |
michael@0 | 969 | |
michael@0 | 970 | if (mPrt) { |
michael@0 | 971 | *aCurrentPrintSettings = mPrt->mPrintSettings; |
michael@0 | 972 | |
michael@0 | 973 | } else if (mPrtPreview) { |
michael@0 | 974 | *aCurrentPrintSettings = mPrtPreview->mPrintSettings; |
michael@0 | 975 | |
michael@0 | 976 | } else { |
michael@0 | 977 | *aCurrentPrintSettings = nullptr; |
michael@0 | 978 | } |
michael@0 | 979 | NS_IF_ADDREF(*aCurrentPrintSettings); |
michael@0 | 980 | return NS_OK; |
michael@0 | 981 | } |
michael@0 | 982 | |
michael@0 | 983 | //----------------------------------------------------------------- |
michael@0 | 984 | //-- Section: Pre-Reflow Methods |
michael@0 | 985 | //----------------------------------------------------------------- |
michael@0 | 986 | |
michael@0 | 987 | //--------------------------------------------------------------------- |
michael@0 | 988 | // This method checks to see if there is at least one printer defined |
michael@0 | 989 | // and if so, it sets the first printer in the list as the default name |
michael@0 | 990 | // in the PrintSettings which is then used for Printer Preview |
michael@0 | 991 | nsresult |
michael@0 | 992 | nsPrintEngine::CheckForPrinters(nsIPrintSettings* aPrintSettings) |
michael@0 | 993 | { |
michael@0 | 994 | #if defined(XP_MACOSX) || defined(ANDROID) |
michael@0 | 995 | // Mac doesn't support retrieving a printer list. |
michael@0 | 996 | return NS_OK; |
michael@0 | 997 | #else |
michael@0 | 998 | NS_ENSURE_ARG_POINTER(aPrintSettings); |
michael@0 | 999 | |
michael@0 | 1000 | // See if aPrintSettings already has a printer |
michael@0 | 1001 | nsXPIDLString printerName; |
michael@0 | 1002 | nsresult rv = aPrintSettings->GetPrinterName(getter_Copies(printerName)); |
michael@0 | 1003 | if (NS_SUCCEEDED(rv) && !printerName.IsEmpty()) { |
michael@0 | 1004 | return NS_OK; |
michael@0 | 1005 | } |
michael@0 | 1006 | |
michael@0 | 1007 | // aPrintSettings doesn't have a printer set. Try to fetch the default. |
michael@0 | 1008 | nsCOMPtr<nsIPrintSettingsService> printSettingsService = |
michael@0 | 1009 | do_GetService(sPrintSettingsServiceContractID, &rv); |
michael@0 | 1010 | NS_ENSURE_SUCCESS(rv, rv); |
michael@0 | 1011 | |
michael@0 | 1012 | rv = printSettingsService->GetDefaultPrinterName(getter_Copies(printerName)); |
michael@0 | 1013 | if (NS_SUCCEEDED(rv) && !printerName.IsEmpty()) { |
michael@0 | 1014 | rv = aPrintSettings->SetPrinterName(printerName.get()); |
michael@0 | 1015 | } |
michael@0 | 1016 | return rv; |
michael@0 | 1017 | #endif |
michael@0 | 1018 | } |
michael@0 | 1019 | |
michael@0 | 1020 | //---------------------------------------------------------------------- |
michael@0 | 1021 | // Set up to use the "pluggable" Print Progress Dialog |
michael@0 | 1022 | void |
michael@0 | 1023 | nsPrintEngine::ShowPrintProgress(bool aIsForPrinting, bool& aDoNotify) |
michael@0 | 1024 | { |
michael@0 | 1025 | // default to not notifying, that if something here goes wrong |
michael@0 | 1026 | // or we aren't going to show the progress dialog we can straight into |
michael@0 | 1027 | // reflowing the doc for printing. |
michael@0 | 1028 | aDoNotify = false; |
michael@0 | 1029 | |
michael@0 | 1030 | // Assume we can't do progress and then see if we can |
michael@0 | 1031 | bool showProgresssDialog = false; |
michael@0 | 1032 | |
michael@0 | 1033 | // if it is already being shown then don't bother to find out if it should be |
michael@0 | 1034 | // so skip this and leave mShowProgressDialog set to FALSE |
michael@0 | 1035 | if (!mProgressDialogIsShown) { |
michael@0 | 1036 | showProgresssDialog = Preferences::GetBool("print.show_print_progress"); |
michael@0 | 1037 | } |
michael@0 | 1038 | |
michael@0 | 1039 | // Turning off the showing of Print Progress in Prefs overrides |
michael@0 | 1040 | // whether the calling PS desire to have it on or off, so only check PS if |
michael@0 | 1041 | // prefs says it's ok to be on. |
michael@0 | 1042 | if (showProgresssDialog) { |
michael@0 | 1043 | mPrt->mPrintSettings->GetShowPrintProgress(&showProgresssDialog); |
michael@0 | 1044 | } |
michael@0 | 1045 | |
michael@0 | 1046 | // Now open the service to get the progress dialog |
michael@0 | 1047 | // If we don't get a service, that's ok, then just don't show progress |
michael@0 | 1048 | if (showProgresssDialog) { |
michael@0 | 1049 | nsCOMPtr<nsIPrintingPromptService> printPromptService(do_GetService(kPrintingPromptService)); |
michael@0 | 1050 | if (printPromptService) { |
michael@0 | 1051 | nsPIDOMWindow *domWin = mDocument->GetWindow(); |
michael@0 | 1052 | if (!domWin) return; |
michael@0 | 1053 | |
michael@0 | 1054 | nsCOMPtr<nsIDocShell> docShell = domWin->GetDocShell(); |
michael@0 | 1055 | if (!docShell) return; |
michael@0 | 1056 | nsCOMPtr<nsIDocShellTreeOwner> owner; |
michael@0 | 1057 | docShell->GetTreeOwner(getter_AddRefs(owner)); |
michael@0 | 1058 | nsCOMPtr<nsIWebBrowserChrome> browserChrome = do_GetInterface(owner); |
michael@0 | 1059 | if (!browserChrome) return; |
michael@0 | 1060 | bool isModal = true; |
michael@0 | 1061 | browserChrome->IsWindowModal(&isModal); |
michael@0 | 1062 | if (isModal) { |
michael@0 | 1063 | // Showing a print progress dialog when printing a modal window |
michael@0 | 1064 | // isn't supported. See bug 301560. |
michael@0 | 1065 | return; |
michael@0 | 1066 | } |
michael@0 | 1067 | |
michael@0 | 1068 | nsCOMPtr<nsIWebProgressListener> printProgressListener; |
michael@0 | 1069 | |
michael@0 | 1070 | nsCOMPtr<nsIWebBrowserPrint> wbp(do_QueryInterface(mDocViewerPrint)); |
michael@0 | 1071 | nsresult rv = printPromptService->ShowProgress(domWin, wbp, mPrt->mPrintSettings, this, aIsForPrinting, |
michael@0 | 1072 | getter_AddRefs(printProgressListener), |
michael@0 | 1073 | getter_AddRefs(mPrt->mPrintProgressParams), |
michael@0 | 1074 | &aDoNotify); |
michael@0 | 1075 | if (NS_SUCCEEDED(rv)) { |
michael@0 | 1076 | if (printProgressListener && mPrt->mPrintProgressParams) { |
michael@0 | 1077 | mPrt->mPrintProgressListeners.AppendObject(printProgressListener); |
michael@0 | 1078 | SetDocAndURLIntoProgress(mPrt->mPrintObject, mPrt->mPrintProgressParams); |
michael@0 | 1079 | } |
michael@0 | 1080 | } |
michael@0 | 1081 | } |
michael@0 | 1082 | } |
michael@0 | 1083 | } |
michael@0 | 1084 | |
michael@0 | 1085 | //--------------------------------------------------------------------- |
michael@0 | 1086 | bool |
michael@0 | 1087 | nsPrintEngine::IsThereARangeSelection(nsIDOMWindow* aDOMWin) |
michael@0 | 1088 | { |
michael@0 | 1089 | if (mDisallowSelectionPrint) |
michael@0 | 1090 | return false; |
michael@0 | 1091 | |
michael@0 | 1092 | nsCOMPtr<nsIPresShell> presShell; |
michael@0 | 1093 | if (aDOMWin) { |
michael@0 | 1094 | nsCOMPtr<nsPIDOMWindow> window(do_QueryInterface(aDOMWin)); |
michael@0 | 1095 | presShell = window->GetDocShell()->GetPresShell(); |
michael@0 | 1096 | } |
michael@0 | 1097 | |
michael@0 | 1098 | if (!presShell) |
michael@0 | 1099 | return false; |
michael@0 | 1100 | |
michael@0 | 1101 | // check here to see if there is a range selection |
michael@0 | 1102 | // so we know whether to turn on the "Selection" radio button |
michael@0 | 1103 | Selection* selection = |
michael@0 | 1104 | presShell->GetCurrentSelection(nsISelectionController::SELECTION_NORMAL); |
michael@0 | 1105 | if (!selection) { |
michael@0 | 1106 | return false; |
michael@0 | 1107 | } |
michael@0 | 1108 | |
michael@0 | 1109 | int32_t rangeCount = selection->GetRangeCount(); |
michael@0 | 1110 | if (!rangeCount) { |
michael@0 | 1111 | return false; |
michael@0 | 1112 | } |
michael@0 | 1113 | |
michael@0 | 1114 | if (rangeCount > 1) { |
michael@0 | 1115 | return true; |
michael@0 | 1116 | } |
michael@0 | 1117 | |
michael@0 | 1118 | // check to make sure it isn't an insertion selection |
michael@0 | 1119 | return selection->GetRangeAt(0) && !selection->IsCollapsed(); |
michael@0 | 1120 | } |
michael@0 | 1121 | |
michael@0 | 1122 | //--------------------------------------------------------------------- |
michael@0 | 1123 | bool |
michael@0 | 1124 | nsPrintEngine::IsParentAFrameSet(nsIDocShell * aParent) |
michael@0 | 1125 | { |
michael@0 | 1126 | // See if the incoming doc is the root document |
michael@0 | 1127 | if (!aParent) return false; |
michael@0 | 1128 | |
michael@0 | 1129 | // When it is the top level document we need to check |
michael@0 | 1130 | // to see if it contains a frameset. If it does, then |
michael@0 | 1131 | // we only want to print the doc's children and not the document itself |
michael@0 | 1132 | // For anything else we always print all the children and the document |
michael@0 | 1133 | // for example, if the doc contains an IFRAME we eant to print the child |
michael@0 | 1134 | // document (the IFRAME) and then the rest of the document. |
michael@0 | 1135 | // |
michael@0 | 1136 | // XXX we really need to search the frame tree, and not the content |
michael@0 | 1137 | // but there is no way to distinguish between IFRAMEs and FRAMEs |
michael@0 | 1138 | // with the GetFrameType call. |
michael@0 | 1139 | // Bug 53459 has been files so we can eventually distinguish |
michael@0 | 1140 | // between IFRAME frames and FRAME frames |
michael@0 | 1141 | bool isFrameSet = false; |
michael@0 | 1142 | // only check to see if there is a frameset if there is |
michael@0 | 1143 | // NO parent doc for this doc. meaning this parent is the root doc |
michael@0 | 1144 | nsCOMPtr<nsIDOMDocument> domDoc = do_GetInterface(aParent); |
michael@0 | 1145 | nsCOMPtr<nsIDocument> doc = do_QueryInterface(domDoc); |
michael@0 | 1146 | if (doc) { |
michael@0 | 1147 | nsIContent *rootElement = doc->GetRootElement(); |
michael@0 | 1148 | if (rootElement) { |
michael@0 | 1149 | isFrameSet = HasFramesetChild(rootElement); |
michael@0 | 1150 | } |
michael@0 | 1151 | } |
michael@0 | 1152 | return isFrameSet; |
michael@0 | 1153 | } |
michael@0 | 1154 | |
michael@0 | 1155 | |
michael@0 | 1156 | //--------------------------------------------------------------------- |
michael@0 | 1157 | // Recursively build a list of sub documents to be printed |
michael@0 | 1158 | // that mirrors the document tree |
michael@0 | 1159 | void |
michael@0 | 1160 | nsPrintEngine::BuildDocTree(nsIDocShell * aParentNode, |
michael@0 | 1161 | nsTArray<nsPrintObject*> * aDocList, |
michael@0 | 1162 | nsPrintObject * aPO) |
michael@0 | 1163 | { |
michael@0 | 1164 | NS_ASSERTION(aParentNode, "Pointer is null!"); |
michael@0 | 1165 | NS_ASSERTION(aDocList, "Pointer is null!"); |
michael@0 | 1166 | NS_ASSERTION(aPO, "Pointer is null!"); |
michael@0 | 1167 | |
michael@0 | 1168 | int32_t childWebshellCount; |
michael@0 | 1169 | aParentNode->GetChildCount(&childWebshellCount); |
michael@0 | 1170 | if (childWebshellCount > 0) { |
michael@0 | 1171 | for (int32_t i=0;i<childWebshellCount;i++) { |
michael@0 | 1172 | nsCOMPtr<nsIDocShellTreeItem> child; |
michael@0 | 1173 | aParentNode->GetChildAt(i, getter_AddRefs(child)); |
michael@0 | 1174 | nsCOMPtr<nsIDocShell> childAsShell(do_QueryInterface(child)); |
michael@0 | 1175 | |
michael@0 | 1176 | nsCOMPtr<nsIContentViewer> viewer; |
michael@0 | 1177 | childAsShell->GetContentViewer(getter_AddRefs(viewer)); |
michael@0 | 1178 | if (viewer) { |
michael@0 | 1179 | nsCOMPtr<nsIContentViewerFile> viewerFile(do_QueryInterface(viewer)); |
michael@0 | 1180 | if (viewerFile) { |
michael@0 | 1181 | nsCOMPtr<nsIDOMDocument> doc = do_GetInterface(childAsShell); |
michael@0 | 1182 | nsPrintObject * po = new nsPrintObject(); |
michael@0 | 1183 | po->mParent = aPO; |
michael@0 | 1184 | nsresult rv = po->Init(childAsShell, doc, aPO->mPrintPreview); |
michael@0 | 1185 | if (NS_FAILED(rv)) |
michael@0 | 1186 | NS_NOTREACHED("Init failed?"); |
michael@0 | 1187 | aPO->mKids.AppendElement(po); |
michael@0 | 1188 | aDocList->AppendElement(po); |
michael@0 | 1189 | BuildDocTree(childAsShell, aDocList, po); |
michael@0 | 1190 | } |
michael@0 | 1191 | } |
michael@0 | 1192 | } |
michael@0 | 1193 | } |
michael@0 | 1194 | } |
michael@0 | 1195 | |
michael@0 | 1196 | //--------------------------------------------------------------------- |
michael@0 | 1197 | void |
michael@0 | 1198 | nsPrintEngine::GetDocumentTitleAndURL(nsIDocument* aDoc, |
michael@0 | 1199 | nsAString& aTitle, |
michael@0 | 1200 | nsAString& aURLStr) |
michael@0 | 1201 | { |
michael@0 | 1202 | NS_ASSERTION(aDoc, "Pointer is null!"); |
michael@0 | 1203 | |
michael@0 | 1204 | aTitle.Truncate(); |
michael@0 | 1205 | aURLStr.Truncate(); |
michael@0 | 1206 | |
michael@0 | 1207 | nsCOMPtr<nsIDOMDocument> doc = do_QueryInterface(aDoc); |
michael@0 | 1208 | doc->GetTitle(aTitle); |
michael@0 | 1209 | |
michael@0 | 1210 | nsIURI* url = aDoc->GetDocumentURI(); |
michael@0 | 1211 | if (!url) return; |
michael@0 | 1212 | |
michael@0 | 1213 | nsCOMPtr<nsIURIFixup> urifixup(do_GetService(NS_URIFIXUP_CONTRACTID)); |
michael@0 | 1214 | if (!urifixup) return; |
michael@0 | 1215 | |
michael@0 | 1216 | nsCOMPtr<nsIURI> exposableURI; |
michael@0 | 1217 | urifixup->CreateExposableURI(url, getter_AddRefs(exposableURI)); |
michael@0 | 1218 | |
michael@0 | 1219 | if (!exposableURI) return; |
michael@0 | 1220 | |
michael@0 | 1221 | nsAutoCString urlCStr; |
michael@0 | 1222 | exposableURI->GetSpec(urlCStr); |
michael@0 | 1223 | |
michael@0 | 1224 | nsresult rv; |
michael@0 | 1225 | nsCOMPtr<nsITextToSubURI> textToSubURI = |
michael@0 | 1226 | do_GetService(NS_ITEXTTOSUBURI_CONTRACTID, &rv); |
michael@0 | 1227 | if (NS_FAILED(rv)) return; |
michael@0 | 1228 | |
michael@0 | 1229 | textToSubURI->UnEscapeURIForUI(NS_LITERAL_CSTRING("UTF-8"), |
michael@0 | 1230 | urlCStr, aURLStr); |
michael@0 | 1231 | } |
michael@0 | 1232 | |
michael@0 | 1233 | //--------------------------------------------------------------------- |
michael@0 | 1234 | // The walks the PO tree and for each document it walks the content |
michael@0 | 1235 | // tree looking for any content that are sub-shells |
michael@0 | 1236 | // |
michael@0 | 1237 | // It then sets the mContent pointer in the "found" PO object back to the |
michael@0 | 1238 | // the document that contained it. |
michael@0 | 1239 | void |
michael@0 | 1240 | nsPrintEngine::MapContentToWebShells(nsPrintObject* aRootPO, |
michael@0 | 1241 | nsPrintObject* aPO) |
michael@0 | 1242 | { |
michael@0 | 1243 | NS_ASSERTION(aRootPO, "Pointer is null!"); |
michael@0 | 1244 | NS_ASSERTION(aPO, "Pointer is null!"); |
michael@0 | 1245 | |
michael@0 | 1246 | // Recursively walk the content from the root item |
michael@0 | 1247 | // XXX Would be faster to enumerate the subdocuments, although right now |
michael@0 | 1248 | // nsIDocument doesn't expose quite what would be needed. |
michael@0 | 1249 | nsCOMPtr<nsIContentViewer> viewer; |
michael@0 | 1250 | aPO->mDocShell->GetContentViewer(getter_AddRefs(viewer)); |
michael@0 | 1251 | if (!viewer) return; |
michael@0 | 1252 | |
michael@0 | 1253 | nsCOMPtr<nsIDOMDocument> domDoc; |
michael@0 | 1254 | viewer->GetDOMDocument(getter_AddRefs(domDoc)); |
michael@0 | 1255 | nsCOMPtr<nsIDocument> doc = do_QueryInterface(domDoc); |
michael@0 | 1256 | if (!doc) return; |
michael@0 | 1257 | |
michael@0 | 1258 | Element* rootElement = doc->GetRootElement(); |
michael@0 | 1259 | if (rootElement) { |
michael@0 | 1260 | MapContentForPO(aPO, rootElement); |
michael@0 | 1261 | } else { |
michael@0 | 1262 | NS_WARNING("Null root content on (sub)document."); |
michael@0 | 1263 | } |
michael@0 | 1264 | |
michael@0 | 1265 | // Continue recursively walking the chilren of this PO |
michael@0 | 1266 | for (uint32_t i=0;i<aPO->mKids.Length();i++) { |
michael@0 | 1267 | MapContentToWebShells(aRootPO, aPO->mKids[i]); |
michael@0 | 1268 | } |
michael@0 | 1269 | |
michael@0 | 1270 | } |
michael@0 | 1271 | |
michael@0 | 1272 | //------------------------------------------------------- |
michael@0 | 1273 | // A Frame's sub-doc may contain content or a FrameSet |
michael@0 | 1274 | // When it contains a FrameSet the mFrameType for the PrintObject |
michael@0 | 1275 | // is always set to an eFrame. Which is fine when printing "AsIs" |
michael@0 | 1276 | // but is incorrect when when printing "Each Frame Separately". |
michael@0 | 1277 | // When printing "Each Frame Separately" the Frame really acts like |
michael@0 | 1278 | // a frameset. |
michael@0 | 1279 | // |
michael@0 | 1280 | // This method walks the PO tree and checks to see if the PrintObject is |
michael@0 | 1281 | // an eFrame and has children that are eFrames (meaning it's a Frame containing a FrameSet) |
michael@0 | 1282 | // If so, then the mFrameType need to be changed to eFrameSet |
michael@0 | 1283 | // |
michael@0 | 1284 | // Also note: We only want to call this we are printing "Each Frame Separately" |
michael@0 | 1285 | // when printing "As Is" leave it as an eFrame |
michael@0 | 1286 | void |
michael@0 | 1287 | nsPrintEngine::CheckForChildFrameSets(nsPrintObject* aPO) |
michael@0 | 1288 | { |
michael@0 | 1289 | NS_ASSERTION(aPO, "Pointer is null!"); |
michael@0 | 1290 | |
michael@0 | 1291 | // Continue recursively walking the chilren of this PO |
michael@0 | 1292 | bool hasChildFrames = false; |
michael@0 | 1293 | for (uint32_t i=0;i<aPO->mKids.Length();i++) { |
michael@0 | 1294 | nsPrintObject* po = aPO->mKids[i]; |
michael@0 | 1295 | if (po->mFrameType == eFrame) { |
michael@0 | 1296 | hasChildFrames = true; |
michael@0 | 1297 | CheckForChildFrameSets(po); |
michael@0 | 1298 | } |
michael@0 | 1299 | } |
michael@0 | 1300 | |
michael@0 | 1301 | if (hasChildFrames && aPO->mFrameType == eFrame) { |
michael@0 | 1302 | aPO->mFrameType = eFrameSet; |
michael@0 | 1303 | } |
michael@0 | 1304 | } |
michael@0 | 1305 | |
michael@0 | 1306 | //--------------------------------------------------------------------- |
michael@0 | 1307 | // This method is key to the entire print mechanism. |
michael@0 | 1308 | // |
michael@0 | 1309 | // This "maps" or figures out which sub-doc represents a |
michael@0 | 1310 | // given Frame or IFrame in its parent sub-doc. |
michael@0 | 1311 | // |
michael@0 | 1312 | // So the Mcontent pointer in the child sub-doc points to the |
michael@0 | 1313 | // content in the its parent document, that caused it to be printed. |
michael@0 | 1314 | // This is used later to (after reflow) to find the absolute location |
michael@0 | 1315 | // of the sub-doc on its parent's page frame so it can be |
michael@0 | 1316 | // printed in the correct location. |
michael@0 | 1317 | // |
michael@0 | 1318 | // This method recursvely "walks" the content for a document finding |
michael@0 | 1319 | // all the Frames and IFrames, then sets the "mFrameType" data member |
michael@0 | 1320 | // which tells us what type of PO we have |
michael@0 | 1321 | void |
michael@0 | 1322 | nsPrintEngine::MapContentForPO(nsPrintObject* aPO, |
michael@0 | 1323 | nsIContent* aContent) |
michael@0 | 1324 | { |
michael@0 | 1325 | NS_PRECONDITION(aPO && aContent, "Null argument"); |
michael@0 | 1326 | |
michael@0 | 1327 | nsIDocument* doc = aContent->GetDocument(); |
michael@0 | 1328 | |
michael@0 | 1329 | NS_ASSERTION(doc, "Content without a document from a document tree?"); |
michael@0 | 1330 | |
michael@0 | 1331 | nsIDocument* subDoc = doc->GetSubDocumentFor(aContent); |
michael@0 | 1332 | |
michael@0 | 1333 | if (subDoc) { |
michael@0 | 1334 | nsCOMPtr<nsIDocShell> docShell(subDoc->GetDocShell()); |
michael@0 | 1335 | |
michael@0 | 1336 | if (docShell) { |
michael@0 | 1337 | nsPrintObject * po = nullptr; |
michael@0 | 1338 | int32_t cnt = aPO->mKids.Length(); |
michael@0 | 1339 | for (int32_t i=0;i<cnt;i++) { |
michael@0 | 1340 | nsPrintObject* kid = aPO->mKids.ElementAt(i); |
michael@0 | 1341 | if (kid->mDocument == subDoc) { |
michael@0 | 1342 | po = kid; |
michael@0 | 1343 | break; |
michael@0 | 1344 | } |
michael@0 | 1345 | } |
michael@0 | 1346 | |
michael@0 | 1347 | // XXX If a subdocument has no onscreen presentation, there will be no PO |
michael@0 | 1348 | // This is even if there should be a print presentation |
michael@0 | 1349 | if (po) { |
michael@0 | 1350 | |
michael@0 | 1351 | nsCOMPtr<nsIDOMHTMLFrameElement> frame(do_QueryInterface(aContent)); |
michael@0 | 1352 | // "frame" elements not in a frameset context should be treated |
michael@0 | 1353 | // as iframes |
michael@0 | 1354 | if (frame && po->mParent->mFrameType == eFrameSet) { |
michael@0 | 1355 | po->mFrameType = eFrame; |
michael@0 | 1356 | } else { |
michael@0 | 1357 | // Assume something iframe-like, i.e. iframe, object, or embed |
michael@0 | 1358 | po->mFrameType = eIFrame; |
michael@0 | 1359 | SetPrintAsIs(po, true); |
michael@0 | 1360 | NS_ASSERTION(po->mParent, "The root must be a parent"); |
michael@0 | 1361 | po->mParent->mPrintAsIs = true; |
michael@0 | 1362 | } |
michael@0 | 1363 | } |
michael@0 | 1364 | } |
michael@0 | 1365 | } |
michael@0 | 1366 | |
michael@0 | 1367 | // walk children content |
michael@0 | 1368 | for (nsIContent* child = aContent->GetFirstChild(); |
michael@0 | 1369 | child; |
michael@0 | 1370 | child = child->GetNextSibling()) { |
michael@0 | 1371 | MapContentForPO(aPO, child); |
michael@0 | 1372 | } |
michael@0 | 1373 | } |
michael@0 | 1374 | |
michael@0 | 1375 | //--------------------------------------------------------------------- |
michael@0 | 1376 | bool |
michael@0 | 1377 | nsPrintEngine::IsThereAnIFrameSelected(nsIDocShell* aDocShell, |
michael@0 | 1378 | nsIDOMWindow* aDOMWin, |
michael@0 | 1379 | bool& aIsParentFrameSet) |
michael@0 | 1380 | { |
michael@0 | 1381 | aIsParentFrameSet = IsParentAFrameSet(aDocShell); |
michael@0 | 1382 | bool iFrameIsSelected = false; |
michael@0 | 1383 | if (mPrt && mPrt->mPrintObject) { |
michael@0 | 1384 | nsPrintObject* po = FindPrintObjectByDOMWin(mPrt->mPrintObject, aDOMWin); |
michael@0 | 1385 | iFrameIsSelected = po && po->mFrameType == eIFrame; |
michael@0 | 1386 | } else { |
michael@0 | 1387 | // First, check to see if we are a frameset |
michael@0 | 1388 | if (!aIsParentFrameSet) { |
michael@0 | 1389 | // Check to see if there is a currenlt focused frame |
michael@0 | 1390 | // if so, it means the selected frame is either the main docshell |
michael@0 | 1391 | // or an IFRAME |
michael@0 | 1392 | if (aDOMWin) { |
michael@0 | 1393 | // Get the main docshell's DOMWin to see if it matches |
michael@0 | 1394 | // the frame that is selected |
michael@0 | 1395 | nsCOMPtr<nsIDOMWindow> domWin = do_GetInterface(aDocShell); |
michael@0 | 1396 | if (domWin != aDOMWin) { |
michael@0 | 1397 | iFrameIsSelected = true; // we have a selected IFRAME |
michael@0 | 1398 | } |
michael@0 | 1399 | } |
michael@0 | 1400 | } |
michael@0 | 1401 | } |
michael@0 | 1402 | |
michael@0 | 1403 | return iFrameIsSelected; |
michael@0 | 1404 | } |
michael@0 | 1405 | |
michael@0 | 1406 | //--------------------------------------------------------------------- |
michael@0 | 1407 | // Recursively sets all the PO items to be printed |
michael@0 | 1408 | // from the given item down into the tree |
michael@0 | 1409 | void |
michael@0 | 1410 | nsPrintEngine::SetPrintPO(nsPrintObject* aPO, bool aPrint) |
michael@0 | 1411 | { |
michael@0 | 1412 | NS_ASSERTION(aPO, "Pointer is null!"); |
michael@0 | 1413 | |
michael@0 | 1414 | // Set whether to print flag |
michael@0 | 1415 | aPO->mDontPrint = !aPrint; |
michael@0 | 1416 | |
michael@0 | 1417 | for (uint32_t i=0;i<aPO->mKids.Length();i++) { |
michael@0 | 1418 | SetPrintPO(aPO->mKids[i], aPrint); |
michael@0 | 1419 | } |
michael@0 | 1420 | } |
michael@0 | 1421 | |
michael@0 | 1422 | //--------------------------------------------------------------------- |
michael@0 | 1423 | // This will first use a Title and/or URL from the PrintSettings |
michael@0 | 1424 | // if one isn't set then it uses the one from the document |
michael@0 | 1425 | // then if not title is there we will make sure we send something back |
michael@0 | 1426 | // depending on the situation. |
michael@0 | 1427 | void |
michael@0 | 1428 | nsPrintEngine::GetDisplayTitleAndURL(nsPrintObject* aPO, |
michael@0 | 1429 | nsAString& aTitle, |
michael@0 | 1430 | nsAString& aURLStr, |
michael@0 | 1431 | eDocTitleDefault aDefType) |
michael@0 | 1432 | { |
michael@0 | 1433 | NS_ASSERTION(aPO, "Pointer is null!"); |
michael@0 | 1434 | |
michael@0 | 1435 | if (!mPrt) |
michael@0 | 1436 | return; |
michael@0 | 1437 | |
michael@0 | 1438 | aTitle.Truncate(); |
michael@0 | 1439 | aURLStr.Truncate(); |
michael@0 | 1440 | |
michael@0 | 1441 | // First check to see if the PrintSettings has defined an alternate title |
michael@0 | 1442 | // and use that if it did |
michael@0 | 1443 | if (mPrt->mPrintSettings) { |
michael@0 | 1444 | char16_t * docTitleStrPS = nullptr; |
michael@0 | 1445 | char16_t * docURLStrPS = nullptr; |
michael@0 | 1446 | mPrt->mPrintSettings->GetTitle(&docTitleStrPS); |
michael@0 | 1447 | mPrt->mPrintSettings->GetDocURL(&docURLStrPS); |
michael@0 | 1448 | |
michael@0 | 1449 | if (docTitleStrPS) { |
michael@0 | 1450 | aTitle = docTitleStrPS; |
michael@0 | 1451 | } |
michael@0 | 1452 | |
michael@0 | 1453 | if (docURLStrPS) { |
michael@0 | 1454 | aURLStr = docURLStrPS; |
michael@0 | 1455 | } |
michael@0 | 1456 | |
michael@0 | 1457 | nsMemory::Free(docTitleStrPS); |
michael@0 | 1458 | nsMemory::Free(docURLStrPS); |
michael@0 | 1459 | } |
michael@0 | 1460 | |
michael@0 | 1461 | nsAutoString docTitle; |
michael@0 | 1462 | nsAutoString docUrl; |
michael@0 | 1463 | GetDocumentTitleAndURL(aPO->mDocument, docTitle, docUrl); |
michael@0 | 1464 | |
michael@0 | 1465 | if (aURLStr.IsEmpty() && !docUrl.IsEmpty()) { |
michael@0 | 1466 | aURLStr = docUrl; |
michael@0 | 1467 | } |
michael@0 | 1468 | |
michael@0 | 1469 | if (aTitle.IsEmpty()) { |
michael@0 | 1470 | if (!docTitle.IsEmpty()) { |
michael@0 | 1471 | aTitle = docTitle; |
michael@0 | 1472 | } else { |
michael@0 | 1473 | if (aDefType == eDocTitleDefURLDoc) { |
michael@0 | 1474 | if (!aURLStr.IsEmpty()) { |
michael@0 | 1475 | aTitle = aURLStr; |
michael@0 | 1476 | } else if (mPrt->mBrandName) { |
michael@0 | 1477 | aTitle = mPrt->mBrandName; |
michael@0 | 1478 | } |
michael@0 | 1479 | } |
michael@0 | 1480 | } |
michael@0 | 1481 | } |
michael@0 | 1482 | } |
michael@0 | 1483 | |
michael@0 | 1484 | //--------------------------------------------------------------------- |
michael@0 | 1485 | nsresult nsPrintEngine::DocumentReadyForPrinting() |
michael@0 | 1486 | { |
michael@0 | 1487 | if (mPrt->mPrintFrameType == nsIPrintSettings::kEachFrameSep) { |
michael@0 | 1488 | CheckForChildFrameSets(mPrt->mPrintObject); |
michael@0 | 1489 | } |
michael@0 | 1490 | |
michael@0 | 1491 | // |
michael@0 | 1492 | // Send the document to the printer... |
michael@0 | 1493 | // |
michael@0 | 1494 | nsresult rv = SetupToPrintContent(); |
michael@0 | 1495 | if (NS_FAILED(rv)) { |
michael@0 | 1496 | // The print job was canceled or there was a problem |
michael@0 | 1497 | // So remove all other documents from the print list |
michael@0 | 1498 | DonePrintingPages(nullptr, rv); |
michael@0 | 1499 | } |
michael@0 | 1500 | return rv; |
michael@0 | 1501 | } |
michael@0 | 1502 | |
michael@0 | 1503 | /** --------------------------------------------------- |
michael@0 | 1504 | * Cleans up when an error occurred |
michael@0 | 1505 | */ |
michael@0 | 1506 | nsresult nsPrintEngine::CleanupOnFailure(nsresult aResult, bool aIsPrinting) |
michael@0 | 1507 | { |
michael@0 | 1508 | PR_PL(("**** Failed %s - rv 0x%X", aIsPrinting?"Printing":"Print Preview", aResult)); |
michael@0 | 1509 | |
michael@0 | 1510 | /* cleanup... */ |
michael@0 | 1511 | if (mPagePrintTimer) { |
michael@0 | 1512 | mPagePrintTimer->Stop(); |
michael@0 | 1513 | NS_RELEASE(mPagePrintTimer); |
michael@0 | 1514 | } |
michael@0 | 1515 | |
michael@0 | 1516 | if (aIsPrinting) { |
michael@0 | 1517 | SetIsPrinting(false); |
michael@0 | 1518 | } else { |
michael@0 | 1519 | SetIsPrintPreview(false); |
michael@0 | 1520 | SetIsCreatingPrintPreview(false); |
michael@0 | 1521 | } |
michael@0 | 1522 | |
michael@0 | 1523 | /* cleanup done, let's fire-up an error dialog to notify the user |
michael@0 | 1524 | * what went wrong... |
michael@0 | 1525 | * |
michael@0 | 1526 | * When rv == NS_ERROR_ABORT, it means we want out of the |
michael@0 | 1527 | * print job without displaying any error messages |
michael@0 | 1528 | */ |
michael@0 | 1529 | if (aResult != NS_ERROR_ABORT) { |
michael@0 | 1530 | ShowPrintErrorDialog(aResult, aIsPrinting); |
michael@0 | 1531 | } |
michael@0 | 1532 | |
michael@0 | 1533 | FirePrintCompletionEvent(); |
michael@0 | 1534 | |
michael@0 | 1535 | return aResult; |
michael@0 | 1536 | |
michael@0 | 1537 | } |
michael@0 | 1538 | |
michael@0 | 1539 | //--------------------------------------------------------------------- |
michael@0 | 1540 | void |
michael@0 | 1541 | nsPrintEngine::ShowPrintErrorDialog(nsresult aPrintError, bool aIsPrinting) |
michael@0 | 1542 | { |
michael@0 | 1543 | nsAutoCString stringName; |
michael@0 | 1544 | nsXPIDLString msg, title; |
michael@0 | 1545 | nsresult rv = NS_OK; |
michael@0 | 1546 | |
michael@0 | 1547 | switch(aPrintError) |
michael@0 | 1548 | { |
michael@0 | 1549 | #define ENTITY_FOR_ERROR(label) \ |
michael@0 | 1550 | case NS_ERROR_##label: stringName.AssignLiteral("PERR_" #label); break |
michael@0 | 1551 | |
michael@0 | 1552 | ENTITY_FOR_ERROR(GFX_PRINTER_NO_PRINTER_AVAILABLE); |
michael@0 | 1553 | ENTITY_FOR_ERROR(GFX_PRINTER_NAME_NOT_FOUND); |
michael@0 | 1554 | ENTITY_FOR_ERROR(GFX_PRINTER_COULD_NOT_OPEN_FILE); |
michael@0 | 1555 | ENTITY_FOR_ERROR(GFX_PRINTER_STARTDOC); |
michael@0 | 1556 | ENTITY_FOR_ERROR(GFX_PRINTER_ENDDOC); |
michael@0 | 1557 | ENTITY_FOR_ERROR(GFX_PRINTER_STARTPAGE); |
michael@0 | 1558 | ENTITY_FOR_ERROR(GFX_PRINTER_DOC_IS_BUSY); |
michael@0 | 1559 | |
michael@0 | 1560 | ENTITY_FOR_ERROR(ABORT); |
michael@0 | 1561 | ENTITY_FOR_ERROR(NOT_AVAILABLE); |
michael@0 | 1562 | ENTITY_FOR_ERROR(NOT_IMPLEMENTED); |
michael@0 | 1563 | ENTITY_FOR_ERROR(OUT_OF_MEMORY); |
michael@0 | 1564 | ENTITY_FOR_ERROR(UNEXPECTED); |
michael@0 | 1565 | |
michael@0 | 1566 | default: |
michael@0 | 1567 | ENTITY_FOR_ERROR(FAILURE); |
michael@0 | 1568 | |
michael@0 | 1569 | #undef ENTITY_FOR_ERROR |
michael@0 | 1570 | } |
michael@0 | 1571 | |
michael@0 | 1572 | if (!aIsPrinting) { |
michael@0 | 1573 | // Try first with _PP suffix. |
michael@0 | 1574 | stringName.AppendLiteral("_PP"); |
michael@0 | 1575 | rv = nsContentUtils::GetLocalizedString( |
michael@0 | 1576 | nsContentUtils::ePRINTING_PROPERTIES, stringName.get(), msg); |
michael@0 | 1577 | if (NS_FAILED(rv)) { |
michael@0 | 1578 | stringName.Truncate(stringName.Length() - 3); |
michael@0 | 1579 | } |
michael@0 | 1580 | } |
michael@0 | 1581 | if (aIsPrinting || NS_FAILED(rv)) { |
michael@0 | 1582 | rv = nsContentUtils::GetLocalizedString( |
michael@0 | 1583 | nsContentUtils::ePRINTING_PROPERTIES, stringName.get(), msg); |
michael@0 | 1584 | } |
michael@0 | 1585 | if (NS_FAILED(rv)) { |
michael@0 | 1586 | return; |
michael@0 | 1587 | } |
michael@0 | 1588 | |
michael@0 | 1589 | rv = nsContentUtils::GetLocalizedString( |
michael@0 | 1590 | nsContentUtils::ePRINTING_PROPERTIES, |
michael@0 | 1591 | aIsPrinting ? "print_error_dialog_title" |
michael@0 | 1592 | : "printpreview_error_dialog_title", |
michael@0 | 1593 | title); |
michael@0 | 1594 | if (NS_FAILED(rv)) { |
michael@0 | 1595 | return; |
michael@0 | 1596 | } |
michael@0 | 1597 | |
michael@0 | 1598 | nsCOMPtr<nsIWindowWatcher> wwatch = |
michael@0 | 1599 | do_GetService(NS_WINDOWWATCHER_CONTRACTID, &rv); |
michael@0 | 1600 | if (NS_FAILED(rv)) { |
michael@0 | 1601 | return; |
michael@0 | 1602 | } |
michael@0 | 1603 | |
michael@0 | 1604 | nsCOMPtr<nsIDOMWindow> active; |
michael@0 | 1605 | wwatch->GetActiveWindow(getter_AddRefs(active)); |
michael@0 | 1606 | |
michael@0 | 1607 | nsCOMPtr<nsIPrompt> dialog; |
michael@0 | 1608 | /* |GetNewPrompter| allows that |active| is |nullptr| |
michael@0 | 1609 | * (see bug 234982 ("nsPrintEngine::ShowPrintErrorDialog() fails in many cases")) */ |
michael@0 | 1610 | wwatch->GetNewPrompter(active, getter_AddRefs(dialog)); |
michael@0 | 1611 | if (!dialog) { |
michael@0 | 1612 | return; |
michael@0 | 1613 | } |
michael@0 | 1614 | |
michael@0 | 1615 | dialog->Alert(title.get(), msg.get()); |
michael@0 | 1616 | } |
michael@0 | 1617 | |
michael@0 | 1618 | //----------------------------------------------------------------- |
michael@0 | 1619 | //-- Section: Reflow Methods |
michael@0 | 1620 | //----------------------------------------------------------------- |
michael@0 | 1621 | |
michael@0 | 1622 | nsresult |
michael@0 | 1623 | nsPrintEngine::ReconstructAndReflow(bool doSetPixelScale) |
michael@0 | 1624 | { |
michael@0 | 1625 | #if defined(XP_WIN) && defined(EXTENDED_DEBUG_PRINTING) |
michael@0 | 1626 | // We need to clear all the output files here |
michael@0 | 1627 | // because they will be re-created with second reflow of the docs |
michael@0 | 1628 | if (kPrintingLogMod && kPrintingLogMod->level == DUMP_LAYOUT_LEVEL) { |
michael@0 | 1629 | RemoveFilesInDir(".\\"); |
michael@0 | 1630 | gDumpFileNameCnt = 0; |
michael@0 | 1631 | gDumpLOFileNameCnt = 0; |
michael@0 | 1632 | } |
michael@0 | 1633 | #endif |
michael@0 | 1634 | |
michael@0 | 1635 | for (uint32_t i = 0; i < mPrt->mPrintDocList.Length(); ++i) { |
michael@0 | 1636 | nsPrintObject* po = mPrt->mPrintDocList.ElementAt(i); |
michael@0 | 1637 | NS_ASSERTION(po, "nsPrintObject can't be null!"); |
michael@0 | 1638 | |
michael@0 | 1639 | if (po->mDontPrint || po->mInvisible) { |
michael@0 | 1640 | continue; |
michael@0 | 1641 | } |
michael@0 | 1642 | |
michael@0 | 1643 | UpdateZoomRatio(po, doSetPixelScale); |
michael@0 | 1644 | |
michael@0 | 1645 | po->mPresContext->SetPageScale(po->mZoomRatio); |
michael@0 | 1646 | |
michael@0 | 1647 | // Calculate scale factor from printer to screen |
michael@0 | 1648 | float printDPI = float(mPrt->mPrintDC->AppUnitsPerCSSInch()) / |
michael@0 | 1649 | float(mPrt->mPrintDC->AppUnitsPerDevPixel()); |
michael@0 | 1650 | po->mPresContext->SetPrintPreviewScale(mScreenDPI / printDPI); |
michael@0 | 1651 | |
michael@0 | 1652 | po->mPresShell->ReconstructFrames(); |
michael@0 | 1653 | |
michael@0 | 1654 | // For all views except the first one, setup the root view. |
michael@0 | 1655 | // ??? Can there be multiple po for the top-level-document? |
michael@0 | 1656 | bool documentIsTopLevel = true; |
michael@0 | 1657 | if (i != 0) { |
michael@0 | 1658 | nsSize adjSize; |
michael@0 | 1659 | bool doReturn; |
michael@0 | 1660 | nsresult rv = SetRootView(po, doReturn, documentIsTopLevel, adjSize); |
michael@0 | 1661 | |
michael@0 | 1662 | MOZ_ASSERT(!documentIsTopLevel, "How could this happen?"); |
michael@0 | 1663 | |
michael@0 | 1664 | if (NS_FAILED(rv) || doReturn) { |
michael@0 | 1665 | return rv; |
michael@0 | 1666 | } |
michael@0 | 1667 | } |
michael@0 | 1668 | |
michael@0 | 1669 | po->mPresShell->FlushPendingNotifications(Flush_Layout); |
michael@0 | 1670 | |
michael@0 | 1671 | nsresult rv = UpdateSelectionAndShrinkPrintObject(po, documentIsTopLevel); |
michael@0 | 1672 | NS_ENSURE_SUCCESS(rv, rv); |
michael@0 | 1673 | } |
michael@0 | 1674 | return NS_OK; |
michael@0 | 1675 | } |
michael@0 | 1676 | |
michael@0 | 1677 | //------------------------------------------------------- |
michael@0 | 1678 | nsresult |
michael@0 | 1679 | nsPrintEngine::SetupToPrintContent() |
michael@0 | 1680 | { |
michael@0 | 1681 | nsresult rv; |
michael@0 | 1682 | |
michael@0 | 1683 | bool didReconstruction = false; |
michael@0 | 1684 | |
michael@0 | 1685 | // If some new content got loaded since the initial reflow rebuild |
michael@0 | 1686 | // everything. |
michael@0 | 1687 | if (mDidLoadDataForPrinting) { |
michael@0 | 1688 | rv = ReconstructAndReflow(DoSetPixelScale()); |
michael@0 | 1689 | didReconstruction = true; |
michael@0 | 1690 | NS_ENSURE_SUCCESS(rv, rv); |
michael@0 | 1691 | } |
michael@0 | 1692 | |
michael@0 | 1693 | // Here is where we figure out if extra reflow for shrinking the content |
michael@0 | 1694 | // is required. |
michael@0 | 1695 | // But skip this step if we are in PrintPreview |
michael@0 | 1696 | bool ppIsShrinkToFit = mPrtPreview && mPrtPreview->mShrinkToFit; |
michael@0 | 1697 | if (mPrt->mShrinkToFit && !ppIsShrinkToFit) { |
michael@0 | 1698 | // Now look for the PO that has the smallest percent for shrink to fit |
michael@0 | 1699 | if (mPrt->mPrintDocList.Length() > 1 && mPrt->mPrintObject->mFrameType == eFrameSet) { |
michael@0 | 1700 | nsPrintObject* smallestPO = FindSmallestSTF(); |
michael@0 | 1701 | NS_ASSERTION(smallestPO, "There must always be an XMost PO!"); |
michael@0 | 1702 | if (smallestPO) { |
michael@0 | 1703 | // Calc the shrinkage based on the entire content area |
michael@0 | 1704 | mPrt->mShrinkRatio = smallestPO->mShrinkRatio; |
michael@0 | 1705 | } |
michael@0 | 1706 | } else { |
michael@0 | 1707 | // Single document so use the Shrink as calculated for the PO |
michael@0 | 1708 | mPrt->mShrinkRatio = mPrt->mPrintObject->mShrinkRatio; |
michael@0 | 1709 | } |
michael@0 | 1710 | |
michael@0 | 1711 | if (mPrt->mShrinkRatio < 0.998f) { |
michael@0 | 1712 | rv = ReconstructAndReflow(true); |
michael@0 | 1713 | didReconstruction = true; |
michael@0 | 1714 | NS_ENSURE_SUCCESS(rv, rv); |
michael@0 | 1715 | } |
michael@0 | 1716 | |
michael@0 | 1717 | #ifdef PR_LOGGING |
michael@0 | 1718 | float calcRatio = 0.0f; |
michael@0 | 1719 | if (mPrt->mPrintDocList.Length() > 1 && mPrt->mPrintObject->mFrameType == eFrameSet) { |
michael@0 | 1720 | nsPrintObject* smallestPO = FindSmallestSTF(); |
michael@0 | 1721 | NS_ASSERTION(smallestPO, "There must always be an XMost PO!"); |
michael@0 | 1722 | if (smallestPO) { |
michael@0 | 1723 | // Calc the shrinkage based on the entire content area |
michael@0 | 1724 | calcRatio = smallestPO->mShrinkRatio; |
michael@0 | 1725 | } |
michael@0 | 1726 | } else { |
michael@0 | 1727 | // Single document so use the Shrink as calculated for the PO |
michael@0 | 1728 | calcRatio = mPrt->mPrintObject->mShrinkRatio; |
michael@0 | 1729 | } |
michael@0 | 1730 | PR_PL(("**************************************************************************\n")); |
michael@0 | 1731 | PR_PL(("STF Ratio is: %8.5f Effective Ratio: %8.5f Diff: %8.5f\n", mPrt->mShrinkRatio, calcRatio, mPrt->mShrinkRatio-calcRatio)); |
michael@0 | 1732 | PR_PL(("**************************************************************************\n")); |
michael@0 | 1733 | #endif |
michael@0 | 1734 | } |
michael@0 | 1735 | |
michael@0 | 1736 | // If the frames got reconstructed and reflowed the number of pages might |
michael@0 | 1737 | // has changed. |
michael@0 | 1738 | if (didReconstruction) { |
michael@0 | 1739 | FirePrintPreviewUpdateEvent(); |
michael@0 | 1740 | } |
michael@0 | 1741 | |
michael@0 | 1742 | DUMP_DOC_LIST(("\nAfter Reflow------------------------------------------")); |
michael@0 | 1743 | PR_PL(("\n")); |
michael@0 | 1744 | PR_PL(("-------------------------------------------------------\n")); |
michael@0 | 1745 | PR_PL(("\n")); |
michael@0 | 1746 | |
michael@0 | 1747 | CalcNumPrintablePages(mPrt->mNumPrintablePages); |
michael@0 | 1748 | |
michael@0 | 1749 | PR_PL(("--- Printing %d pages\n", mPrt->mNumPrintablePages)); |
michael@0 | 1750 | DUMP_DOC_TREELAYOUT; |
michael@0 | 1751 | |
michael@0 | 1752 | // Print listener setup... |
michael@0 | 1753 | if (mPrt != nullptr) { |
michael@0 | 1754 | mPrt->OnStartPrinting(); |
michael@0 | 1755 | } |
michael@0 | 1756 | |
michael@0 | 1757 | char16_t* fileName = nullptr; |
michael@0 | 1758 | // check to see if we are printing to a file |
michael@0 | 1759 | bool isPrintToFile = false; |
michael@0 | 1760 | mPrt->mPrintSettings->GetPrintToFile(&isPrintToFile); |
michael@0 | 1761 | if (isPrintToFile) { |
michael@0 | 1762 | // On some platforms The BeginDocument needs to know the name of the file |
michael@0 | 1763 | // and it uses the PrintService to get it, so we need to set it into the PrintService here |
michael@0 | 1764 | mPrt->mPrintSettings->GetToFileName(&fileName); |
michael@0 | 1765 | } |
michael@0 | 1766 | |
michael@0 | 1767 | nsAutoString docTitleStr; |
michael@0 | 1768 | nsAutoString docURLStr; |
michael@0 | 1769 | GetDisplayTitleAndURL(mPrt->mPrintObject, docTitleStr, docURLStr, eDocTitleDefURLDoc); |
michael@0 | 1770 | |
michael@0 | 1771 | int32_t startPage = 1; |
michael@0 | 1772 | int32_t endPage = mPrt->mNumPrintablePages; |
michael@0 | 1773 | |
michael@0 | 1774 | int16_t printRangeType = nsIPrintSettings::kRangeAllPages; |
michael@0 | 1775 | mPrt->mPrintSettings->GetPrintRange(&printRangeType); |
michael@0 | 1776 | if (printRangeType == nsIPrintSettings::kRangeSpecifiedPageRange) { |
michael@0 | 1777 | mPrt->mPrintSettings->GetStartPageRange(&startPage); |
michael@0 | 1778 | mPrt->mPrintSettings->GetEndPageRange(&endPage); |
michael@0 | 1779 | if (endPage > mPrt->mNumPrintablePages) { |
michael@0 | 1780 | endPage = mPrt->mNumPrintablePages; |
michael@0 | 1781 | } |
michael@0 | 1782 | } |
michael@0 | 1783 | |
michael@0 | 1784 | rv = NS_OK; |
michael@0 | 1785 | // BeginDocument may pass back a FAILURE code |
michael@0 | 1786 | // i.e. On Windows, if you are printing to a file and hit "Cancel" |
michael@0 | 1787 | // to the "File Name" dialog, this comes back as an error |
michael@0 | 1788 | // Don't start printing when regression test are executed |
michael@0 | 1789 | if (!mPrt->mDebugFilePtr && mIsDoingPrinting) { |
michael@0 | 1790 | rv = mPrt->mPrintDC->BeginDocument(docTitleStr, fileName, startPage, endPage); |
michael@0 | 1791 | } |
michael@0 | 1792 | |
michael@0 | 1793 | if (mIsCreatingPrintPreview) { |
michael@0 | 1794 | // Copy docTitleStr and docURLStr to the pageSequenceFrame, to be displayed |
michael@0 | 1795 | // in the header |
michael@0 | 1796 | nsIPageSequenceFrame *seqFrame = mPrt->mPrintObject->mPresShell->GetPageSequenceFrame(); |
michael@0 | 1797 | if (seqFrame) { |
michael@0 | 1798 | seqFrame->StartPrint(mPrt->mPrintObject->mPresContext, |
michael@0 | 1799 | mPrt->mPrintSettings, docTitleStr, docURLStr); |
michael@0 | 1800 | } |
michael@0 | 1801 | } |
michael@0 | 1802 | |
michael@0 | 1803 | PR_PL(("****************** Begin Document ************************\n")); |
michael@0 | 1804 | |
michael@0 | 1805 | NS_ENSURE_SUCCESS(rv, rv); |
michael@0 | 1806 | |
michael@0 | 1807 | // This will print the docshell document |
michael@0 | 1808 | // when it completes asynchronously in the DonePrintingPages method |
michael@0 | 1809 | // it will check to see if there are more docshells to be printed and |
michael@0 | 1810 | // then PrintDocContent will be called again. |
michael@0 | 1811 | |
michael@0 | 1812 | if (mIsDoingPrinting) { |
michael@0 | 1813 | PrintDocContent(mPrt->mPrintObject, rv); // ignore return value |
michael@0 | 1814 | } |
michael@0 | 1815 | |
michael@0 | 1816 | return rv; |
michael@0 | 1817 | } |
michael@0 | 1818 | |
michael@0 | 1819 | //------------------------------------------------------- |
michael@0 | 1820 | // Recursively reflow each sub-doc and then calc |
michael@0 | 1821 | // all the frame locations of the sub-docs |
michael@0 | 1822 | nsresult |
michael@0 | 1823 | nsPrintEngine::ReflowDocList(nsPrintObject* aPO, bool aSetPixelScale) |
michael@0 | 1824 | { |
michael@0 | 1825 | NS_ENSURE_ARG_POINTER(aPO); |
michael@0 | 1826 | |
michael@0 | 1827 | // Check to see if the subdocument's element has been hidden by the parent document |
michael@0 | 1828 | if (aPO->mParent && aPO->mParent->mPresShell) { |
michael@0 | 1829 | nsIFrame* frame = aPO->mContent ? aPO->mContent->GetPrimaryFrame() : nullptr; |
michael@0 | 1830 | if (!frame || !frame->StyleVisibility()->IsVisible()) { |
michael@0 | 1831 | SetPrintPO(aPO, false); |
michael@0 | 1832 | aPO->mInvisible = true; |
michael@0 | 1833 | return NS_OK; |
michael@0 | 1834 | } |
michael@0 | 1835 | } |
michael@0 | 1836 | |
michael@0 | 1837 | UpdateZoomRatio(aPO, aSetPixelScale); |
michael@0 | 1838 | |
michael@0 | 1839 | nsresult rv; |
michael@0 | 1840 | // Reflow the PO |
michael@0 | 1841 | rv = ReflowPrintObject(aPO); |
michael@0 | 1842 | NS_ENSURE_SUCCESS(rv, rv); |
michael@0 | 1843 | |
michael@0 | 1844 | int32_t cnt = aPO->mKids.Length(); |
michael@0 | 1845 | for (int32_t i=0;i<cnt;i++) { |
michael@0 | 1846 | rv = ReflowDocList(aPO->mKids[i], aSetPixelScale); |
michael@0 | 1847 | NS_ENSURE_SUCCESS(rv, rv); |
michael@0 | 1848 | } |
michael@0 | 1849 | return NS_OK; |
michael@0 | 1850 | } |
michael@0 | 1851 | |
michael@0 | 1852 | void |
michael@0 | 1853 | nsPrintEngine::FirePrintPreviewUpdateEvent() |
michael@0 | 1854 | { |
michael@0 | 1855 | // Dispatch the event only while in PrintPreview. When printing, there is no |
michael@0 | 1856 | // listener bound to this event and therefore no need to dispatch it. |
michael@0 | 1857 | if (mIsDoingPrintPreview && !mIsDoingPrinting) { |
michael@0 | 1858 | nsCOMPtr<nsIContentViewer> cv = do_QueryInterface(mDocViewerPrint); |
michael@0 | 1859 | (new AsyncEventDispatcher( |
michael@0 | 1860 | cv->GetDocument(), NS_LITERAL_STRING("printPreviewUpdate"), true, true) |
michael@0 | 1861 | )->RunDOMEventWhenSafe(); |
michael@0 | 1862 | } |
michael@0 | 1863 | } |
michael@0 | 1864 | |
michael@0 | 1865 | nsresult |
michael@0 | 1866 | nsPrintEngine::InitPrintDocConstruction(bool aHandleError) |
michael@0 | 1867 | { |
michael@0 | 1868 | nsresult rv; |
michael@0 | 1869 | rv = ReflowDocList(mPrt->mPrintObject, DoSetPixelScale()); |
michael@0 | 1870 | NS_ENSURE_SUCCESS(rv, rv); |
michael@0 | 1871 | |
michael@0 | 1872 | FirePrintPreviewUpdateEvent(); |
michael@0 | 1873 | |
michael@0 | 1874 | if (mLoadCounter == 0) { |
michael@0 | 1875 | AfterNetworkPrint(aHandleError); |
michael@0 | 1876 | } |
michael@0 | 1877 | return rv; |
michael@0 | 1878 | } |
michael@0 | 1879 | |
michael@0 | 1880 | nsresult |
michael@0 | 1881 | nsPrintEngine::AfterNetworkPrint(bool aHandleError) |
michael@0 | 1882 | { |
michael@0 | 1883 | nsCOMPtr<nsIWebProgress> webProgress = do_QueryInterface(mPrt->mPrintObject->mDocShell); |
michael@0 | 1884 | |
michael@0 | 1885 | webProgress->RemoveProgressListener( |
michael@0 | 1886 | static_cast<nsIWebProgressListener*>(this)); |
michael@0 | 1887 | |
michael@0 | 1888 | nsresult rv; |
michael@0 | 1889 | if (mIsDoingPrinting) { |
michael@0 | 1890 | rv = DocumentReadyForPrinting(); |
michael@0 | 1891 | } else { |
michael@0 | 1892 | rv = FinishPrintPreview(); |
michael@0 | 1893 | } |
michael@0 | 1894 | |
michael@0 | 1895 | /* cleaup on failure + notify user */ |
michael@0 | 1896 | if (aHandleError && NS_FAILED(rv)) { |
michael@0 | 1897 | CleanupOnFailure(rv, !mIsDoingPrinting); |
michael@0 | 1898 | } |
michael@0 | 1899 | |
michael@0 | 1900 | return rv; |
michael@0 | 1901 | } |
michael@0 | 1902 | |
michael@0 | 1903 | //////////////////////////////////////////////////////////////////////////////// |
michael@0 | 1904 | // nsIWebProgressListener |
michael@0 | 1905 | |
michael@0 | 1906 | NS_IMETHODIMP |
michael@0 | 1907 | nsPrintEngine::OnStateChange(nsIWebProgress* aWebProgress, |
michael@0 | 1908 | nsIRequest* aRequest, |
michael@0 | 1909 | uint32_t aStateFlags, |
michael@0 | 1910 | nsresult aStatus) |
michael@0 | 1911 | { |
michael@0 | 1912 | nsAutoCString name; |
michael@0 | 1913 | aRequest->GetName(name); |
michael@0 | 1914 | if (name.Equals("about:document-onload-blocker")) { |
michael@0 | 1915 | return NS_OK; |
michael@0 | 1916 | } |
michael@0 | 1917 | if (aStateFlags & STATE_START) { |
michael@0 | 1918 | nsCOMPtr<nsIChannel> channel = do_QueryInterface(aRequest); |
michael@0 | 1919 | |
michael@0 | 1920 | ++mLoadCounter; |
michael@0 | 1921 | } else if (aStateFlags & STATE_STOP) { |
michael@0 | 1922 | mDidLoadDataForPrinting = true; |
michael@0 | 1923 | --mLoadCounter; |
michael@0 | 1924 | |
michael@0 | 1925 | // If all resources are loaded, then do a small timeout and if there |
michael@0 | 1926 | // are still no new requests, then another reflow. |
michael@0 | 1927 | if (mLoadCounter == 0) { |
michael@0 | 1928 | AfterNetworkPrint(true); |
michael@0 | 1929 | } |
michael@0 | 1930 | } |
michael@0 | 1931 | return NS_OK; |
michael@0 | 1932 | } |
michael@0 | 1933 | |
michael@0 | 1934 | |
michael@0 | 1935 | |
michael@0 | 1936 | NS_IMETHODIMP |
michael@0 | 1937 | nsPrintEngine::OnProgressChange(nsIWebProgress* aWebProgress, |
michael@0 | 1938 | nsIRequest* aRequest, |
michael@0 | 1939 | int32_t aCurSelfProgress, |
michael@0 | 1940 | int32_t aMaxSelfProgress, |
michael@0 | 1941 | int32_t aCurTotalProgress, |
michael@0 | 1942 | int32_t aMaxTotalProgress) |
michael@0 | 1943 | { |
michael@0 | 1944 | NS_NOTREACHED("notification excluded in AddProgressListener(...)"); |
michael@0 | 1945 | return NS_OK; |
michael@0 | 1946 | } |
michael@0 | 1947 | |
michael@0 | 1948 | NS_IMETHODIMP |
michael@0 | 1949 | nsPrintEngine::OnLocationChange(nsIWebProgress* aWebProgress, |
michael@0 | 1950 | nsIRequest* aRequest, |
michael@0 | 1951 | nsIURI* aLocation, |
michael@0 | 1952 | uint32_t aFlags) |
michael@0 | 1953 | { |
michael@0 | 1954 | NS_NOTREACHED("notification excluded in AddProgressListener(...)"); |
michael@0 | 1955 | return NS_OK; |
michael@0 | 1956 | } |
michael@0 | 1957 | |
michael@0 | 1958 | NS_IMETHODIMP |
michael@0 | 1959 | nsPrintEngine::OnStatusChange(nsIWebProgress *aWebProgress, |
michael@0 | 1960 | nsIRequest *aRequest, |
michael@0 | 1961 | nsresult aStatus, |
michael@0 | 1962 | const char16_t *aMessage) |
michael@0 | 1963 | { |
michael@0 | 1964 | NS_NOTREACHED("notification excluded in AddProgressListener(...)"); |
michael@0 | 1965 | return NS_OK; |
michael@0 | 1966 | } |
michael@0 | 1967 | |
michael@0 | 1968 | NS_IMETHODIMP |
michael@0 | 1969 | nsPrintEngine::OnSecurityChange(nsIWebProgress *aWebProgress, |
michael@0 | 1970 | nsIRequest *aRequest, |
michael@0 | 1971 | uint32_t aState) |
michael@0 | 1972 | { |
michael@0 | 1973 | NS_NOTREACHED("notification excluded in AddProgressListener(...)"); |
michael@0 | 1974 | return NS_OK; |
michael@0 | 1975 | } |
michael@0 | 1976 | |
michael@0 | 1977 | //------------------------------------------------------- |
michael@0 | 1978 | |
michael@0 | 1979 | void |
michael@0 | 1980 | nsPrintEngine::UpdateZoomRatio(nsPrintObject* aPO, bool aSetPixelScale) |
michael@0 | 1981 | { |
michael@0 | 1982 | // Here is where we set the shrinkage value into the DC |
michael@0 | 1983 | // and this is what actually makes it shrink |
michael@0 | 1984 | if (aSetPixelScale && aPO->mFrameType != eIFrame) { |
michael@0 | 1985 | float ratio; |
michael@0 | 1986 | if (mPrt->mPrintFrameType == nsIPrintSettings::kFramesAsIs || mPrt->mPrintFrameType == nsIPrintSettings::kNoFrames) { |
michael@0 | 1987 | ratio = mPrt->mShrinkRatio - 0.005f; // round down |
michael@0 | 1988 | } else { |
michael@0 | 1989 | ratio = aPO->mShrinkRatio - 0.005f; // round down |
michael@0 | 1990 | } |
michael@0 | 1991 | aPO->mZoomRatio = ratio; |
michael@0 | 1992 | } else if (!mPrt->mShrinkToFit) { |
michael@0 | 1993 | double scaling; |
michael@0 | 1994 | mPrt->mPrintSettings->GetScaling(&scaling); |
michael@0 | 1995 | aPO->mZoomRatio = float(scaling); |
michael@0 | 1996 | } |
michael@0 | 1997 | } |
michael@0 | 1998 | |
michael@0 | 1999 | nsresult |
michael@0 | 2000 | nsPrintEngine::UpdateSelectionAndShrinkPrintObject(nsPrintObject* aPO, |
michael@0 | 2001 | bool aDocumentIsTopLevel) |
michael@0 | 2002 | { |
michael@0 | 2003 | nsCOMPtr<nsIPresShell> displayShell = aPO->mDocShell->GetPresShell(); |
michael@0 | 2004 | // Transfer Selection Ranges to the new Print PresShell |
michael@0 | 2005 | nsRefPtr<Selection> selection, selectionPS; |
michael@0 | 2006 | // It's okay if there is no display shell, just skip copying the selection |
michael@0 | 2007 | if (displayShell) { |
michael@0 | 2008 | selection = displayShell->GetCurrentSelection(nsISelectionController::SELECTION_NORMAL); |
michael@0 | 2009 | } |
michael@0 | 2010 | selectionPS = aPO->mPresShell->GetCurrentSelection(nsISelectionController::SELECTION_NORMAL); |
michael@0 | 2011 | |
michael@0 | 2012 | // Reset all existing selection ranges that might have been added by calling |
michael@0 | 2013 | // this function before. |
michael@0 | 2014 | if (selectionPS) { |
michael@0 | 2015 | selectionPS->RemoveAllRanges(); |
michael@0 | 2016 | } |
michael@0 | 2017 | if (selection && selectionPS) { |
michael@0 | 2018 | int32_t cnt = selection->GetRangeCount(); |
michael@0 | 2019 | int32_t inx; |
michael@0 | 2020 | for (inx = 0; inx < cnt; ++inx) { |
michael@0 | 2021 | selectionPS->AddRange(selection->GetRangeAt(inx)); |
michael@0 | 2022 | } |
michael@0 | 2023 | } |
michael@0 | 2024 | |
michael@0 | 2025 | // If we are trying to shrink the contents to fit on the page |
michael@0 | 2026 | // we must first locate the "pageContent" frame |
michael@0 | 2027 | // Then we walk the frame tree and look for the "xmost" frame |
michael@0 | 2028 | // this is the frame where the right-hand side of the frame extends |
michael@0 | 2029 | // the furthest |
michael@0 | 2030 | if (mPrt->mShrinkToFit && aDocumentIsTopLevel) { |
michael@0 | 2031 | nsIPageSequenceFrame* pageSequence = aPO->mPresShell->GetPageSequenceFrame(); |
michael@0 | 2032 | NS_ENSURE_STATE(pageSequence); |
michael@0 | 2033 | pageSequence->GetSTFPercent(aPO->mShrinkRatio); |
michael@0 | 2034 | // Limit the shrink-to-fit scaling for some text-ish type of documents. |
michael@0 | 2035 | nsAutoString contentType; |
michael@0 | 2036 | aPO->mPresShell->GetDocument()->GetContentType(contentType); |
michael@0 | 2037 | if (contentType.EqualsLiteral("application/xhtml+xml") || |
michael@0 | 2038 | StringBeginsWith(contentType, NS_LITERAL_STRING("text/"))) { |
michael@0 | 2039 | int32_t limitPercent = |
michael@0 | 2040 | Preferences::GetInt("print.shrink-to-fit.scale-limit-percent", 20); |
michael@0 | 2041 | limitPercent = std::max(0, limitPercent); |
michael@0 | 2042 | limitPercent = std::min(100, limitPercent); |
michael@0 | 2043 | float minShrinkRatio = float(limitPercent) / 100; |
michael@0 | 2044 | aPO->mShrinkRatio = std::max(aPO->mShrinkRatio, minShrinkRatio); |
michael@0 | 2045 | } |
michael@0 | 2046 | } |
michael@0 | 2047 | return NS_OK; |
michael@0 | 2048 | } |
michael@0 | 2049 | |
michael@0 | 2050 | bool |
michael@0 | 2051 | nsPrintEngine::DoSetPixelScale() |
michael@0 | 2052 | { |
michael@0 | 2053 | // This is an Optimization |
michael@0 | 2054 | // If we are in PP then we already know all the shrinkage information |
michael@0 | 2055 | // so just transfer it to the PrintData and we will skip the extra shrinkage reflow |
michael@0 | 2056 | // |
michael@0 | 2057 | // doSetPixelScale tells Reflow whether to set the shrinkage value into the DC |
michael@0 | 2058 | // The first time we do not want to do this, the second time through we do |
michael@0 | 2059 | bool doSetPixelScale = false; |
michael@0 | 2060 | bool ppIsShrinkToFit = mPrtPreview && mPrtPreview->mShrinkToFit; |
michael@0 | 2061 | if (ppIsShrinkToFit) { |
michael@0 | 2062 | mPrt->mShrinkRatio = mPrtPreview->mShrinkRatio; |
michael@0 | 2063 | doSetPixelScale = true; |
michael@0 | 2064 | } |
michael@0 | 2065 | return doSetPixelScale; |
michael@0 | 2066 | } |
michael@0 | 2067 | |
michael@0 | 2068 | nsView* |
michael@0 | 2069 | nsPrintEngine::GetParentViewForRoot() |
michael@0 | 2070 | { |
michael@0 | 2071 | if (mIsCreatingPrintPreview) { |
michael@0 | 2072 | nsCOMPtr<nsIContentViewer> cv = do_QueryInterface(mDocViewerPrint); |
michael@0 | 2073 | if (cv) { |
michael@0 | 2074 | return cv->FindContainerView(); |
michael@0 | 2075 | } |
michael@0 | 2076 | } |
michael@0 | 2077 | return nullptr; |
michael@0 | 2078 | } |
michael@0 | 2079 | |
michael@0 | 2080 | nsresult |
michael@0 | 2081 | nsPrintEngine::SetRootView( |
michael@0 | 2082 | nsPrintObject* aPO, |
michael@0 | 2083 | bool& doReturn, |
michael@0 | 2084 | bool& documentIsTopLevel, |
michael@0 | 2085 | nsSize& adjSize |
michael@0 | 2086 | ) |
michael@0 | 2087 | { |
michael@0 | 2088 | bool canCreateScrollbars = true; |
michael@0 | 2089 | |
michael@0 | 2090 | nsView* rootView; |
michael@0 | 2091 | nsView* parentView = nullptr; |
michael@0 | 2092 | |
michael@0 | 2093 | doReturn = false; |
michael@0 | 2094 | |
michael@0 | 2095 | if (aPO->mParent && aPO->mParent->IsPrintable()) { |
michael@0 | 2096 | nsIFrame* frame = aPO->mContent ? aPO->mContent->GetPrimaryFrame() : nullptr; |
michael@0 | 2097 | // Without a frame, this document can't be displayed; therefore, there is no |
michael@0 | 2098 | // point to reflowing it |
michael@0 | 2099 | if (!frame) { |
michael@0 | 2100 | SetPrintPO(aPO, false); |
michael@0 | 2101 | doReturn = true; |
michael@0 | 2102 | return NS_OK; |
michael@0 | 2103 | } |
michael@0 | 2104 | |
michael@0 | 2105 | //XXX If printing supported printing document hierarchies with non-constant |
michael@0 | 2106 | // zoom this would be wrong as we use the same mPrt->mPrintDC for all |
michael@0 | 2107 | // subdocuments. |
michael@0 | 2108 | adjSize = frame->GetContentRect().Size(); |
michael@0 | 2109 | documentIsTopLevel = false; |
michael@0 | 2110 | // presshell exists because parent is printable |
michael@0 | 2111 | |
michael@0 | 2112 | // the top nsPrintObject's widget will always have scrollbars |
michael@0 | 2113 | if (frame && frame->GetType() == nsGkAtoms::subDocumentFrame) { |
michael@0 | 2114 | nsView* view = frame->GetView(); |
michael@0 | 2115 | NS_ENSURE_TRUE(view, NS_ERROR_FAILURE); |
michael@0 | 2116 | view = view->GetFirstChild(); |
michael@0 | 2117 | NS_ENSURE_TRUE(view, NS_ERROR_FAILURE); |
michael@0 | 2118 | parentView = view; |
michael@0 | 2119 | canCreateScrollbars = false; |
michael@0 | 2120 | } |
michael@0 | 2121 | } else { |
michael@0 | 2122 | nscoord pageWidth, pageHeight; |
michael@0 | 2123 | mPrt->mPrintDC->GetDeviceSurfaceDimensions(pageWidth, pageHeight); |
michael@0 | 2124 | adjSize = nsSize(pageWidth, pageHeight); |
michael@0 | 2125 | documentIsTopLevel = true; |
michael@0 | 2126 | parentView = GetParentViewForRoot(); |
michael@0 | 2127 | } |
michael@0 | 2128 | |
michael@0 | 2129 | if (aPO->mViewManager->GetRootView()) { |
michael@0 | 2130 | // Reuse the root view that is already on the root frame. |
michael@0 | 2131 | rootView = aPO->mViewManager->GetRootView(); |
michael@0 | 2132 | // Remove it from its existing parent if necessary |
michael@0 | 2133 | aPO->mViewManager->RemoveChild(rootView); |
michael@0 | 2134 | rootView->SetParent(parentView); |
michael@0 | 2135 | } else { |
michael@0 | 2136 | // Create a child window of the parent that is our "root view/window" |
michael@0 | 2137 | nsRect tbounds = nsRect(nsPoint(0, 0), adjSize); |
michael@0 | 2138 | rootView = aPO->mViewManager->CreateView(tbounds, parentView); |
michael@0 | 2139 | NS_ENSURE_TRUE(rootView, NS_ERROR_OUT_OF_MEMORY); |
michael@0 | 2140 | } |
michael@0 | 2141 | |
michael@0 | 2142 | if (mIsCreatingPrintPreview && documentIsTopLevel) { |
michael@0 | 2143 | aPO->mPresContext->SetPaginatedScrolling(canCreateScrollbars); |
michael@0 | 2144 | } |
michael@0 | 2145 | |
michael@0 | 2146 | // Setup hierarchical relationship in view manager |
michael@0 | 2147 | aPO->mViewManager->SetRootView(rootView); |
michael@0 | 2148 | |
michael@0 | 2149 | return NS_OK; |
michael@0 | 2150 | } |
michael@0 | 2151 | |
michael@0 | 2152 | // Reflow a nsPrintObject |
michael@0 | 2153 | nsresult |
michael@0 | 2154 | nsPrintEngine::ReflowPrintObject(nsPrintObject * aPO) |
michael@0 | 2155 | { |
michael@0 | 2156 | NS_ENSURE_STATE(aPO); |
michael@0 | 2157 | |
michael@0 | 2158 | if (!aPO->IsPrintable()) { |
michael@0 | 2159 | return NS_OK; |
michael@0 | 2160 | } |
michael@0 | 2161 | |
michael@0 | 2162 | NS_ASSERTION(!aPO->mPresContext, "Recreating prescontext"); |
michael@0 | 2163 | |
michael@0 | 2164 | // create the PresContext |
michael@0 | 2165 | nsPresContext::nsPresContextType type = |
michael@0 | 2166 | mIsCreatingPrintPreview ? nsPresContext::eContext_PrintPreview: |
michael@0 | 2167 | nsPresContext::eContext_Print; |
michael@0 | 2168 | nsView* parentView = |
michael@0 | 2169 | aPO->mParent && aPO->mParent->IsPrintable() ? nullptr : GetParentViewForRoot(); |
michael@0 | 2170 | aPO->mPresContext = parentView ? |
michael@0 | 2171 | new nsPresContext(aPO->mDocument, type) : |
michael@0 | 2172 | new nsRootPresContext(aPO->mDocument, type); |
michael@0 | 2173 | NS_ENSURE_TRUE(aPO->mPresContext, NS_ERROR_OUT_OF_MEMORY); |
michael@0 | 2174 | aPO->mPresContext->SetPrintSettings(mPrt->mPrintSettings); |
michael@0 | 2175 | |
michael@0 | 2176 | // set the presentation context to the value in the print settings |
michael@0 | 2177 | bool printBGColors; |
michael@0 | 2178 | mPrt->mPrintSettings->GetPrintBGColors(&printBGColors); |
michael@0 | 2179 | aPO->mPresContext->SetBackgroundColorDraw(printBGColors); |
michael@0 | 2180 | mPrt->mPrintSettings->GetPrintBGImages(&printBGColors); |
michael@0 | 2181 | aPO->mPresContext->SetBackgroundImageDraw(printBGColors); |
michael@0 | 2182 | |
michael@0 | 2183 | // init it with the DC |
michael@0 | 2184 | nsresult rv = aPO->mPresContext->Init(mPrt->mPrintDC); |
michael@0 | 2185 | NS_ENSURE_SUCCESS(rv, rv); |
michael@0 | 2186 | |
michael@0 | 2187 | aPO->mViewManager = new nsViewManager(); |
michael@0 | 2188 | |
michael@0 | 2189 | rv = aPO->mViewManager->Init(mPrt->mPrintDC); |
michael@0 | 2190 | NS_ENSURE_SUCCESS(rv,rv); |
michael@0 | 2191 | |
michael@0 | 2192 | nsStyleSet* styleSet; |
michael@0 | 2193 | rv = mDocViewerPrint->CreateStyleSet(aPO->mDocument, &styleSet); |
michael@0 | 2194 | NS_ENSURE_SUCCESS(rv, rv); |
michael@0 | 2195 | |
michael@0 | 2196 | aPO->mPresShell = aPO->mDocument->CreateShell(aPO->mPresContext, |
michael@0 | 2197 | aPO->mViewManager, styleSet); |
michael@0 | 2198 | if (!aPO->mPresShell) { |
michael@0 | 2199 | delete styleSet; |
michael@0 | 2200 | return NS_ERROR_FAILURE; |
michael@0 | 2201 | } |
michael@0 | 2202 | |
michael@0 | 2203 | styleSet->EndUpdate(); |
michael@0 | 2204 | |
michael@0 | 2205 | // The pres shell now owns the style set object. |
michael@0 | 2206 | |
michael@0 | 2207 | |
michael@0 | 2208 | bool doReturn = false;; |
michael@0 | 2209 | bool documentIsTopLevel = false; |
michael@0 | 2210 | nsSize adjSize; |
michael@0 | 2211 | |
michael@0 | 2212 | rv = SetRootView(aPO, doReturn, documentIsTopLevel, adjSize); |
michael@0 | 2213 | |
michael@0 | 2214 | if (NS_FAILED(rv) || doReturn) { |
michael@0 | 2215 | return rv; |
michael@0 | 2216 | } |
michael@0 | 2217 | |
michael@0 | 2218 | PR_PL(("In DV::ReflowPrintObject PO: %p pS: %p (%9s) Setting w,h to %d,%d\n", aPO, aPO->mPresShell.get(), |
michael@0 | 2219 | gFrameTypesStr[aPO->mFrameType], adjSize.width, adjSize.height)); |
michael@0 | 2220 | |
michael@0 | 2221 | |
michael@0 | 2222 | // This docshell stuff is weird; will go away when we stop having multiple |
michael@0 | 2223 | // presentations per document |
michael@0 | 2224 | aPO->mPresContext->SetContainer(aPO->mDocShell); |
michael@0 | 2225 | |
michael@0 | 2226 | aPO->mPresShell->BeginObservingDocument(); |
michael@0 | 2227 | |
michael@0 | 2228 | aPO->mPresContext->SetPageSize(adjSize); |
michael@0 | 2229 | aPO->mPresContext->SetIsRootPaginatedDocument(documentIsTopLevel); |
michael@0 | 2230 | aPO->mPresContext->SetPageScale(aPO->mZoomRatio); |
michael@0 | 2231 | // Calculate scale factor from printer to screen |
michael@0 | 2232 | float printDPI = float(mPrt->mPrintDC->AppUnitsPerCSSInch()) / |
michael@0 | 2233 | float(mPrt->mPrintDC->AppUnitsPerDevPixel()); |
michael@0 | 2234 | aPO->mPresContext->SetPrintPreviewScale(mScreenDPI / printDPI); |
michael@0 | 2235 | |
michael@0 | 2236 | if (mIsCreatingPrintPreview && documentIsTopLevel) { |
michael@0 | 2237 | mDocViewerPrint->SetPrintPreviewPresentation(aPO->mViewManager, |
michael@0 | 2238 | aPO->mPresContext, |
michael@0 | 2239 | aPO->mPresShell); |
michael@0 | 2240 | } |
michael@0 | 2241 | |
michael@0 | 2242 | rv = aPO->mPresShell->Initialize(adjSize.width, adjSize.height); |
michael@0 | 2243 | |
michael@0 | 2244 | NS_ENSURE_SUCCESS(rv, rv); |
michael@0 | 2245 | NS_ASSERTION(aPO->mPresShell, "Presshell should still be here"); |
michael@0 | 2246 | |
michael@0 | 2247 | // Process the reflow event Initialize posted |
michael@0 | 2248 | aPO->mPresShell->FlushPendingNotifications(Flush_Layout); |
michael@0 | 2249 | |
michael@0 | 2250 | rv = UpdateSelectionAndShrinkPrintObject(aPO, documentIsTopLevel); |
michael@0 | 2251 | NS_ENSURE_SUCCESS(rv, rv); |
michael@0 | 2252 | |
michael@0 | 2253 | #ifdef EXTENDED_DEBUG_PRINTING |
michael@0 | 2254 | if (kPrintingLogMod && kPrintingLogMod->level == DUMP_LAYOUT_LEVEL) { |
michael@0 | 2255 | nsAutoCString docStr; |
michael@0 | 2256 | nsAutoCString urlStr; |
michael@0 | 2257 | GetDocTitleAndURL(aPO, docStr, urlStr); |
michael@0 | 2258 | char filename[256]; |
michael@0 | 2259 | sprintf(filename, "print_dump_%d.txt", gDumpFileNameCnt++); |
michael@0 | 2260 | // Dump all the frames and view to a a file |
michael@0 | 2261 | FILE * fd = fopen(filename, "w"); |
michael@0 | 2262 | if (fd) { |
michael@0 | 2263 | nsIFrame *theRootFrame = |
michael@0 | 2264 | aPO->mPresShell->FrameManager()->GetRootFrame(); |
michael@0 | 2265 | fprintf(fd, "Title: %s\n", docStr.get()); |
michael@0 | 2266 | fprintf(fd, "URL: %s\n", urlStr.get()); |
michael@0 | 2267 | fprintf(fd, "--------------- Frames ----------------\n"); |
michael@0 | 2268 | nsRefPtr<nsRenderingContext> renderingContext = |
michael@0 | 2269 | mPrt->mPrintDocDC->CreateRenderingContext(); |
michael@0 | 2270 | RootFrameList(aPO->mPresContext, fd, 0); |
michael@0 | 2271 | //DumpFrames(fd, aPO->mPresContext, renderingContext, theRootFrame, 0); |
michael@0 | 2272 | fprintf(fd, "---------------------------------------\n\n"); |
michael@0 | 2273 | fprintf(fd, "--------------- Views From Root Frame----------------\n"); |
michael@0 | 2274 | nsView* v = theRootFrame->GetView(); |
michael@0 | 2275 | if (v) { |
michael@0 | 2276 | v->List(fd); |
michael@0 | 2277 | } else { |
michael@0 | 2278 | printf("View is null!\n"); |
michael@0 | 2279 | } |
michael@0 | 2280 | if (docShell) { |
michael@0 | 2281 | fprintf(fd, "--------------- All Views ----------------\n"); |
michael@0 | 2282 | DumpViews(docShell, fd); |
michael@0 | 2283 | fprintf(fd, "---------------------------------------\n\n"); |
michael@0 | 2284 | } |
michael@0 | 2285 | fclose(fd); |
michael@0 | 2286 | } |
michael@0 | 2287 | } |
michael@0 | 2288 | #endif |
michael@0 | 2289 | |
michael@0 | 2290 | return NS_OK; |
michael@0 | 2291 | } |
michael@0 | 2292 | |
michael@0 | 2293 | //------------------------------------------------------- |
michael@0 | 2294 | // Figure out how many documents and how many total pages we are printing |
michael@0 | 2295 | void |
michael@0 | 2296 | nsPrintEngine::CalcNumPrintablePages(int32_t& aNumPages) |
michael@0 | 2297 | { |
michael@0 | 2298 | aNumPages = 0; |
michael@0 | 2299 | // Count the number of printable documents |
michael@0 | 2300 | // and printable pages |
michael@0 | 2301 | for (uint32_t i=0; i<mPrt->mPrintDocList.Length(); i++) { |
michael@0 | 2302 | nsPrintObject* po = mPrt->mPrintDocList.ElementAt(i); |
michael@0 | 2303 | NS_ASSERTION(po, "nsPrintObject can't be null!"); |
michael@0 | 2304 | if (po->mPresContext && po->mPresContext->IsRootPaginatedDocument()) { |
michael@0 | 2305 | nsIPageSequenceFrame* pageSequence = po->mPresShell->GetPageSequenceFrame(); |
michael@0 | 2306 | nsIFrame * seqFrame = do_QueryFrame(pageSequence); |
michael@0 | 2307 | if (seqFrame) { |
michael@0 | 2308 | nsIFrame* frame = seqFrame->GetFirstPrincipalChild(); |
michael@0 | 2309 | while (frame) { |
michael@0 | 2310 | aNumPages++; |
michael@0 | 2311 | frame = frame->GetNextSibling(); |
michael@0 | 2312 | } |
michael@0 | 2313 | } |
michael@0 | 2314 | } |
michael@0 | 2315 | } |
michael@0 | 2316 | } |
michael@0 | 2317 | |
michael@0 | 2318 | //----------------------------------------------------------------- |
michael@0 | 2319 | //-- Done: Reflow Methods |
michael@0 | 2320 | //----------------------------------------------------------------- |
michael@0 | 2321 | |
michael@0 | 2322 | //----------------------------------------------------------------- |
michael@0 | 2323 | //-- Section: Printing Methods |
michael@0 | 2324 | //----------------------------------------------------------------- |
michael@0 | 2325 | |
michael@0 | 2326 | //------------------------------------------------------- |
michael@0 | 2327 | // Called for each DocShell that needs to be printed |
michael@0 | 2328 | bool |
michael@0 | 2329 | nsPrintEngine::PrintDocContent(nsPrintObject* aPO, nsresult& aStatus) |
michael@0 | 2330 | { |
michael@0 | 2331 | NS_ASSERTION(aPO, "Pointer is null!"); |
michael@0 | 2332 | aStatus = NS_OK; |
michael@0 | 2333 | |
michael@0 | 2334 | if (!aPO->mHasBeenPrinted && aPO->IsPrintable()) { |
michael@0 | 2335 | aStatus = DoPrint(aPO); |
michael@0 | 2336 | return true; |
michael@0 | 2337 | } |
michael@0 | 2338 | |
michael@0 | 2339 | // If |aPO->mPrintAsIs| and |aPO->mHasBeenPrinted| are true, |
michael@0 | 2340 | // the kids frames are already processed in |PrintPage|. |
michael@0 | 2341 | if (!aPO->mInvisible && !(aPO->mPrintAsIs && aPO->mHasBeenPrinted)) { |
michael@0 | 2342 | for (uint32_t i=0;i<aPO->mKids.Length();i++) { |
michael@0 | 2343 | nsPrintObject* po = aPO->mKids[i]; |
michael@0 | 2344 | bool printed = PrintDocContent(po, aStatus); |
michael@0 | 2345 | if (printed || NS_FAILED(aStatus)) { |
michael@0 | 2346 | return true; |
michael@0 | 2347 | } |
michael@0 | 2348 | } |
michael@0 | 2349 | } |
michael@0 | 2350 | return false; |
michael@0 | 2351 | } |
michael@0 | 2352 | |
michael@0 | 2353 | static already_AddRefed<nsIDOMNode> |
michael@0 | 2354 | GetEqualNodeInCloneTree(nsIDOMNode* aNode, nsIDocument* aDoc) |
michael@0 | 2355 | { |
michael@0 | 2356 | nsCOMPtr<nsIContent> content = do_QueryInterface(aNode); |
michael@0 | 2357 | // Selections in anonymous subtrees aren't supported. |
michael@0 | 2358 | if (content && content->IsInAnonymousSubtree()) { |
michael@0 | 2359 | return nullptr; |
michael@0 | 2360 | } |
michael@0 | 2361 | |
michael@0 | 2362 | nsCOMPtr<nsINode> node = do_QueryInterface(aNode); |
michael@0 | 2363 | NS_ENSURE_TRUE(node, nullptr); |
michael@0 | 2364 | |
michael@0 | 2365 | nsTArray<int32_t> indexArray; |
michael@0 | 2366 | nsINode* current = node; |
michael@0 | 2367 | NS_ENSURE_TRUE(current, nullptr); |
michael@0 | 2368 | while (current) { |
michael@0 | 2369 | nsINode* parent = current->GetParentNode(); |
michael@0 | 2370 | if (!parent) { |
michael@0 | 2371 | break; |
michael@0 | 2372 | } |
michael@0 | 2373 | int32_t index = parent->IndexOf(current); |
michael@0 | 2374 | NS_ENSURE_TRUE(index >= 0, nullptr); |
michael@0 | 2375 | indexArray.AppendElement(index); |
michael@0 | 2376 | current = parent; |
michael@0 | 2377 | } |
michael@0 | 2378 | NS_ENSURE_TRUE(current->IsNodeOfType(nsINode::eDOCUMENT), nullptr); |
michael@0 | 2379 | |
michael@0 | 2380 | current = aDoc; |
michael@0 | 2381 | for (int32_t i = indexArray.Length() - 1; i >= 0; --i) { |
michael@0 | 2382 | current = current->GetChildAt(indexArray[i]); |
michael@0 | 2383 | NS_ENSURE_TRUE(current, nullptr); |
michael@0 | 2384 | } |
michael@0 | 2385 | nsCOMPtr<nsIDOMNode> result = do_QueryInterface(current); |
michael@0 | 2386 | return result.forget(); |
michael@0 | 2387 | } |
michael@0 | 2388 | |
michael@0 | 2389 | static void |
michael@0 | 2390 | CloneRangeToSelection(nsRange* aRange, nsIDocument* aDoc, |
michael@0 | 2391 | Selection* aSelection) |
michael@0 | 2392 | { |
michael@0 | 2393 | if (aRange->Collapsed()) { |
michael@0 | 2394 | return; |
michael@0 | 2395 | } |
michael@0 | 2396 | |
michael@0 | 2397 | nsCOMPtr<nsIDOMNode> startContainer, endContainer; |
michael@0 | 2398 | aRange->GetStartContainer(getter_AddRefs(startContainer)); |
michael@0 | 2399 | int32_t startOffset = aRange->StartOffset(); |
michael@0 | 2400 | aRange->GetEndContainer(getter_AddRefs(endContainer)); |
michael@0 | 2401 | int32_t endOffset = aRange->EndOffset(); |
michael@0 | 2402 | NS_ENSURE_TRUE_VOID(startContainer && endContainer); |
michael@0 | 2403 | |
michael@0 | 2404 | nsCOMPtr<nsIDOMNode> newStart = GetEqualNodeInCloneTree(startContainer, aDoc); |
michael@0 | 2405 | nsCOMPtr<nsIDOMNode> newEnd = GetEqualNodeInCloneTree(endContainer, aDoc); |
michael@0 | 2406 | NS_ENSURE_TRUE_VOID(newStart && newEnd); |
michael@0 | 2407 | |
michael@0 | 2408 | nsCOMPtr<nsINode> newStartNode = do_QueryInterface(newStart); |
michael@0 | 2409 | NS_ENSURE_TRUE_VOID(newStartNode); |
michael@0 | 2410 | |
michael@0 | 2411 | nsRefPtr<nsRange> range = new nsRange(newStartNode); |
michael@0 | 2412 | nsresult rv = range->SetStart(newStartNode, startOffset); |
michael@0 | 2413 | NS_ENSURE_SUCCESS_VOID(rv); |
michael@0 | 2414 | rv = range->SetEnd(newEnd, endOffset); |
michael@0 | 2415 | NS_ENSURE_SUCCESS_VOID(rv); |
michael@0 | 2416 | |
michael@0 | 2417 | aSelection->AddRange(range); |
michael@0 | 2418 | } |
michael@0 | 2419 | |
michael@0 | 2420 | static nsresult CloneSelection(nsIDocument* aOrigDoc, nsIDocument* aDoc) |
michael@0 | 2421 | { |
michael@0 | 2422 | nsIPresShell* origShell = aOrigDoc->GetShell(); |
michael@0 | 2423 | nsIPresShell* shell = aDoc->GetShell(); |
michael@0 | 2424 | NS_ENSURE_STATE(origShell && shell); |
michael@0 | 2425 | |
michael@0 | 2426 | nsRefPtr<Selection> origSelection = |
michael@0 | 2427 | origShell->GetCurrentSelection(nsISelectionController::SELECTION_NORMAL); |
michael@0 | 2428 | nsRefPtr<Selection> selection = |
michael@0 | 2429 | shell->GetCurrentSelection(nsISelectionController::SELECTION_NORMAL); |
michael@0 | 2430 | NS_ENSURE_STATE(origSelection && selection); |
michael@0 | 2431 | |
michael@0 | 2432 | int32_t rangeCount = origSelection->GetRangeCount(); |
michael@0 | 2433 | for (int32_t i = 0; i < rangeCount; ++i) { |
michael@0 | 2434 | CloneRangeToSelection(origSelection->GetRangeAt(i), aDoc, selection); |
michael@0 | 2435 | } |
michael@0 | 2436 | return NS_OK; |
michael@0 | 2437 | } |
michael@0 | 2438 | |
michael@0 | 2439 | //------------------------------------------------------- |
michael@0 | 2440 | nsresult |
michael@0 | 2441 | nsPrintEngine::DoPrint(nsPrintObject * aPO) |
michael@0 | 2442 | { |
michael@0 | 2443 | PR_PL(("\n")); |
michael@0 | 2444 | PR_PL(("**************************** %s ****************************\n", gFrameTypesStr[aPO->mFrameType])); |
michael@0 | 2445 | PR_PL(("****** In DV::DoPrint PO: %p \n", aPO)); |
michael@0 | 2446 | |
michael@0 | 2447 | nsIPresShell* poPresShell = aPO->mPresShell; |
michael@0 | 2448 | nsPresContext* poPresContext = aPO->mPresContext; |
michael@0 | 2449 | |
michael@0 | 2450 | NS_ASSERTION(poPresContext, "PrintObject has not been reflowed"); |
michael@0 | 2451 | NS_ASSERTION(poPresContext->Type() != nsPresContext::eContext_PrintPreview, |
michael@0 | 2452 | "How did this context end up here?"); |
michael@0 | 2453 | |
michael@0 | 2454 | if (mPrt->mPrintProgressParams) { |
michael@0 | 2455 | SetDocAndURLIntoProgress(aPO, mPrt->mPrintProgressParams); |
michael@0 | 2456 | } |
michael@0 | 2457 | |
michael@0 | 2458 | { |
michael@0 | 2459 | int16_t printRangeType = nsIPrintSettings::kRangeAllPages; |
michael@0 | 2460 | nsresult rv; |
michael@0 | 2461 | if (mPrt->mPrintSettings != nullptr) { |
michael@0 | 2462 | mPrt->mPrintSettings->GetPrintRange(&printRangeType); |
michael@0 | 2463 | } |
michael@0 | 2464 | |
michael@0 | 2465 | // Ask the page sequence frame to print all the pages |
michael@0 | 2466 | nsIPageSequenceFrame* pageSequence = poPresShell->GetPageSequenceFrame(); |
michael@0 | 2467 | NS_ASSERTION(nullptr != pageSequence, "no page sequence frame"); |
michael@0 | 2468 | |
michael@0 | 2469 | // We are done preparing for printing, so we can turn this off |
michael@0 | 2470 | mPrt->mPreparingForPrint = false; |
michael@0 | 2471 | |
michael@0 | 2472 | // mPrt->mDebugFilePtr this is onlu non-null when compiled for debugging |
michael@0 | 2473 | if (nullptr != mPrt->mDebugFilePtr) { |
michael@0 | 2474 | #ifdef DEBUG |
michael@0 | 2475 | // output the regression test |
michael@0 | 2476 | nsIFrame* root = poPresShell->FrameManager()->GetRootFrame(); |
michael@0 | 2477 | root->DumpRegressionData(poPresContext, mPrt->mDebugFilePtr, 0); |
michael@0 | 2478 | fclose(mPrt->mDebugFilePtr); |
michael@0 | 2479 | SetIsPrinting(false); |
michael@0 | 2480 | #endif |
michael@0 | 2481 | } else { |
michael@0 | 2482 | #ifdef EXTENDED_DEBUG_PRINTING |
michael@0 | 2483 | nsIFrame* rootFrame = poPresShell->FrameManager()->GetRootFrame(); |
michael@0 | 2484 | if (aPO->IsPrintable()) { |
michael@0 | 2485 | nsAutoCString docStr; |
michael@0 | 2486 | nsAutoCString urlStr; |
michael@0 | 2487 | GetDocTitleAndURL(aPO, docStr, urlStr); |
michael@0 | 2488 | DumpLayoutData(docStr.get(), urlStr.get(), poPresContext, mPrt->mPrintDocDC, rootFrame, docShell, nullptr); |
michael@0 | 2489 | } |
michael@0 | 2490 | #endif |
michael@0 | 2491 | |
michael@0 | 2492 | if (!mPrt->mPrintSettings) { |
michael@0 | 2493 | // not sure what to do here! |
michael@0 | 2494 | SetIsPrinting(false); |
michael@0 | 2495 | return NS_ERROR_FAILURE; |
michael@0 | 2496 | } |
michael@0 | 2497 | |
michael@0 | 2498 | nsAutoString docTitleStr; |
michael@0 | 2499 | nsAutoString docURLStr; |
michael@0 | 2500 | GetDisplayTitleAndURL(aPO, docTitleStr, docURLStr, eDocTitleDefBlank); |
michael@0 | 2501 | |
michael@0 | 2502 | if (nsIPrintSettings::kRangeSelection == printRangeType) { |
michael@0 | 2503 | CloneSelection(aPO->mDocument->GetOriginalDocument(), aPO->mDocument); |
michael@0 | 2504 | |
michael@0 | 2505 | poPresContext->SetIsRenderingOnlySelection(true); |
michael@0 | 2506 | // temporarily creating rendering context |
michael@0 | 2507 | // which is needed to find the selection frames |
michael@0 | 2508 | nsRefPtr<nsRenderingContext> rc = |
michael@0 | 2509 | mPrt->mPrintDC->CreateRenderingContext(); |
michael@0 | 2510 | |
michael@0 | 2511 | // find the starting and ending page numbers |
michael@0 | 2512 | // via the selection |
michael@0 | 2513 | nsIFrame* startFrame; |
michael@0 | 2514 | nsIFrame* endFrame; |
michael@0 | 2515 | int32_t startPageNum; |
michael@0 | 2516 | int32_t endPageNum; |
michael@0 | 2517 | nsRect startRect; |
michael@0 | 2518 | nsRect endRect; |
michael@0 | 2519 | |
michael@0 | 2520 | nsRefPtr<Selection> selectionPS = |
michael@0 | 2521 | poPresShell->GetCurrentSelection(nsISelectionController::SELECTION_NORMAL); |
michael@0 | 2522 | |
michael@0 | 2523 | rv = GetPageRangeForSelection(poPresShell, poPresContext, *rc, selectionPS, pageSequence, |
michael@0 | 2524 | &startFrame, startPageNum, startRect, |
michael@0 | 2525 | &endFrame, endPageNum, endRect); |
michael@0 | 2526 | if (NS_SUCCEEDED(rv)) { |
michael@0 | 2527 | mPrt->mPrintSettings->SetStartPageRange(startPageNum); |
michael@0 | 2528 | mPrt->mPrintSettings->SetEndPageRange(endPageNum); |
michael@0 | 2529 | nsIntMargin marginTwips(0,0,0,0); |
michael@0 | 2530 | nsIntMargin unwrtMarginTwips(0,0,0,0); |
michael@0 | 2531 | mPrt->mPrintSettings->GetMarginInTwips(marginTwips); |
michael@0 | 2532 | mPrt->mPrintSettings->GetUnwriteableMarginInTwips(unwrtMarginTwips); |
michael@0 | 2533 | nsMargin totalMargin = poPresContext->CSSTwipsToAppUnits(marginTwips + |
michael@0 | 2534 | unwrtMarginTwips); |
michael@0 | 2535 | if (startPageNum == endPageNum) { |
michael@0 | 2536 | startRect.y -= totalMargin.top; |
michael@0 | 2537 | endRect.y -= totalMargin.top; |
michael@0 | 2538 | |
michael@0 | 2539 | // Clip out selection regions above the top of the first page |
michael@0 | 2540 | if (startRect.y < 0) { |
michael@0 | 2541 | // Reduce height to be the height of the positive-territory |
michael@0 | 2542 | // region of original rect |
michael@0 | 2543 | startRect.height = std::max(0, startRect.YMost()); |
michael@0 | 2544 | startRect.y = 0; |
michael@0 | 2545 | } |
michael@0 | 2546 | if (endRect.y < 0) { |
michael@0 | 2547 | // Reduce height to be the height of the positive-territory |
michael@0 | 2548 | // region of original rect |
michael@0 | 2549 | endRect.height = std::max(0, endRect.YMost()); |
michael@0 | 2550 | endRect.y = 0; |
michael@0 | 2551 | } |
michael@0 | 2552 | NS_ASSERTION(endRect.y >= startRect.y, |
michael@0 | 2553 | "Selection end point should be after start point"); |
michael@0 | 2554 | NS_ASSERTION(startRect.height >= 0, |
michael@0 | 2555 | "rect should have non-negative height."); |
michael@0 | 2556 | NS_ASSERTION(endRect.height >= 0, |
michael@0 | 2557 | "rect should have non-negative height."); |
michael@0 | 2558 | |
michael@0 | 2559 | nscoord selectionHgt = endRect.y + endRect.height - startRect.y; |
michael@0 | 2560 | // XXX This is temporary fix for printing more than one page of a selection |
michael@0 | 2561 | pageSequence->SetSelectionHeight(startRect.y * aPO->mZoomRatio, |
michael@0 | 2562 | selectionHgt * aPO->mZoomRatio); |
michael@0 | 2563 | |
michael@0 | 2564 | // calc total pages by getting calculating the selection's height |
michael@0 | 2565 | // and then dividing it by how page content frames will fit. |
michael@0 | 2566 | nscoord pageWidth, pageHeight; |
michael@0 | 2567 | mPrt->mPrintDC->GetDeviceSurfaceDimensions(pageWidth, pageHeight); |
michael@0 | 2568 | pageHeight -= totalMargin.top + totalMargin.bottom; |
michael@0 | 2569 | int32_t totalPages = NSToIntCeil(float(selectionHgt) * aPO->mZoomRatio / float(pageHeight)); |
michael@0 | 2570 | pageSequence->SetTotalNumPages(totalPages); |
michael@0 | 2571 | } |
michael@0 | 2572 | } |
michael@0 | 2573 | } |
michael@0 | 2574 | |
michael@0 | 2575 | nsIFrame * seqFrame = do_QueryFrame(pageSequence); |
michael@0 | 2576 | if (!seqFrame) { |
michael@0 | 2577 | SetIsPrinting(false); |
michael@0 | 2578 | return NS_ERROR_FAILURE; |
michael@0 | 2579 | } |
michael@0 | 2580 | |
michael@0 | 2581 | mPageSeqFrame = pageSequence; |
michael@0 | 2582 | mPageSeqFrame->StartPrint(poPresContext, mPrt->mPrintSettings, docTitleStr, docURLStr); |
michael@0 | 2583 | |
michael@0 | 2584 | // Schedule Page to Print |
michael@0 | 2585 | PR_PL(("Scheduling Print of PO: %p (%s) \n", aPO, gFrameTypesStr[aPO->mFrameType])); |
michael@0 | 2586 | StartPagePrintTimer(aPO); |
michael@0 | 2587 | } |
michael@0 | 2588 | } |
michael@0 | 2589 | |
michael@0 | 2590 | return NS_OK; |
michael@0 | 2591 | } |
michael@0 | 2592 | |
michael@0 | 2593 | //--------------------------------------------------------------------- |
michael@0 | 2594 | void |
michael@0 | 2595 | nsPrintEngine::SetDocAndURLIntoProgress(nsPrintObject* aPO, |
michael@0 | 2596 | nsIPrintProgressParams* aParams) |
michael@0 | 2597 | { |
michael@0 | 2598 | NS_ASSERTION(aPO, "Must have valid nsPrintObject"); |
michael@0 | 2599 | NS_ASSERTION(aParams, "Must have valid nsIPrintProgressParams"); |
michael@0 | 2600 | |
michael@0 | 2601 | if (!aPO || !aPO->mDocShell || !aParams) { |
michael@0 | 2602 | return; |
michael@0 | 2603 | } |
michael@0 | 2604 | const uint32_t kTitleLength = 64; |
michael@0 | 2605 | |
michael@0 | 2606 | nsAutoString docTitleStr; |
michael@0 | 2607 | nsAutoString docURLStr; |
michael@0 | 2608 | GetDisplayTitleAndURL(aPO, docTitleStr, docURLStr, eDocTitleDefURLDoc); |
michael@0 | 2609 | |
michael@0 | 2610 | // Make sure the Titles & URLS don't get too long for the progress dialog |
michael@0 | 2611 | EllipseLongString(docTitleStr, kTitleLength, false); |
michael@0 | 2612 | EllipseLongString(docURLStr, kTitleLength, true); |
michael@0 | 2613 | |
michael@0 | 2614 | aParams->SetDocTitle(docTitleStr.get()); |
michael@0 | 2615 | aParams->SetDocURL(docURLStr.get()); |
michael@0 | 2616 | } |
michael@0 | 2617 | |
michael@0 | 2618 | //--------------------------------------------------------------------- |
michael@0 | 2619 | void |
michael@0 | 2620 | nsPrintEngine::EllipseLongString(nsAString& aStr, const uint32_t aLen, bool aDoFront) |
michael@0 | 2621 | { |
michael@0 | 2622 | // Make sure the URLS don't get too long for the progress dialog |
michael@0 | 2623 | if (aLen >= 3 && aStr.Length() > aLen) { |
michael@0 | 2624 | if (aDoFront) { |
michael@0 | 2625 | nsAutoString newStr; |
michael@0 | 2626 | newStr.AppendLiteral("..."); |
michael@0 | 2627 | newStr += Substring(aStr, aStr.Length() - (aLen - 3), aLen - 3); |
michael@0 | 2628 | aStr = newStr; |
michael@0 | 2629 | } else { |
michael@0 | 2630 | aStr.SetLength(aLen - 3); |
michael@0 | 2631 | aStr.AppendLiteral("..."); |
michael@0 | 2632 | } |
michael@0 | 2633 | } |
michael@0 | 2634 | } |
michael@0 | 2635 | |
michael@0 | 2636 | static bool |
michael@0 | 2637 | DocHasPrintCallbackCanvas(nsIDocument* aDoc, void* aData) |
michael@0 | 2638 | { |
michael@0 | 2639 | if (!aDoc) { |
michael@0 | 2640 | return true; |
michael@0 | 2641 | } |
michael@0 | 2642 | Element* root = aDoc->GetRootElement(); |
michael@0 | 2643 | if (!root) { |
michael@0 | 2644 | return true; |
michael@0 | 2645 | } |
michael@0 | 2646 | nsRefPtr<nsContentList> canvases = NS_GetContentList(root, |
michael@0 | 2647 | kNameSpaceID_XHTML, |
michael@0 | 2648 | NS_LITERAL_STRING("canvas")); |
michael@0 | 2649 | uint32_t canvasCount = canvases->Length(true); |
michael@0 | 2650 | for (uint32_t i = 0; i < canvasCount; ++i) { |
michael@0 | 2651 | HTMLCanvasElement* canvas = HTMLCanvasElement::FromContentOrNull(canvases->Item(i, false)); |
michael@0 | 2652 | if (canvas && canvas->GetMozPrintCallback()) { |
michael@0 | 2653 | // This subdocument has a print callback. Set result and return false to |
michael@0 | 2654 | // stop iteration. |
michael@0 | 2655 | *static_cast<bool*>(aData) = true; |
michael@0 | 2656 | return false; |
michael@0 | 2657 | } |
michael@0 | 2658 | } |
michael@0 | 2659 | return true; |
michael@0 | 2660 | } |
michael@0 | 2661 | |
michael@0 | 2662 | static bool |
michael@0 | 2663 | DocHasPrintCallbackCanvas(nsIDocument* aDoc) |
michael@0 | 2664 | { |
michael@0 | 2665 | bool result = false; |
michael@0 | 2666 | aDoc->EnumerateSubDocuments(&DocHasPrintCallbackCanvas, static_cast<void*>(&result)); |
michael@0 | 2667 | return result; |
michael@0 | 2668 | } |
michael@0 | 2669 | |
michael@0 | 2670 | /** |
michael@0 | 2671 | * Checks to see if the document this print engine is associated with has any |
michael@0 | 2672 | * canvases that have a mozPrintCallback. |
michael@0 | 2673 | */ |
michael@0 | 2674 | bool |
michael@0 | 2675 | nsPrintEngine::HasPrintCallbackCanvas() |
michael@0 | 2676 | { |
michael@0 | 2677 | if (!mDocument) { |
michael@0 | 2678 | return false; |
michael@0 | 2679 | } |
michael@0 | 2680 | // First check this mDocument. |
michael@0 | 2681 | bool result = false; |
michael@0 | 2682 | DocHasPrintCallbackCanvas(mDocument, static_cast<void*>(&result)); |
michael@0 | 2683 | // Also check the sub documents. |
michael@0 | 2684 | return result || DocHasPrintCallbackCanvas(mDocument); |
michael@0 | 2685 | } |
michael@0 | 2686 | |
michael@0 | 2687 | //------------------------------------------------------- |
michael@0 | 2688 | bool |
michael@0 | 2689 | nsPrintEngine::PrePrintPage() |
michael@0 | 2690 | { |
michael@0 | 2691 | NS_ASSERTION(mPageSeqFrame, "mPageSeqFrame is null!"); |
michael@0 | 2692 | NS_ASSERTION(mPrt, "mPrt is null!"); |
michael@0 | 2693 | |
michael@0 | 2694 | // Although these should NEVER be nullptr |
michael@0 | 2695 | // This is added insurance, to make sure we don't crash in optimized builds |
michael@0 | 2696 | if (!mPrt || !mPageSeqFrame) { |
michael@0 | 2697 | return true; // means we are done preparing the page. |
michael@0 | 2698 | } |
michael@0 | 2699 | |
michael@0 | 2700 | // Check setting to see if someone request it be cancelled |
michael@0 | 2701 | bool isCancelled = false; |
michael@0 | 2702 | mPrt->mPrintSettings->GetIsCancelled(&isCancelled); |
michael@0 | 2703 | if (isCancelled) |
michael@0 | 2704 | return true; |
michael@0 | 2705 | |
michael@0 | 2706 | // Ask mPageSeqFrame if the page is ready to be printed. |
michael@0 | 2707 | // If the page doesn't get printed at all, the |done| will be |true|. |
michael@0 | 2708 | bool done = false; |
michael@0 | 2709 | nsresult rv = mPageSeqFrame->PrePrintNextPage(mPagePrintTimer, &done); |
michael@0 | 2710 | if (NS_FAILED(rv)) { |
michael@0 | 2711 | // ??? ::PrintPage doesn't set |mPrt->mIsAborted = true| if rv != NS_ERROR_ABORT, |
michael@0 | 2712 | // but I don't really understand why this should be the right thing to do? |
michael@0 | 2713 | // Shouldn't |mPrt->mIsAborted| set to true all the time if something |
michael@0 | 2714 | // wents wrong? |
michael@0 | 2715 | if (rv != NS_ERROR_ABORT) { |
michael@0 | 2716 | ShowPrintErrorDialog(rv); |
michael@0 | 2717 | mPrt->mIsAborted = true; |
michael@0 | 2718 | } |
michael@0 | 2719 | done = true; |
michael@0 | 2720 | } |
michael@0 | 2721 | return done; |
michael@0 | 2722 | } |
michael@0 | 2723 | |
michael@0 | 2724 | bool |
michael@0 | 2725 | nsPrintEngine::PrintPage(nsPrintObject* aPO, |
michael@0 | 2726 | bool& aInRange) |
michael@0 | 2727 | { |
michael@0 | 2728 | NS_ASSERTION(aPO, "aPO is null!"); |
michael@0 | 2729 | NS_ASSERTION(mPageSeqFrame, "mPageSeqFrame is null!"); |
michael@0 | 2730 | NS_ASSERTION(mPrt, "mPrt is null!"); |
michael@0 | 2731 | |
michael@0 | 2732 | // Although these should NEVER be nullptr |
michael@0 | 2733 | // This is added insurance, to make sure we don't crash in optimized builds |
michael@0 | 2734 | if (!mPrt || !aPO || !mPageSeqFrame) { |
michael@0 | 2735 | ShowPrintErrorDialog(NS_ERROR_FAILURE); |
michael@0 | 2736 | return true; // means we are done printing |
michael@0 | 2737 | } |
michael@0 | 2738 | |
michael@0 | 2739 | PR_PL(("-----------------------------------\n")); |
michael@0 | 2740 | PR_PL(("------ In DV::PrintPage PO: %p (%s)\n", aPO, gFrameTypesStr[aPO->mFrameType])); |
michael@0 | 2741 | |
michael@0 | 2742 | // Check setting to see if someone request it be cancelled |
michael@0 | 2743 | bool isCancelled = false; |
michael@0 | 2744 | mPrt->mPrintSettings->GetIsCancelled(&isCancelled); |
michael@0 | 2745 | if (isCancelled || mPrt->mIsAborted) |
michael@0 | 2746 | return true; |
michael@0 | 2747 | |
michael@0 | 2748 | int32_t pageNum, numPages, endPage; |
michael@0 | 2749 | mPageSeqFrame->GetCurrentPageNum(&pageNum); |
michael@0 | 2750 | mPageSeqFrame->GetNumPages(&numPages); |
michael@0 | 2751 | |
michael@0 | 2752 | bool donePrinting; |
michael@0 | 2753 | bool isDoingPrintRange; |
michael@0 | 2754 | mPageSeqFrame->IsDoingPrintRange(&isDoingPrintRange); |
michael@0 | 2755 | if (isDoingPrintRange) { |
michael@0 | 2756 | int32_t fromPage; |
michael@0 | 2757 | int32_t toPage; |
michael@0 | 2758 | mPageSeqFrame->GetPrintRange(&fromPage, &toPage); |
michael@0 | 2759 | |
michael@0 | 2760 | if (fromPage > numPages) { |
michael@0 | 2761 | return true; |
michael@0 | 2762 | } |
michael@0 | 2763 | if (toPage > numPages) { |
michael@0 | 2764 | toPage = numPages; |
michael@0 | 2765 | } |
michael@0 | 2766 | |
michael@0 | 2767 | PR_PL(("****** Printing Page %d printing from %d to page %d\n", pageNum, fromPage, toPage)); |
michael@0 | 2768 | |
michael@0 | 2769 | donePrinting = pageNum >= toPage; |
michael@0 | 2770 | aInRange = pageNum >= fromPage && pageNum <= toPage; |
michael@0 | 2771 | endPage = (toPage - fromPage)+1; |
michael@0 | 2772 | } else { |
michael@0 | 2773 | PR_PL(("****** Printing Page %d of %d page(s)\n", pageNum, numPages)); |
michael@0 | 2774 | |
michael@0 | 2775 | donePrinting = pageNum >= numPages; |
michael@0 | 2776 | endPage = numPages; |
michael@0 | 2777 | aInRange = true; |
michael@0 | 2778 | } |
michael@0 | 2779 | |
michael@0 | 2780 | // XXX This is wrong, but the actual behavior in the presence of a print |
michael@0 | 2781 | // range sucks. |
michael@0 | 2782 | if (mPrt->mPrintFrameType == nsIPrintSettings::kEachFrameSep) |
michael@0 | 2783 | endPage = mPrt->mNumPrintablePages; |
michael@0 | 2784 | |
michael@0 | 2785 | mPrt->DoOnProgressChange(++mPrt->mNumPagesPrinted, endPage, false, 0); |
michael@0 | 2786 | |
michael@0 | 2787 | // Print the Page |
michael@0 | 2788 | // if a print job was cancelled externally, an EndPage or BeginPage may |
michael@0 | 2789 | // fail and the failure is passed back here. |
michael@0 | 2790 | // Returning true means we are done printing. |
michael@0 | 2791 | // |
michael@0 | 2792 | // When rv == NS_ERROR_ABORT, it means we want out of the |
michael@0 | 2793 | // print job without displaying any error messages |
michael@0 | 2794 | nsresult rv = mPageSeqFrame->PrintNextPage(); |
michael@0 | 2795 | if (NS_FAILED(rv)) { |
michael@0 | 2796 | if (rv != NS_ERROR_ABORT) { |
michael@0 | 2797 | ShowPrintErrorDialog(rv); |
michael@0 | 2798 | mPrt->mIsAborted = true; |
michael@0 | 2799 | } |
michael@0 | 2800 | return true; |
michael@0 | 2801 | } |
michael@0 | 2802 | |
michael@0 | 2803 | mPageSeqFrame->DoPageEnd(); |
michael@0 | 2804 | |
michael@0 | 2805 | return donePrinting; |
michael@0 | 2806 | } |
michael@0 | 2807 | |
michael@0 | 2808 | /** --------------------------------------------------- |
michael@0 | 2809 | * Find by checking frames type |
michael@0 | 2810 | */ |
michael@0 | 2811 | nsresult |
michael@0 | 2812 | nsPrintEngine::FindSelectionBoundsWithList(nsPresContext* aPresContext, |
michael@0 | 2813 | nsRenderingContext& aRC, |
michael@0 | 2814 | nsFrameList::Enumerator& aChildFrames, |
michael@0 | 2815 | nsIFrame * aParentFrame, |
michael@0 | 2816 | nsRect& aRect, |
michael@0 | 2817 | nsIFrame *& aStartFrame, |
michael@0 | 2818 | nsRect& aStartRect, |
michael@0 | 2819 | nsIFrame *& aEndFrame, |
michael@0 | 2820 | nsRect& aEndRect) |
michael@0 | 2821 | { |
michael@0 | 2822 | NS_ASSERTION(aPresContext, "Pointer is null!"); |
michael@0 | 2823 | NS_ASSERTION(aParentFrame, "Pointer is null!"); |
michael@0 | 2824 | |
michael@0 | 2825 | aRect += aParentFrame->GetPosition(); |
michael@0 | 2826 | for (; !aChildFrames.AtEnd(); aChildFrames.Next()) { |
michael@0 | 2827 | nsIFrame* child = aChildFrames.get(); |
michael@0 | 2828 | if (child->IsSelected() && child->IsVisibleForPainting()) { |
michael@0 | 2829 | nsRect r = child->GetRect(); |
michael@0 | 2830 | if (aStartFrame == nullptr) { |
michael@0 | 2831 | aStartFrame = child; |
michael@0 | 2832 | aStartRect.SetRect(aRect.x + r.x, aRect.y + r.y, r.width, r.height); |
michael@0 | 2833 | } else { |
michael@0 | 2834 | aEndFrame = child; |
michael@0 | 2835 | aEndRect.SetRect(aRect.x + r.x, aRect.y + r.y, r.width, r.height); |
michael@0 | 2836 | } |
michael@0 | 2837 | } |
michael@0 | 2838 | FindSelectionBounds(aPresContext, aRC, child, aRect, aStartFrame, aStartRect, aEndFrame, aEndRect); |
michael@0 | 2839 | child = child->GetNextSibling(); |
michael@0 | 2840 | } |
michael@0 | 2841 | aRect -= aParentFrame->GetPosition(); |
michael@0 | 2842 | return NS_OK; |
michael@0 | 2843 | } |
michael@0 | 2844 | |
michael@0 | 2845 | //------------------------------------------------------- |
michael@0 | 2846 | // Find the Frame that is XMost |
michael@0 | 2847 | nsresult |
michael@0 | 2848 | nsPrintEngine::FindSelectionBounds(nsPresContext* aPresContext, |
michael@0 | 2849 | nsRenderingContext& aRC, |
michael@0 | 2850 | nsIFrame * aParentFrame, |
michael@0 | 2851 | nsRect& aRect, |
michael@0 | 2852 | nsIFrame *& aStartFrame, |
michael@0 | 2853 | nsRect& aStartRect, |
michael@0 | 2854 | nsIFrame *& aEndFrame, |
michael@0 | 2855 | nsRect& aEndRect) |
michael@0 | 2856 | { |
michael@0 | 2857 | NS_ASSERTION(aPresContext, "Pointer is null!"); |
michael@0 | 2858 | NS_ASSERTION(aParentFrame, "Pointer is null!"); |
michael@0 | 2859 | |
michael@0 | 2860 | // loop through named child lists |
michael@0 | 2861 | nsIFrame::ChildListIterator lists(aParentFrame); |
michael@0 | 2862 | for (; !lists.IsDone(); lists.Next()) { |
michael@0 | 2863 | nsFrameList::Enumerator childFrames(lists.CurrentList()); |
michael@0 | 2864 | nsresult rv = FindSelectionBoundsWithList(aPresContext, aRC, childFrames, aParentFrame, aRect, aStartFrame, aStartRect, aEndFrame, aEndRect); |
michael@0 | 2865 | NS_ENSURE_SUCCESS(rv, rv); |
michael@0 | 2866 | } |
michael@0 | 2867 | return NS_OK; |
michael@0 | 2868 | } |
michael@0 | 2869 | |
michael@0 | 2870 | /** --------------------------------------------------- |
michael@0 | 2871 | * This method finds the starting and ending page numbers |
michael@0 | 2872 | * of the selection and also returns rect for each where |
michael@0 | 2873 | * the x,y of the rect is relative to the very top of the |
michael@0 | 2874 | * frame tree (absolutely positioned) |
michael@0 | 2875 | */ |
michael@0 | 2876 | nsresult |
michael@0 | 2877 | nsPrintEngine::GetPageRangeForSelection(nsIPresShell * aPresShell, |
michael@0 | 2878 | nsPresContext* aPresContext, |
michael@0 | 2879 | nsRenderingContext& aRC, |
michael@0 | 2880 | nsISelection* aSelection, |
michael@0 | 2881 | nsIPageSequenceFrame* aPageSeqFrame, |
michael@0 | 2882 | nsIFrame** aStartFrame, |
michael@0 | 2883 | int32_t& aStartPageNum, |
michael@0 | 2884 | nsRect& aStartRect, |
michael@0 | 2885 | nsIFrame** aEndFrame, |
michael@0 | 2886 | int32_t& aEndPageNum, |
michael@0 | 2887 | nsRect& aEndRect) |
michael@0 | 2888 | { |
michael@0 | 2889 | NS_ASSERTION(aPresShell, "Pointer is null!"); |
michael@0 | 2890 | NS_ASSERTION(aPresContext, "Pointer is null!"); |
michael@0 | 2891 | NS_ASSERTION(aSelection, "Pointer is null!"); |
michael@0 | 2892 | NS_ASSERTION(aPageSeqFrame, "Pointer is null!"); |
michael@0 | 2893 | NS_ASSERTION(aStartFrame, "Pointer is null!"); |
michael@0 | 2894 | NS_ASSERTION(aEndFrame, "Pointer is null!"); |
michael@0 | 2895 | |
michael@0 | 2896 | nsIFrame * seqFrame = do_QueryFrame(aPageSeqFrame); |
michael@0 | 2897 | if (!seqFrame) { |
michael@0 | 2898 | return NS_ERROR_FAILURE; |
michael@0 | 2899 | } |
michael@0 | 2900 | |
michael@0 | 2901 | nsIFrame * startFrame = nullptr; |
michael@0 | 2902 | nsIFrame * endFrame = nullptr; |
michael@0 | 2903 | |
michael@0 | 2904 | // start out with the sequence frame and search the entire frame tree |
michael@0 | 2905 | // capturing the starting and ending child frames of the selection |
michael@0 | 2906 | // and their rects |
michael@0 | 2907 | nsRect r = seqFrame->GetRect(); |
michael@0 | 2908 | FindSelectionBounds(aPresContext, aRC, seqFrame, r, |
michael@0 | 2909 | startFrame, aStartRect, endFrame, aEndRect); |
michael@0 | 2910 | |
michael@0 | 2911 | #ifdef DEBUG_rodsX |
michael@0 | 2912 | printf("Start Frame: %p\n", startFrame); |
michael@0 | 2913 | printf("End Frame: %p\n", endFrame); |
michael@0 | 2914 | #endif |
michael@0 | 2915 | |
michael@0 | 2916 | // initial the page numbers here |
michael@0 | 2917 | // in case we don't find and frames |
michael@0 | 2918 | aStartPageNum = -1; |
michael@0 | 2919 | aEndPageNum = -1; |
michael@0 | 2920 | |
michael@0 | 2921 | nsIFrame * startPageFrame; |
michael@0 | 2922 | nsIFrame * endPageFrame; |
michael@0 | 2923 | |
michael@0 | 2924 | // check to make sure we found a starting frame |
michael@0 | 2925 | if (startFrame != nullptr) { |
michael@0 | 2926 | // Now search up the tree to find what page the |
michael@0 | 2927 | // start/ending selections frames are on |
michael@0 | 2928 | // |
michael@0 | 2929 | // Check to see if start should be same as end if |
michael@0 | 2930 | // the end frame comes back null |
michael@0 | 2931 | if (endFrame == nullptr) { |
michael@0 | 2932 | // XXX the "GetPageFrame" step could be integrated into |
michael@0 | 2933 | // the FindSelectionBounds step, but walking up to find |
michael@0 | 2934 | // the parent of a child frame isn't expensive and it makes |
michael@0 | 2935 | // FindSelectionBounds a little easier to understand |
michael@0 | 2936 | startPageFrame = nsLayoutUtils::GetPageFrame(startFrame); |
michael@0 | 2937 | endPageFrame = startPageFrame; |
michael@0 | 2938 | aEndRect = aStartRect; |
michael@0 | 2939 | } else { |
michael@0 | 2940 | startPageFrame = nsLayoutUtils::GetPageFrame(startFrame); |
michael@0 | 2941 | endPageFrame = nsLayoutUtils::GetPageFrame(endFrame); |
michael@0 | 2942 | } |
michael@0 | 2943 | } else { |
michael@0 | 2944 | return NS_ERROR_FAILURE; |
michael@0 | 2945 | } |
michael@0 | 2946 | |
michael@0 | 2947 | #ifdef DEBUG_rodsX |
michael@0 | 2948 | printf("Start Page: %p\n", startPageFrame); |
michael@0 | 2949 | printf("End Page: %p\n", endPageFrame); |
michael@0 | 2950 | |
michael@0 | 2951 | // dump all the pages and their pointers |
michael@0 | 2952 | { |
michael@0 | 2953 | int32_t pageNum = 1; |
michael@0 | 2954 | nsIFrame* child = seqFrame->GetFirstPrincipalChild(); |
michael@0 | 2955 | while (child != nullptr) { |
michael@0 | 2956 | printf("Page: %d - %p\n", pageNum, child); |
michael@0 | 2957 | pageNum++; |
michael@0 | 2958 | child = child->GetNextSibling(); |
michael@0 | 2959 | } |
michael@0 | 2960 | } |
michael@0 | 2961 | #endif |
michael@0 | 2962 | |
michael@0 | 2963 | // Now that we have the page frames |
michael@0 | 2964 | // find out what the page numbers are for each frame |
michael@0 | 2965 | int32_t pageNum = 1; |
michael@0 | 2966 | nsIFrame* page = seqFrame->GetFirstPrincipalChild(); |
michael@0 | 2967 | while (page != nullptr) { |
michael@0 | 2968 | if (page == startPageFrame) { |
michael@0 | 2969 | aStartPageNum = pageNum; |
michael@0 | 2970 | } |
michael@0 | 2971 | if (page == endPageFrame) { |
michael@0 | 2972 | aEndPageNum = pageNum; |
michael@0 | 2973 | } |
michael@0 | 2974 | pageNum++; |
michael@0 | 2975 | page = page->GetNextSibling(); |
michael@0 | 2976 | } |
michael@0 | 2977 | |
michael@0 | 2978 | #ifdef DEBUG_rodsX |
michael@0 | 2979 | printf("Start Page No: %d\n", aStartPageNum); |
michael@0 | 2980 | printf("End Page No: %d\n", aEndPageNum); |
michael@0 | 2981 | #endif |
michael@0 | 2982 | |
michael@0 | 2983 | *aStartFrame = startPageFrame; |
michael@0 | 2984 | *aEndFrame = endPageFrame; |
michael@0 | 2985 | |
michael@0 | 2986 | return NS_OK; |
michael@0 | 2987 | } |
michael@0 | 2988 | |
michael@0 | 2989 | //----------------------------------------------------------------- |
michael@0 | 2990 | //-- Done: Printing Methods |
michael@0 | 2991 | //----------------------------------------------------------------- |
michael@0 | 2992 | |
michael@0 | 2993 | |
michael@0 | 2994 | //----------------------------------------------------------------- |
michael@0 | 2995 | //-- Section: Misc Support Methods |
michael@0 | 2996 | //----------------------------------------------------------------- |
michael@0 | 2997 | |
michael@0 | 2998 | //--------------------------------------------------------------------- |
michael@0 | 2999 | void nsPrintEngine::SetIsPrinting(bool aIsPrinting) |
michael@0 | 3000 | { |
michael@0 | 3001 | mIsDoingPrinting = aIsPrinting; |
michael@0 | 3002 | // Calling SetIsPrinting while in print preview confuses the document viewer |
michael@0 | 3003 | // This is safe because we prevent exiting print preview while printing |
michael@0 | 3004 | if (!mIsDoingPrintPreview && mDocViewerPrint) { |
michael@0 | 3005 | mDocViewerPrint->SetIsPrinting(aIsPrinting); |
michael@0 | 3006 | } |
michael@0 | 3007 | if (mPrt && aIsPrinting) { |
michael@0 | 3008 | mPrt->mPreparingForPrint = true; |
michael@0 | 3009 | } |
michael@0 | 3010 | } |
michael@0 | 3011 | |
michael@0 | 3012 | //--------------------------------------------------------------------- |
michael@0 | 3013 | void nsPrintEngine::SetIsPrintPreview(bool aIsPrintPreview) |
michael@0 | 3014 | { |
michael@0 | 3015 | mIsDoingPrintPreview = aIsPrintPreview; |
michael@0 | 3016 | |
michael@0 | 3017 | if (mDocViewerPrint) { |
michael@0 | 3018 | mDocViewerPrint->SetIsPrintPreview(aIsPrintPreview); |
michael@0 | 3019 | } |
michael@0 | 3020 | } |
michael@0 | 3021 | |
michael@0 | 3022 | //--------------------------------------------------------------------- |
michael@0 | 3023 | void |
michael@0 | 3024 | nsPrintEngine::CleanupDocTitleArray(char16_t**& aArray, int32_t& aCount) |
michael@0 | 3025 | { |
michael@0 | 3026 | for (int32_t i = aCount - 1; i >= 0; i--) { |
michael@0 | 3027 | nsMemory::Free(aArray[i]); |
michael@0 | 3028 | } |
michael@0 | 3029 | nsMemory::Free(aArray); |
michael@0 | 3030 | aArray = nullptr; |
michael@0 | 3031 | aCount = 0; |
michael@0 | 3032 | } |
michael@0 | 3033 | |
michael@0 | 3034 | //--------------------------------------------------------------------- |
michael@0 | 3035 | // static |
michael@0 | 3036 | bool nsPrintEngine::HasFramesetChild(nsIContent* aContent) |
michael@0 | 3037 | { |
michael@0 | 3038 | if (!aContent) { |
michael@0 | 3039 | return false; |
michael@0 | 3040 | } |
michael@0 | 3041 | |
michael@0 | 3042 | // do a breadth search across all siblings |
michael@0 | 3043 | for (nsIContent* child = aContent->GetFirstChild(); |
michael@0 | 3044 | child; |
michael@0 | 3045 | child = child->GetNextSibling()) { |
michael@0 | 3046 | if (child->IsHTML(nsGkAtoms::frameset)) { |
michael@0 | 3047 | return true; |
michael@0 | 3048 | } |
michael@0 | 3049 | } |
michael@0 | 3050 | |
michael@0 | 3051 | return false; |
michael@0 | 3052 | } |
michael@0 | 3053 | |
michael@0 | 3054 | |
michael@0 | 3055 | |
michael@0 | 3056 | /** --------------------------------------------------- |
michael@0 | 3057 | * Get the Focused Frame for a documentviewer |
michael@0 | 3058 | */ |
michael@0 | 3059 | already_AddRefed<nsIDOMWindow> |
michael@0 | 3060 | nsPrintEngine::FindFocusedDOMWindow() |
michael@0 | 3061 | { |
michael@0 | 3062 | nsIFocusManager* fm = nsFocusManager::GetFocusManager(); |
michael@0 | 3063 | NS_ENSURE_TRUE(fm, nullptr); |
michael@0 | 3064 | |
michael@0 | 3065 | nsCOMPtr<nsPIDOMWindow> window(mDocument->GetWindow()); |
michael@0 | 3066 | NS_ENSURE_TRUE(window, nullptr); |
michael@0 | 3067 | |
michael@0 | 3068 | nsCOMPtr<nsPIDOMWindow> rootWindow = window->GetPrivateRoot(); |
michael@0 | 3069 | NS_ENSURE_TRUE(rootWindow, nullptr); |
michael@0 | 3070 | |
michael@0 | 3071 | nsCOMPtr<nsPIDOMWindow> focusedWindow; |
michael@0 | 3072 | nsFocusManager::GetFocusedDescendant(rootWindow, true, |
michael@0 | 3073 | getter_AddRefs(focusedWindow)); |
michael@0 | 3074 | NS_ENSURE_TRUE(focusedWindow, nullptr); |
michael@0 | 3075 | |
michael@0 | 3076 | if (IsWindowsInOurSubTree(focusedWindow)) { |
michael@0 | 3077 | return focusedWindow.forget(); |
michael@0 | 3078 | } |
michael@0 | 3079 | |
michael@0 | 3080 | return nullptr; |
michael@0 | 3081 | } |
michael@0 | 3082 | |
michael@0 | 3083 | //--------------------------------------------------------------------- |
michael@0 | 3084 | bool |
michael@0 | 3085 | nsPrintEngine::IsWindowsInOurSubTree(nsPIDOMWindow * window) |
michael@0 | 3086 | { |
michael@0 | 3087 | bool found = false; |
michael@0 | 3088 | |
michael@0 | 3089 | // now check to make sure it is in "our" tree of docshells |
michael@0 | 3090 | if (window) { |
michael@0 | 3091 | nsCOMPtr<nsIDocShell> docShell = window->GetDocShell(); |
michael@0 | 3092 | |
michael@0 | 3093 | if (docShell) { |
michael@0 | 3094 | // get this DocViewer docshell |
michael@0 | 3095 | nsCOMPtr<nsIDocShell> thisDVDocShell(do_QueryReferent(mContainer)); |
michael@0 | 3096 | while (!found) { |
michael@0 | 3097 | if (docShell) { |
michael@0 | 3098 | if (docShell == thisDVDocShell) { |
michael@0 | 3099 | found = true; |
michael@0 | 3100 | break; |
michael@0 | 3101 | } |
michael@0 | 3102 | } else { |
michael@0 | 3103 | break; // at top of tree |
michael@0 | 3104 | } |
michael@0 | 3105 | nsCOMPtr<nsIDocShellTreeItem> docShellItemParent; |
michael@0 | 3106 | docShell->GetSameTypeParent(getter_AddRefs(docShellItemParent)); |
michael@0 | 3107 | docShell = do_QueryInterface(docShellItemParent); |
michael@0 | 3108 | } // while |
michael@0 | 3109 | } |
michael@0 | 3110 | } // scriptobj |
michael@0 | 3111 | |
michael@0 | 3112 | return found; |
michael@0 | 3113 | } |
michael@0 | 3114 | |
michael@0 | 3115 | //------------------------------------------------------- |
michael@0 | 3116 | bool |
michael@0 | 3117 | nsPrintEngine::DonePrintingPages(nsPrintObject* aPO, nsresult aResult) |
michael@0 | 3118 | { |
michael@0 | 3119 | //NS_ASSERTION(aPO, "Pointer is null!"); |
michael@0 | 3120 | PR_PL(("****** In DV::DonePrintingPages PO: %p (%s)\n", aPO, aPO?gFrameTypesStr[aPO->mFrameType]:"")); |
michael@0 | 3121 | |
michael@0 | 3122 | // If there is a pageSeqFrame, make sure there are no more printCanvas active |
michael@0 | 3123 | // that might call |Notify| on the pagePrintTimer after things are cleaned up |
michael@0 | 3124 | // and printing was marked as being done. |
michael@0 | 3125 | if (mPageSeqFrame) { |
michael@0 | 3126 | mPageSeqFrame->ResetPrintCanvasList(); |
michael@0 | 3127 | } |
michael@0 | 3128 | |
michael@0 | 3129 | if (aPO && !mPrt->mIsAborted) { |
michael@0 | 3130 | aPO->mHasBeenPrinted = true; |
michael@0 | 3131 | nsresult rv; |
michael@0 | 3132 | bool didPrint = PrintDocContent(mPrt->mPrintObject, rv); |
michael@0 | 3133 | if (NS_SUCCEEDED(rv) && didPrint) { |
michael@0 | 3134 | PR_PL(("****** In DV::DonePrintingPages PO: %p (%s) didPrint:%s (Not Done Printing)\n", aPO, gFrameTypesStr[aPO->mFrameType], PRT_YESNO(didPrint))); |
michael@0 | 3135 | return false; |
michael@0 | 3136 | } |
michael@0 | 3137 | } |
michael@0 | 3138 | |
michael@0 | 3139 | if (NS_SUCCEEDED(aResult)) { |
michael@0 | 3140 | FirePrintCompletionEvent(); |
michael@0 | 3141 | } |
michael@0 | 3142 | |
michael@0 | 3143 | TurnScriptingOn(true); |
michael@0 | 3144 | SetIsPrinting(false); |
michael@0 | 3145 | |
michael@0 | 3146 | // Release reference to mPagePrintTimer; the timer object destroys itself |
michael@0 | 3147 | // after this returns true |
michael@0 | 3148 | NS_IF_RELEASE(mPagePrintTimer); |
michael@0 | 3149 | |
michael@0 | 3150 | return true; |
michael@0 | 3151 | } |
michael@0 | 3152 | |
michael@0 | 3153 | //------------------------------------------------------- |
michael@0 | 3154 | // Recursively sets the PO items to be printed "As Is" |
michael@0 | 3155 | // from the given item down into the tree |
michael@0 | 3156 | void |
michael@0 | 3157 | nsPrintEngine::SetPrintAsIs(nsPrintObject* aPO, bool aAsIs) |
michael@0 | 3158 | { |
michael@0 | 3159 | NS_ASSERTION(aPO, "Pointer is null!"); |
michael@0 | 3160 | |
michael@0 | 3161 | aPO->mPrintAsIs = aAsIs; |
michael@0 | 3162 | for (uint32_t i=0;i<aPO->mKids.Length();i++) { |
michael@0 | 3163 | SetPrintAsIs(aPO->mKids[i], aAsIs); |
michael@0 | 3164 | } |
michael@0 | 3165 | } |
michael@0 | 3166 | |
michael@0 | 3167 | //------------------------------------------------------- |
michael@0 | 3168 | // Given a DOMWindow it recursively finds the PO object that matches |
michael@0 | 3169 | nsPrintObject* |
michael@0 | 3170 | nsPrintEngine::FindPrintObjectByDOMWin(nsPrintObject* aPO, |
michael@0 | 3171 | nsIDOMWindow* aDOMWin) |
michael@0 | 3172 | { |
michael@0 | 3173 | NS_ASSERTION(aPO, "Pointer is null!"); |
michael@0 | 3174 | |
michael@0 | 3175 | // Often the CurFocused DOMWindow is passed in |
michael@0 | 3176 | // andit is valid for it to be null, so short circut |
michael@0 | 3177 | if (!aDOMWin) { |
michael@0 | 3178 | return nullptr; |
michael@0 | 3179 | } |
michael@0 | 3180 | |
michael@0 | 3181 | nsCOMPtr<nsIDOMDocument> domDoc; |
michael@0 | 3182 | aDOMWin->GetDocument(getter_AddRefs(domDoc)); |
michael@0 | 3183 | nsCOMPtr<nsIDocument> doc = do_QueryInterface(domDoc); |
michael@0 | 3184 | if (aPO->mDocument && aPO->mDocument->GetOriginalDocument() == doc) { |
michael@0 | 3185 | return aPO; |
michael@0 | 3186 | } |
michael@0 | 3187 | |
michael@0 | 3188 | int32_t cnt = aPO->mKids.Length(); |
michael@0 | 3189 | for (int32_t i = 0; i < cnt; ++i) { |
michael@0 | 3190 | nsPrintObject* po = FindPrintObjectByDOMWin(aPO->mKids[i], aDOMWin); |
michael@0 | 3191 | if (po) { |
michael@0 | 3192 | return po; |
michael@0 | 3193 | } |
michael@0 | 3194 | } |
michael@0 | 3195 | |
michael@0 | 3196 | return nullptr; |
michael@0 | 3197 | } |
michael@0 | 3198 | |
michael@0 | 3199 | //------------------------------------------------------- |
michael@0 | 3200 | nsresult |
michael@0 | 3201 | nsPrintEngine::EnablePOsForPrinting() |
michael@0 | 3202 | { |
michael@0 | 3203 | // NOTE: All POs have been "turned off" for printing |
michael@0 | 3204 | // this is where we decided which POs get printed. |
michael@0 | 3205 | mPrt->mSelectedPO = nullptr; |
michael@0 | 3206 | |
michael@0 | 3207 | if (mPrt->mPrintSettings == nullptr) { |
michael@0 | 3208 | return NS_ERROR_FAILURE; |
michael@0 | 3209 | } |
michael@0 | 3210 | |
michael@0 | 3211 | mPrt->mPrintFrameType = nsIPrintSettings::kNoFrames; |
michael@0 | 3212 | mPrt->mPrintSettings->GetPrintFrameType(&mPrt->mPrintFrameType); |
michael@0 | 3213 | |
michael@0 | 3214 | int16_t printHowEnable = nsIPrintSettings::kFrameEnableNone; |
michael@0 | 3215 | mPrt->mPrintSettings->GetHowToEnableFrameUI(&printHowEnable); |
michael@0 | 3216 | |
michael@0 | 3217 | int16_t printRangeType = nsIPrintSettings::kRangeAllPages; |
michael@0 | 3218 | mPrt->mPrintSettings->GetPrintRange(&printRangeType); |
michael@0 | 3219 | |
michael@0 | 3220 | PR_PL(("\n")); |
michael@0 | 3221 | PR_PL(("********* nsPrintEngine::EnablePOsForPrinting *********\n")); |
michael@0 | 3222 | PR_PL(("PrintFrameType: %s \n", gPrintFrameTypeStr[mPrt->mPrintFrameType])); |
michael@0 | 3223 | PR_PL(("HowToEnableFrameUI: %s \n", gFrameHowToEnableStr[printHowEnable])); |
michael@0 | 3224 | PR_PL(("PrintRange: %s \n", gPrintRangeStr[printRangeType])); |
michael@0 | 3225 | PR_PL(("----\n")); |
michael@0 | 3226 | |
michael@0 | 3227 | // ***** This is the ultimate override ***** |
michael@0 | 3228 | // if we are printing the selection (either an IFrame or selection range) |
michael@0 | 3229 | // then set the mPrintFrameType as if it were the selected frame |
michael@0 | 3230 | if (printRangeType == nsIPrintSettings::kRangeSelection) { |
michael@0 | 3231 | mPrt->mPrintFrameType = nsIPrintSettings::kSelectedFrame; |
michael@0 | 3232 | printHowEnable = nsIPrintSettings::kFrameEnableNone; |
michael@0 | 3233 | } |
michael@0 | 3234 | |
michael@0 | 3235 | // This tells us that the "Frame" UI has turned off, |
michael@0 | 3236 | // so therefore there are no FrameSets/Frames/IFrames to be printed |
michael@0 | 3237 | // |
michael@0 | 3238 | // This means there are not FrameSets, |
michael@0 | 3239 | // but the document could contain an IFrame |
michael@0 | 3240 | if (printHowEnable == nsIPrintSettings::kFrameEnableNone) { |
michael@0 | 3241 | |
michael@0 | 3242 | // Print all the pages or a sub range of pages |
michael@0 | 3243 | if (printRangeType == nsIPrintSettings::kRangeAllPages || |
michael@0 | 3244 | printRangeType == nsIPrintSettings::kRangeSpecifiedPageRange) { |
michael@0 | 3245 | SetPrintPO(mPrt->mPrintObject, true); |
michael@0 | 3246 | |
michael@0 | 3247 | // Set the children so they are PrinAsIs |
michael@0 | 3248 | // In this case, the children are probably IFrames |
michael@0 | 3249 | if (mPrt->mPrintObject->mKids.Length() > 0) { |
michael@0 | 3250 | for (uint32_t i=0;i<mPrt->mPrintObject->mKids.Length();i++) { |
michael@0 | 3251 | nsPrintObject* po = mPrt->mPrintObject->mKids[i]; |
michael@0 | 3252 | NS_ASSERTION(po, "nsPrintObject can't be null!"); |
michael@0 | 3253 | SetPrintAsIs(po); |
michael@0 | 3254 | } |
michael@0 | 3255 | |
michael@0 | 3256 | // ***** Another override ***** |
michael@0 | 3257 | mPrt->mPrintFrameType = nsIPrintSettings::kFramesAsIs; |
michael@0 | 3258 | } |
michael@0 | 3259 | PR_PL(("PrintFrameType: %s \n", gPrintFrameTypeStr[mPrt->mPrintFrameType])); |
michael@0 | 3260 | PR_PL(("HowToEnableFrameUI: %s \n", gFrameHowToEnableStr[printHowEnable])); |
michael@0 | 3261 | PR_PL(("PrintRange: %s \n", gPrintRangeStr[printRangeType])); |
michael@0 | 3262 | return NS_OK; |
michael@0 | 3263 | } |
michael@0 | 3264 | |
michael@0 | 3265 | // This means we are either printed a selected IFrame or |
michael@0 | 3266 | // we are printing the current selection |
michael@0 | 3267 | if (printRangeType == nsIPrintSettings::kRangeSelection) { |
michael@0 | 3268 | |
michael@0 | 3269 | // If the currentFocusDOMWin can'r be null if something is selected |
michael@0 | 3270 | if (mPrt->mCurrentFocusWin) { |
michael@0 | 3271 | // Find the selected IFrame |
michael@0 | 3272 | nsPrintObject * po = FindPrintObjectByDOMWin(mPrt->mPrintObject, mPrt->mCurrentFocusWin); |
michael@0 | 3273 | if (po != nullptr) { |
michael@0 | 3274 | mPrt->mSelectedPO = po; |
michael@0 | 3275 | // Makes sure all of its children are be printed "AsIs" |
michael@0 | 3276 | SetPrintAsIs(po); |
michael@0 | 3277 | |
michael@0 | 3278 | // Now, only enable this POs (the selected PO) and all of its children |
michael@0 | 3279 | SetPrintPO(po, true); |
michael@0 | 3280 | |
michael@0 | 3281 | // check to see if we have a range selection, |
michael@0 | 3282 | // as oppose to a insert selection |
michael@0 | 3283 | // this means if the user just clicked on the IFrame then |
michael@0 | 3284 | // there will not be a selection so we want the entire page to print |
michael@0 | 3285 | // |
michael@0 | 3286 | // XXX this is sort of a hack right here to make the page |
michael@0 | 3287 | // not try to reposition itself when printing selection |
michael@0 | 3288 | nsCOMPtr<nsIDOMWindow> domWin = |
michael@0 | 3289 | do_QueryInterface(po->mDocument->GetOriginalDocument()->GetWindow()); |
michael@0 | 3290 | if (!IsThereARangeSelection(domWin)) { |
michael@0 | 3291 | printRangeType = nsIPrintSettings::kRangeAllPages; |
michael@0 | 3292 | mPrt->mPrintSettings->SetPrintRange(printRangeType); |
michael@0 | 3293 | } |
michael@0 | 3294 | PR_PL(("PrintFrameType: %s \n", gPrintFrameTypeStr[mPrt->mPrintFrameType])); |
michael@0 | 3295 | PR_PL(("HowToEnableFrameUI: %s \n", gFrameHowToEnableStr[printHowEnable])); |
michael@0 | 3296 | PR_PL(("PrintRange: %s \n", gPrintRangeStr[printRangeType])); |
michael@0 | 3297 | return NS_OK; |
michael@0 | 3298 | } |
michael@0 | 3299 | } else { |
michael@0 | 3300 | for (uint32_t i=0;i<mPrt->mPrintDocList.Length();i++) { |
michael@0 | 3301 | nsPrintObject* po = mPrt->mPrintDocList.ElementAt(i); |
michael@0 | 3302 | NS_ASSERTION(po, "nsPrintObject can't be null!"); |
michael@0 | 3303 | nsCOMPtr<nsIDOMWindow> domWin = do_GetInterface(po->mDocShell); |
michael@0 | 3304 | if (IsThereARangeSelection(domWin)) { |
michael@0 | 3305 | mPrt->mCurrentFocusWin = domWin; |
michael@0 | 3306 | SetPrintPO(po, true); |
michael@0 | 3307 | break; |
michael@0 | 3308 | } |
michael@0 | 3309 | } |
michael@0 | 3310 | return NS_OK; |
michael@0 | 3311 | } |
michael@0 | 3312 | } |
michael@0 | 3313 | } |
michael@0 | 3314 | |
michael@0 | 3315 | // check to see if there is a selection when a FrameSet is present |
michael@0 | 3316 | if (printRangeType == nsIPrintSettings::kRangeSelection) { |
michael@0 | 3317 | // If the currentFocusDOMWin can'r be null if something is selected |
michael@0 | 3318 | if (mPrt->mCurrentFocusWin) { |
michael@0 | 3319 | // Find the selected IFrame |
michael@0 | 3320 | nsPrintObject * po = FindPrintObjectByDOMWin(mPrt->mPrintObject, mPrt->mCurrentFocusWin); |
michael@0 | 3321 | if (po != nullptr) { |
michael@0 | 3322 | mPrt->mSelectedPO = po; |
michael@0 | 3323 | // Makes sure all of its children are be printed "AsIs" |
michael@0 | 3324 | SetPrintAsIs(po); |
michael@0 | 3325 | |
michael@0 | 3326 | // Now, only enable this POs (the selected PO) and all of its children |
michael@0 | 3327 | SetPrintPO(po, true); |
michael@0 | 3328 | |
michael@0 | 3329 | // check to see if we have a range selection, |
michael@0 | 3330 | // as oppose to a insert selection |
michael@0 | 3331 | // this means if the user just clicked on the IFrame then |
michael@0 | 3332 | // there will not be a selection so we want the entire page to print |
michael@0 | 3333 | // |
michael@0 | 3334 | // XXX this is sort of a hack right here to make the page |
michael@0 | 3335 | // not try to reposition itself when printing selection |
michael@0 | 3336 | nsCOMPtr<nsIDOMWindow> domWin = |
michael@0 | 3337 | do_QueryInterface(po->mDocument->GetOriginalDocument()->GetWindow()); |
michael@0 | 3338 | if (!IsThereARangeSelection(domWin)) { |
michael@0 | 3339 | printRangeType = nsIPrintSettings::kRangeAllPages; |
michael@0 | 3340 | mPrt->mPrintSettings->SetPrintRange(printRangeType); |
michael@0 | 3341 | } |
michael@0 | 3342 | PR_PL(("PrintFrameType: %s \n", gPrintFrameTypeStr[mPrt->mPrintFrameType])); |
michael@0 | 3343 | PR_PL(("HowToEnableFrameUI: %s \n", gFrameHowToEnableStr[printHowEnable])); |
michael@0 | 3344 | PR_PL(("PrintRange: %s \n", gPrintRangeStr[printRangeType])); |
michael@0 | 3345 | return NS_OK; |
michael@0 | 3346 | } |
michael@0 | 3347 | } |
michael@0 | 3348 | } |
michael@0 | 3349 | |
michael@0 | 3350 | // If we are printing "AsIs" then sets all the POs to be printed as is |
michael@0 | 3351 | if (mPrt->mPrintFrameType == nsIPrintSettings::kFramesAsIs) { |
michael@0 | 3352 | SetPrintAsIs(mPrt->mPrintObject); |
michael@0 | 3353 | SetPrintPO(mPrt->mPrintObject, true); |
michael@0 | 3354 | return NS_OK; |
michael@0 | 3355 | } |
michael@0 | 3356 | |
michael@0 | 3357 | // If we are printing the selected Frame then |
michael@0 | 3358 | // find that PO for that selected DOMWin and set it all of its |
michael@0 | 3359 | // children to be printed |
michael@0 | 3360 | if (mPrt->mPrintFrameType == nsIPrintSettings::kSelectedFrame) { |
michael@0 | 3361 | |
michael@0 | 3362 | if ((mPrt->mIsParentAFrameSet && mPrt->mCurrentFocusWin) || mPrt->mIsIFrameSelected) { |
michael@0 | 3363 | nsPrintObject * po = FindPrintObjectByDOMWin(mPrt->mPrintObject, mPrt->mCurrentFocusWin); |
michael@0 | 3364 | if (po != nullptr) { |
michael@0 | 3365 | mPrt->mSelectedPO = po; |
michael@0 | 3366 | // NOTE: Calling this sets the "po" and |
michael@0 | 3367 | // we don't want to do this for documents that have no children, |
michael@0 | 3368 | // because then the "DoEndPage" gets called and it shouldn't |
michael@0 | 3369 | if (po->mKids.Length() > 0) { |
michael@0 | 3370 | // Makes sure that itself, and all of its children are printed "AsIs" |
michael@0 | 3371 | SetPrintAsIs(po); |
michael@0 | 3372 | } |
michael@0 | 3373 | |
michael@0 | 3374 | // Now, only enable this POs (the selected PO) and all of its children |
michael@0 | 3375 | SetPrintPO(po, true); |
michael@0 | 3376 | } |
michael@0 | 3377 | } |
michael@0 | 3378 | return NS_OK; |
michael@0 | 3379 | } |
michael@0 | 3380 | |
michael@0 | 3381 | // If we are print each subdoc separately, |
michael@0 | 3382 | // then don't print any of the FraneSet Docs |
michael@0 | 3383 | if (mPrt->mPrintFrameType == nsIPrintSettings::kEachFrameSep) { |
michael@0 | 3384 | SetPrintPO(mPrt->mPrintObject, true); |
michael@0 | 3385 | int32_t cnt = mPrt->mPrintDocList.Length(); |
michael@0 | 3386 | for (int32_t i=0;i<cnt;i++) { |
michael@0 | 3387 | nsPrintObject* po = mPrt->mPrintDocList.ElementAt(i); |
michael@0 | 3388 | NS_ASSERTION(po, "nsPrintObject can't be null!"); |
michael@0 | 3389 | if (po->mFrameType == eFrameSet) { |
michael@0 | 3390 | po->mDontPrint = true; |
michael@0 | 3391 | } |
michael@0 | 3392 | } |
michael@0 | 3393 | } |
michael@0 | 3394 | |
michael@0 | 3395 | return NS_OK; |
michael@0 | 3396 | } |
michael@0 | 3397 | |
michael@0 | 3398 | //------------------------------------------------------- |
michael@0 | 3399 | // Return the nsPrintObject with that is XMost (The widest frameset frame) AND |
michael@0 | 3400 | // contains the XMost (widest) layout frame |
michael@0 | 3401 | nsPrintObject* |
michael@0 | 3402 | nsPrintEngine::FindSmallestSTF() |
michael@0 | 3403 | { |
michael@0 | 3404 | float smallestRatio = 1.0f; |
michael@0 | 3405 | nsPrintObject* smallestPO = nullptr; |
michael@0 | 3406 | |
michael@0 | 3407 | for (uint32_t i=0;i<mPrt->mPrintDocList.Length();i++) { |
michael@0 | 3408 | nsPrintObject* po = mPrt->mPrintDocList.ElementAt(i); |
michael@0 | 3409 | NS_ASSERTION(po, "nsPrintObject can't be null!"); |
michael@0 | 3410 | if (po->mFrameType != eFrameSet && po->mFrameType != eIFrame) { |
michael@0 | 3411 | if (po->mShrinkRatio < smallestRatio) { |
michael@0 | 3412 | smallestRatio = po->mShrinkRatio; |
michael@0 | 3413 | smallestPO = po; |
michael@0 | 3414 | } |
michael@0 | 3415 | } |
michael@0 | 3416 | } |
michael@0 | 3417 | |
michael@0 | 3418 | #ifdef EXTENDED_DEBUG_PRINTING |
michael@0 | 3419 | if (smallestPO) printf("*PO: %p Type: %d %10.3f\n", smallestPO, smallestPO->mFrameType, smallestPO->mShrinkRatio); |
michael@0 | 3420 | #endif |
michael@0 | 3421 | return smallestPO; |
michael@0 | 3422 | } |
michael@0 | 3423 | |
michael@0 | 3424 | //------------------------------------------------------- |
michael@0 | 3425 | void |
michael@0 | 3426 | nsPrintEngine::TurnScriptingOn(bool aDoTurnOn) |
michael@0 | 3427 | { |
michael@0 | 3428 | if (mIsDoingPrinting && aDoTurnOn && mDocViewerPrint && |
michael@0 | 3429 | mDocViewerPrint->GetIsPrintPreview()) { |
michael@0 | 3430 | // We don't want to turn scripting on if print preview is shown still after |
michael@0 | 3431 | // printing. |
michael@0 | 3432 | return; |
michael@0 | 3433 | } |
michael@0 | 3434 | |
michael@0 | 3435 | nsPrintData* prt = mPrt; |
michael@0 | 3436 | #ifdef NS_PRINT_PREVIEW |
michael@0 | 3437 | if (!prt) { |
michael@0 | 3438 | prt = mPrtPreview; |
michael@0 | 3439 | } |
michael@0 | 3440 | #endif |
michael@0 | 3441 | if (!prt) { |
michael@0 | 3442 | return; |
michael@0 | 3443 | } |
michael@0 | 3444 | |
michael@0 | 3445 | NS_ASSERTION(mDocument, "We MUST have a document."); |
michael@0 | 3446 | // First, get the script global object from the document... |
michael@0 | 3447 | |
michael@0 | 3448 | for (uint32_t i=0;i<prt->mPrintDocList.Length();i++) { |
michael@0 | 3449 | nsPrintObject* po = prt->mPrintDocList.ElementAt(i); |
michael@0 | 3450 | NS_ASSERTION(po, "nsPrintObject can't be null!"); |
michael@0 | 3451 | |
michael@0 | 3452 | nsIDocument* doc = po->mDocument; |
michael@0 | 3453 | if (!doc) { |
michael@0 | 3454 | continue; |
michael@0 | 3455 | } |
michael@0 | 3456 | |
michael@0 | 3457 | if (nsCOMPtr<nsPIDOMWindow> window = doc->GetInnerWindow()) { |
michael@0 | 3458 | nsCOMPtr<nsIGlobalObject> go = do_QueryInterface(window); |
michael@0 | 3459 | NS_WARN_IF_FALSE(go && go->GetGlobalJSObject(), "Can't get global"); |
michael@0 | 3460 | nsresult propThere = NS_PROPTABLE_PROP_NOT_THERE; |
michael@0 | 3461 | doc->GetProperty(nsGkAtoms::scriptEnabledBeforePrintOrPreview, |
michael@0 | 3462 | &propThere); |
michael@0 | 3463 | if (aDoTurnOn) { |
michael@0 | 3464 | if (propThere != NS_PROPTABLE_PROP_NOT_THERE) { |
michael@0 | 3465 | doc->DeleteProperty(nsGkAtoms::scriptEnabledBeforePrintOrPreview); |
michael@0 | 3466 | if (go && go->GetGlobalJSObject()) { |
michael@0 | 3467 | xpc::Scriptability::Get(go->GetGlobalJSObject()).Unblock(); |
michael@0 | 3468 | } |
michael@0 | 3469 | window->ResumeTimeouts(false); |
michael@0 | 3470 | } |
michael@0 | 3471 | } else { |
michael@0 | 3472 | // Have to be careful, because people call us over and over again with |
michael@0 | 3473 | // aDoTurnOn == false. So don't set the property if it's already |
michael@0 | 3474 | // set, since in that case we'd set it to the wrong value. |
michael@0 | 3475 | if (propThere == NS_PROPTABLE_PROP_NOT_THERE) { |
michael@0 | 3476 | // Stash the current value of IsScriptEnabled on the document, so |
michael@0 | 3477 | // that layout code running in print preview doesn't get confused. |
michael@0 | 3478 | doc->SetProperty(nsGkAtoms::scriptEnabledBeforePrintOrPreview, |
michael@0 | 3479 | NS_INT32_TO_PTR(doc->IsScriptEnabled())); |
michael@0 | 3480 | if (go && go->GetGlobalJSObject()) { |
michael@0 | 3481 | xpc::Scriptability::Get(go->GetGlobalJSObject()).Block(); |
michael@0 | 3482 | } |
michael@0 | 3483 | window->SuspendTimeouts(1, false); |
michael@0 | 3484 | } |
michael@0 | 3485 | } |
michael@0 | 3486 | } |
michael@0 | 3487 | } |
michael@0 | 3488 | } |
michael@0 | 3489 | |
michael@0 | 3490 | //----------------------------------------------------------------- |
michael@0 | 3491 | //-- Done: Misc Support Methods |
michael@0 | 3492 | //----------------------------------------------------------------- |
michael@0 | 3493 | |
michael@0 | 3494 | |
michael@0 | 3495 | //----------------------------------------------------------------- |
michael@0 | 3496 | //-- Section: Finishing up or Cleaning up |
michael@0 | 3497 | //----------------------------------------------------------------- |
michael@0 | 3498 | |
michael@0 | 3499 | //----------------------------------------------------------------- |
michael@0 | 3500 | void |
michael@0 | 3501 | nsPrintEngine::CloseProgressDialog(nsIWebProgressListener* aWebProgressListener) |
michael@0 | 3502 | { |
michael@0 | 3503 | if (aWebProgressListener) { |
michael@0 | 3504 | aWebProgressListener->OnStateChange(nullptr, nullptr, nsIWebProgressListener::STATE_STOP|nsIWebProgressListener::STATE_IS_DOCUMENT, NS_OK); |
michael@0 | 3505 | } |
michael@0 | 3506 | } |
michael@0 | 3507 | |
michael@0 | 3508 | //----------------------------------------------------------------- |
michael@0 | 3509 | nsresult |
michael@0 | 3510 | nsPrintEngine::FinishPrintPreview() |
michael@0 | 3511 | { |
michael@0 | 3512 | nsresult rv = NS_OK; |
michael@0 | 3513 | |
michael@0 | 3514 | #ifdef NS_PRINT_PREVIEW |
michael@0 | 3515 | |
michael@0 | 3516 | if (!mPrt) { |
michael@0 | 3517 | /* we're already finished with print preview */ |
michael@0 | 3518 | return rv; |
michael@0 | 3519 | } |
michael@0 | 3520 | |
michael@0 | 3521 | rv = DocumentReadyForPrinting(); |
michael@0 | 3522 | |
michael@0 | 3523 | SetIsCreatingPrintPreview(false); |
michael@0 | 3524 | |
michael@0 | 3525 | /* cleaup on failure + notify user */ |
michael@0 | 3526 | if (NS_FAILED(rv)) { |
michael@0 | 3527 | /* cleanup done, let's fire-up an error dialog to notify the user |
michael@0 | 3528 | * what went wrong... |
michael@0 | 3529 | */ |
michael@0 | 3530 | mPrt->OnEndPrinting(); |
michael@0 | 3531 | TurnScriptingOn(true); |
michael@0 | 3532 | |
michael@0 | 3533 | return rv; |
michael@0 | 3534 | } |
michael@0 | 3535 | |
michael@0 | 3536 | // At this point we are done preparing everything |
michael@0 | 3537 | // before it is to be created |
michael@0 | 3538 | |
michael@0 | 3539 | |
michael@0 | 3540 | if (mIsDoingPrintPreview && mOldPrtPreview) { |
michael@0 | 3541 | delete mOldPrtPreview; |
michael@0 | 3542 | mOldPrtPreview = nullptr; |
michael@0 | 3543 | } |
michael@0 | 3544 | |
michael@0 | 3545 | |
michael@0 | 3546 | mPrt->OnEndPrinting(); |
michael@0 | 3547 | |
michael@0 | 3548 | // PrintPreview was built using the mPrt (code reuse) |
michael@0 | 3549 | // then we assign it over |
michael@0 | 3550 | mPrtPreview = mPrt; |
michael@0 | 3551 | mPrt = nullptr; |
michael@0 | 3552 | |
michael@0 | 3553 | #endif // NS_PRINT_PREVIEW |
michael@0 | 3554 | |
michael@0 | 3555 | return NS_OK; |
michael@0 | 3556 | } |
michael@0 | 3557 | |
michael@0 | 3558 | //----------------------------------------------------------------- |
michael@0 | 3559 | //-- Done: Finishing up or Cleaning up |
michael@0 | 3560 | //----------------------------------------------------------------- |
michael@0 | 3561 | |
michael@0 | 3562 | |
michael@0 | 3563 | /*=============== Timer Related Code ======================*/ |
michael@0 | 3564 | nsresult |
michael@0 | 3565 | nsPrintEngine::StartPagePrintTimer(nsPrintObject* aPO) |
michael@0 | 3566 | { |
michael@0 | 3567 | if (!mPagePrintTimer) { |
michael@0 | 3568 | // Get the delay time in between the printing of each page |
michael@0 | 3569 | // this gives the user more time to press cancel |
michael@0 | 3570 | int32_t printPageDelay = 50; |
michael@0 | 3571 | mPrt->mPrintSettings->GetPrintPageDelay(&printPageDelay); |
michael@0 | 3572 | |
michael@0 | 3573 | nsRefPtr<nsPagePrintTimer> timer = |
michael@0 | 3574 | new nsPagePrintTimer(this, mDocViewerPrint, printPageDelay); |
michael@0 | 3575 | timer.forget(&mPagePrintTimer); |
michael@0 | 3576 | } |
michael@0 | 3577 | |
michael@0 | 3578 | return mPagePrintTimer->Start(aPO); |
michael@0 | 3579 | } |
michael@0 | 3580 | |
michael@0 | 3581 | /*=============== nsIObserver Interface ======================*/ |
michael@0 | 3582 | NS_IMETHODIMP |
michael@0 | 3583 | nsPrintEngine::Observe(nsISupports *aSubject, const char *aTopic, const char16_t *aData) |
michael@0 | 3584 | { |
michael@0 | 3585 | nsresult rv = NS_ERROR_FAILURE; |
michael@0 | 3586 | |
michael@0 | 3587 | rv = InitPrintDocConstruction(true); |
michael@0 | 3588 | if (!mIsDoingPrinting && mPrtPreview) { |
michael@0 | 3589 | mPrtPreview->OnEndPrinting(); |
michael@0 | 3590 | } |
michael@0 | 3591 | |
michael@0 | 3592 | return rv; |
michael@0 | 3593 | |
michael@0 | 3594 | } |
michael@0 | 3595 | |
michael@0 | 3596 | //--------------------------------------------------------------- |
michael@0 | 3597 | //-- PLEvent Notification |
michael@0 | 3598 | //--------------------------------------------------------------- |
michael@0 | 3599 | class nsPrintCompletionEvent : public nsRunnable { |
michael@0 | 3600 | public: |
michael@0 | 3601 | nsPrintCompletionEvent(nsIDocumentViewerPrint *docViewerPrint) |
michael@0 | 3602 | : mDocViewerPrint(docViewerPrint) { |
michael@0 | 3603 | NS_ASSERTION(mDocViewerPrint, "mDocViewerPrint is null."); |
michael@0 | 3604 | } |
michael@0 | 3605 | |
michael@0 | 3606 | NS_IMETHOD Run() MOZ_OVERRIDE { |
michael@0 | 3607 | if (mDocViewerPrint) |
michael@0 | 3608 | mDocViewerPrint->OnDonePrinting(); |
michael@0 | 3609 | return NS_OK; |
michael@0 | 3610 | } |
michael@0 | 3611 | |
michael@0 | 3612 | private: |
michael@0 | 3613 | nsCOMPtr<nsIDocumentViewerPrint> mDocViewerPrint; |
michael@0 | 3614 | }; |
michael@0 | 3615 | |
michael@0 | 3616 | //----------------------------------------------------------- |
michael@0 | 3617 | void |
michael@0 | 3618 | nsPrintEngine::FirePrintCompletionEvent() |
michael@0 | 3619 | { |
michael@0 | 3620 | nsCOMPtr<nsIRunnable> event = new nsPrintCompletionEvent(mDocViewerPrint); |
michael@0 | 3621 | if (NS_FAILED(NS_DispatchToCurrentThread(event))) |
michael@0 | 3622 | NS_WARNING("failed to dispatch print completion event"); |
michael@0 | 3623 | } |
michael@0 | 3624 | |
michael@0 | 3625 | //--------------------------------------------------------------- |
michael@0 | 3626 | //--------------------------------------------------------------- |
michael@0 | 3627 | //-- Debug helper routines |
michael@0 | 3628 | //--------------------------------------------------------------- |
michael@0 | 3629 | //--------------------------------------------------------------- |
michael@0 | 3630 | #if defined(XP_WIN) && defined(EXTENDED_DEBUG_PRINTING) |
michael@0 | 3631 | #include "windows.h" |
michael@0 | 3632 | #include "process.h" |
michael@0 | 3633 | #include "direct.h" |
michael@0 | 3634 | |
michael@0 | 3635 | #define MY_FINDFIRST(a,b) FindFirstFile(a,b) |
michael@0 | 3636 | #define MY_FINDNEXT(a,b) FindNextFile(a,b) |
michael@0 | 3637 | #define ISDIR(a) (a.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) |
michael@0 | 3638 | #define MY_FINDCLOSE(a) FindClose(a) |
michael@0 | 3639 | #define MY_FILENAME(a) a.cFileName |
michael@0 | 3640 | #define MY_FILESIZE(a) (a.nFileSizeHigh * MAXDWORD) + a.nFileSizeLow |
michael@0 | 3641 | |
michael@0 | 3642 | int RemoveFilesInDir(const char * aDir) |
michael@0 | 3643 | { |
michael@0 | 3644 | WIN32_FIND_DATA data_ptr; |
michael@0 | 3645 | HANDLE find_handle; |
michael@0 | 3646 | |
michael@0 | 3647 | char path[MAX_PATH]; |
michael@0 | 3648 | |
michael@0 | 3649 | strcpy(path, aDir); |
michael@0 | 3650 | |
michael@0 | 3651 | // Append slash to the end of the directory names if not there |
michael@0 | 3652 | if (path[strlen(path)-1] != '\\') |
michael@0 | 3653 | strcat(path, "\\"); |
michael@0 | 3654 | |
michael@0 | 3655 | char findPath[MAX_PATH]; |
michael@0 | 3656 | strcpy(findPath, path); |
michael@0 | 3657 | strcat(findPath, "*.*"); |
michael@0 | 3658 | |
michael@0 | 3659 | find_handle = MY_FINDFIRST(findPath, &data_ptr); |
michael@0 | 3660 | |
michael@0 | 3661 | if (find_handle != INVALID_HANDLE_VALUE) { |
michael@0 | 3662 | do { |
michael@0 | 3663 | if (ISDIR(data_ptr) |
michael@0 | 3664 | && (stricmp(MY_FILENAME(data_ptr),".")) |
michael@0 | 3665 | && (stricmp(MY_FILENAME(data_ptr),".."))) { |
michael@0 | 3666 | // skip |
michael@0 | 3667 | } |
michael@0 | 3668 | else if (!ISDIR(data_ptr)) { |
michael@0 | 3669 | if (!strncmp(MY_FILENAME(data_ptr), "print_dump", 10)) { |
michael@0 | 3670 | char fileName[MAX_PATH]; |
michael@0 | 3671 | strcpy(fileName, aDir); |
michael@0 | 3672 | strcat(fileName, "\\"); |
michael@0 | 3673 | strcat(fileName, MY_FILENAME(data_ptr)); |
michael@0 | 3674 | printf("Removing %s\n", fileName); |
michael@0 | 3675 | remove(fileName); |
michael@0 | 3676 | } |
michael@0 | 3677 | } |
michael@0 | 3678 | } while(MY_FINDNEXT(find_handle,&data_ptr)); |
michael@0 | 3679 | MY_FINDCLOSE(find_handle); |
michael@0 | 3680 | } |
michael@0 | 3681 | return TRUE; |
michael@0 | 3682 | } |
michael@0 | 3683 | #endif |
michael@0 | 3684 | |
michael@0 | 3685 | #ifdef EXTENDED_DEBUG_PRINTING |
michael@0 | 3686 | |
michael@0 | 3687 | /** --------------------------------------------------- |
michael@0 | 3688 | * Dumps Frames for Printing |
michael@0 | 3689 | */ |
michael@0 | 3690 | static void RootFrameList(nsPresContext* aPresContext, FILE* out, int32_t aIndent) |
michael@0 | 3691 | { |
michael@0 | 3692 | if (!aPresContext || !out) |
michael@0 | 3693 | return; |
michael@0 | 3694 | |
michael@0 | 3695 | nsIPresShell *shell = aPresContext->GetPresShell(); |
michael@0 | 3696 | if (shell) { |
michael@0 | 3697 | nsIFrame* frame = shell->FrameManager()->GetRootFrame(); |
michael@0 | 3698 | if (frame) { |
michael@0 | 3699 | frame->List(aPresContext, out, aIndent); |
michael@0 | 3700 | } |
michael@0 | 3701 | } |
michael@0 | 3702 | } |
michael@0 | 3703 | |
michael@0 | 3704 | /** --------------------------------------------------- |
michael@0 | 3705 | * Dumps Frames for Printing |
michael@0 | 3706 | */ |
michael@0 | 3707 | static void DumpFrames(FILE* out, |
michael@0 | 3708 | nsPresContext* aPresContext, |
michael@0 | 3709 | nsRenderingContext * aRendContext, |
michael@0 | 3710 | nsIFrame * aFrame, |
michael@0 | 3711 | int32_t aLevel) |
michael@0 | 3712 | { |
michael@0 | 3713 | NS_ASSERTION(out, "Pointer is null!"); |
michael@0 | 3714 | NS_ASSERTION(aPresContext, "Pointer is null!"); |
michael@0 | 3715 | NS_ASSERTION(aRendContext, "Pointer is null!"); |
michael@0 | 3716 | NS_ASSERTION(aFrame, "Pointer is null!"); |
michael@0 | 3717 | |
michael@0 | 3718 | nsIFrame* child = aFrame->GetFirstPrincipalChild(); |
michael@0 | 3719 | while (child != nullptr) { |
michael@0 | 3720 | for (int32_t i=0;i<aLevel;i++) { |
michael@0 | 3721 | fprintf(out, " "); |
michael@0 | 3722 | } |
michael@0 | 3723 | nsAutoString tmp; |
michael@0 | 3724 | child->GetFrameName(tmp); |
michael@0 | 3725 | fputs(NS_LossyConvertUTF16toASCII(tmp).get(), out); |
michael@0 | 3726 | bool isSelected; |
michael@0 | 3727 | if (NS_SUCCEEDED(child->IsVisibleForPainting(aPresContext, *aRendContext, true, &isSelected))) { |
michael@0 | 3728 | fprintf(out, " %p %s", child, isSelected?"VIS":"UVS"); |
michael@0 | 3729 | nsRect rect = child->GetRect(); |
michael@0 | 3730 | fprintf(out, "[%d,%d,%d,%d] ", rect.x, rect.y, rect.width, rect.height); |
michael@0 | 3731 | fprintf(out, "v: %p ", (void*)child->GetView()); |
michael@0 | 3732 | fprintf(out, "\n"); |
michael@0 | 3733 | DumpFrames(out, aPresContext, aRendContext, child, aLevel+1); |
michael@0 | 3734 | child = child->GetNextSibling(); |
michael@0 | 3735 | } |
michael@0 | 3736 | } |
michael@0 | 3737 | } |
michael@0 | 3738 | |
michael@0 | 3739 | |
michael@0 | 3740 | /** --------------------------------------------------- |
michael@0 | 3741 | * Dumps the Views from the DocShell |
michael@0 | 3742 | */ |
michael@0 | 3743 | static void |
michael@0 | 3744 | DumpViews(nsIDocShell* aDocShell, FILE* out) |
michael@0 | 3745 | { |
michael@0 | 3746 | NS_ASSERTION(aDocShell, "Pointer is null!"); |
michael@0 | 3747 | NS_ASSERTION(out, "Pointer is null!"); |
michael@0 | 3748 | |
michael@0 | 3749 | if (nullptr != aDocShell) { |
michael@0 | 3750 | fprintf(out, "docshell=%p \n", aDocShell); |
michael@0 | 3751 | nsIPresShell* shell = nsPrintEngine::GetPresShellFor(aDocShell); |
michael@0 | 3752 | if (shell) { |
michael@0 | 3753 | nsViewManager* vm = shell->GetViewManager(); |
michael@0 | 3754 | if (vm) { |
michael@0 | 3755 | nsView* root = vm->GetRootView(); |
michael@0 | 3756 | if (root) { |
michael@0 | 3757 | root->List(out); |
michael@0 | 3758 | } |
michael@0 | 3759 | } |
michael@0 | 3760 | } |
michael@0 | 3761 | else { |
michael@0 | 3762 | fputs("null pres shell\n", out); |
michael@0 | 3763 | } |
michael@0 | 3764 | |
michael@0 | 3765 | // dump the views of the sub documents |
michael@0 | 3766 | int32_t i, n; |
michael@0 | 3767 | aDocShell->GetChildCount(&n); |
michael@0 | 3768 | for (i = 0; i < n; i++) { |
michael@0 | 3769 | nsCOMPtr<nsIDocShellTreeItem> child; |
michael@0 | 3770 | aDocShell->GetChildAt(i, getter_AddRefs(child)); |
michael@0 | 3771 | nsCOMPtr<nsIDocShell> childAsShell(do_QueryInterface(child)); |
michael@0 | 3772 | if (childAsShell) { |
michael@0 | 3773 | DumpViews(childAsShell, out); |
michael@0 | 3774 | } |
michael@0 | 3775 | } |
michael@0 | 3776 | } |
michael@0 | 3777 | } |
michael@0 | 3778 | |
michael@0 | 3779 | /** --------------------------------------------------- |
michael@0 | 3780 | * Dumps the Views and Frames |
michael@0 | 3781 | */ |
michael@0 | 3782 | void DumpLayoutData(char* aTitleStr, |
michael@0 | 3783 | char* aURLStr, |
michael@0 | 3784 | nsPresContext* aPresContext, |
michael@0 | 3785 | nsDeviceContext * aDC, |
michael@0 | 3786 | nsIFrame * aRootFrame, |
michael@0 | 3787 | nsIDocShekk * aDocShell, |
michael@0 | 3788 | FILE* aFD = nullptr) |
michael@0 | 3789 | { |
michael@0 | 3790 | if (!kPrintingLogMod || kPrintingLogMod->level != DUMP_LAYOUT_LEVEL) return; |
michael@0 | 3791 | |
michael@0 | 3792 | if (aPresContext == nullptr || aDC == nullptr) { |
michael@0 | 3793 | return; |
michael@0 | 3794 | } |
michael@0 | 3795 | |
michael@0 | 3796 | #ifdef NS_PRINT_PREVIEW |
michael@0 | 3797 | if (aPresContext->Type() == nsPresContext::eContext_PrintPreview) { |
michael@0 | 3798 | return; |
michael@0 | 3799 | } |
michael@0 | 3800 | #endif |
michael@0 | 3801 | |
michael@0 | 3802 | NS_ASSERTION(aRootFrame, "Pointer is null!"); |
michael@0 | 3803 | NS_ASSERTION(aDocShell, "Pointer is null!"); |
michael@0 | 3804 | |
michael@0 | 3805 | // Dump all the frames and view to a a file |
michael@0 | 3806 | char filename[256]; |
michael@0 | 3807 | sprintf(filename, "print_dump_layout_%d.txt", gDumpLOFileNameCnt++); |
michael@0 | 3808 | FILE * fd = aFD?aFD:fopen(filename, "w"); |
michael@0 | 3809 | if (fd) { |
michael@0 | 3810 | fprintf(fd, "Title: %s\n", aTitleStr?aTitleStr:""); |
michael@0 | 3811 | fprintf(fd, "URL: %s\n", aURLStr?aURLStr:""); |
michael@0 | 3812 | fprintf(fd, "--------------- Frames ----------------\n"); |
michael@0 | 3813 | fprintf(fd, "--------------- Frames ----------------\n"); |
michael@0 | 3814 | nsRefPtr<nsRenderingContext> renderingContext = |
michael@0 | 3815 | aDC->CreateRenderingContext(); |
michael@0 | 3816 | RootFrameList(aPresContext, fd, 0); |
michael@0 | 3817 | //DumpFrames(fd, aPresContext, renderingContext, aRootFrame, 0); |
michael@0 | 3818 | fprintf(fd, "---------------------------------------\n\n"); |
michael@0 | 3819 | fprintf(fd, "--------------- Views From Root Frame----------------\n"); |
michael@0 | 3820 | nsView* v = aRootFrame->GetView(); |
michael@0 | 3821 | if (v) { |
michael@0 | 3822 | v->List(fd); |
michael@0 | 3823 | } else { |
michael@0 | 3824 | printf("View is null!\n"); |
michael@0 | 3825 | } |
michael@0 | 3826 | if (aDocShell) { |
michael@0 | 3827 | fprintf(fd, "--------------- All Views ----------------\n"); |
michael@0 | 3828 | DumpViews(aDocShell, fd); |
michael@0 | 3829 | fprintf(fd, "---------------------------------------\n\n"); |
michael@0 | 3830 | } |
michael@0 | 3831 | if (aFD == nullptr) { |
michael@0 | 3832 | fclose(fd); |
michael@0 | 3833 | } |
michael@0 | 3834 | } |
michael@0 | 3835 | } |
michael@0 | 3836 | |
michael@0 | 3837 | //------------------------------------------------------------- |
michael@0 | 3838 | static void DumpPrintObjectsList(nsTArray<nsPrintObject*> * aDocList) |
michael@0 | 3839 | { |
michael@0 | 3840 | if (!kPrintingLogMod || kPrintingLogMod->level != DUMP_LAYOUT_LEVEL) return; |
michael@0 | 3841 | |
michael@0 | 3842 | NS_ASSERTION(aDocList, "Pointer is null!"); |
michael@0 | 3843 | |
michael@0 | 3844 | const char types[][3] = {"DC", "FR", "IF", "FS"}; |
michael@0 | 3845 | PR_PL(("Doc List\n***************************************************\n")); |
michael@0 | 3846 | PR_PL(("T P A H PO DocShell Seq Page Root Page# Rect\n")); |
michael@0 | 3847 | int32_t cnt = aDocList->Length(); |
michael@0 | 3848 | for (int32_t i=0;i<cnt;i++) { |
michael@0 | 3849 | nsPrintObject* po = aDocList->ElementAt(i); |
michael@0 | 3850 | NS_ASSERTION(po, "nsPrintObject can't be null!"); |
michael@0 | 3851 | nsIFrame* rootFrame = nullptr; |
michael@0 | 3852 | if (po->mPresShell) { |
michael@0 | 3853 | rootFrame = po->mPresShell->FrameManager()->GetRootFrame(); |
michael@0 | 3854 | while (rootFrame != nullptr) { |
michael@0 | 3855 | nsIPageSequenceFrame * sqf = do_QueryFrame(rootFrame); |
michael@0 | 3856 | if (sqf) { |
michael@0 | 3857 | break; |
michael@0 | 3858 | } |
michael@0 | 3859 | rootFrame = rootFrame->GetFirstPrincipalChild(); |
michael@0 | 3860 | } |
michael@0 | 3861 | } |
michael@0 | 3862 | |
michael@0 | 3863 | PR_PL(("%s %d %d %d %p %p %p %p %p %d %d,%d,%d,%d\n", types[po->mFrameType], |
michael@0 | 3864 | po->IsPrintable(), po->mPrintAsIs, po->mHasBeenPrinted, po, po->mDocShell.get(), po->mSeqFrame, |
michael@0 | 3865 | po->mPageFrame, rootFrame, po->mPageNum, po->mRect.x, po->mRect.y, po->mRect.width, po->mRect.height)); |
michael@0 | 3866 | } |
michael@0 | 3867 | } |
michael@0 | 3868 | |
michael@0 | 3869 | //------------------------------------------------------------- |
michael@0 | 3870 | static void DumpPrintObjectsTree(nsPrintObject * aPO, int aLevel, FILE* aFD) |
michael@0 | 3871 | { |
michael@0 | 3872 | if (!kPrintingLogMod || kPrintingLogMod->level != DUMP_LAYOUT_LEVEL) return; |
michael@0 | 3873 | |
michael@0 | 3874 | NS_ASSERTION(aPO, "Pointer is null!"); |
michael@0 | 3875 | |
michael@0 | 3876 | FILE * fd = aFD?aFD:stdout; |
michael@0 | 3877 | const char types[][3] = {"DC", "FR", "IF", "FS"}; |
michael@0 | 3878 | if (aLevel == 0) { |
michael@0 | 3879 | fprintf(fd, "DocTree\n***************************************************\n"); |
michael@0 | 3880 | fprintf(fd, "T PO DocShell Seq Page Page# Rect\n"); |
michael@0 | 3881 | } |
michael@0 | 3882 | int32_t cnt = aPO->mKids.Length(); |
michael@0 | 3883 | for (int32_t i=0;i<cnt;i++) { |
michael@0 | 3884 | nsPrintObject* po = aPO->mKids.ElementAt(i); |
michael@0 | 3885 | NS_ASSERTION(po, "nsPrintObject can't be null!"); |
michael@0 | 3886 | for (int32_t k=0;k<aLevel;k++) fprintf(fd, " "); |
michael@0 | 3887 | fprintf(fd, "%s %p %p %p %p %d %d,%d,%d,%d\n", types[po->mFrameType], po, po->mDocShell.get(), po->mSeqFrame, |
michael@0 | 3888 | po->mPageFrame, po->mPageNum, po->mRect.x, po->mRect.y, po->mRect.width, po->mRect.height); |
michael@0 | 3889 | } |
michael@0 | 3890 | } |
michael@0 | 3891 | |
michael@0 | 3892 | //------------------------------------------------------------- |
michael@0 | 3893 | static void GetDocTitleAndURL(nsPrintObject* aPO, nsACString& aDocStr, nsACString& aURLStr) |
michael@0 | 3894 | { |
michael@0 | 3895 | nsAutoString docTitleStr; |
michael@0 | 3896 | nsAutoString docURLStr; |
michael@0 | 3897 | nsPrintEngine::GetDisplayTitleAndURL(aPO, |
michael@0 | 3898 | docTitleStr, docURLStr, |
michael@0 | 3899 | nsPrintEngine::eDocTitleDefURLDoc); |
michael@0 | 3900 | aDocStr = NS_ConvertUTF16toUTF8(docTitleStr); |
michael@0 | 3901 | aURLStr = NS_ConvertUTF16toUTF8(docURLStr); |
michael@0 | 3902 | } |
michael@0 | 3903 | |
michael@0 | 3904 | //------------------------------------------------------------- |
michael@0 | 3905 | static void DumpPrintObjectsTreeLayout(nsPrintObject * aPO, |
michael@0 | 3906 | nsDeviceContext * aDC, |
michael@0 | 3907 | int aLevel, FILE * aFD) |
michael@0 | 3908 | { |
michael@0 | 3909 | if (!kPrintingLogMod || kPrintingLogMod->level != DUMP_LAYOUT_LEVEL) return; |
michael@0 | 3910 | |
michael@0 | 3911 | NS_ASSERTION(aPO, "Pointer is null!"); |
michael@0 | 3912 | NS_ASSERTION(aDC, "Pointer is null!"); |
michael@0 | 3913 | |
michael@0 | 3914 | const char types[][3] = {"DC", "FR", "IF", "FS"}; |
michael@0 | 3915 | FILE * fd = nullptr; |
michael@0 | 3916 | if (aLevel == 0) { |
michael@0 | 3917 | fd = fopen("tree_layout.txt", "w"); |
michael@0 | 3918 | fprintf(fd, "DocTree\n***************************************************\n"); |
michael@0 | 3919 | fprintf(fd, "***************************************************\n"); |
michael@0 | 3920 | fprintf(fd, "T PO DocShell Seq Page Page# Rect\n"); |
michael@0 | 3921 | } else { |
michael@0 | 3922 | fd = aFD; |
michael@0 | 3923 | } |
michael@0 | 3924 | if (fd) { |
michael@0 | 3925 | nsIFrame* rootFrame = nullptr; |
michael@0 | 3926 | if (aPO->mPresShell) { |
michael@0 | 3927 | rootFrame = aPO->mPresShell->FrameManager()->GetRootFrame(); |
michael@0 | 3928 | } |
michael@0 | 3929 | for (int32_t k=0;k<aLevel;k++) fprintf(fd, " "); |
michael@0 | 3930 | fprintf(fd, "%s %p %p %p %p %d %d,%d,%d,%d\n", types[aPO->mFrameType], aPO, aPO->mDocShell.get(), aPO->mSeqFrame, |
michael@0 | 3931 | aPO->mPageFrame, aPO->mPageNum, aPO->mRect.x, aPO->mRect.y, aPO->mRect.width, aPO->mRect.height); |
michael@0 | 3932 | if (aPO->IsPrintable()) { |
michael@0 | 3933 | nsAutoCString docStr; |
michael@0 | 3934 | nsAutoCString urlStr; |
michael@0 | 3935 | GetDocTitleAndURL(aPO, docStr, urlStr); |
michael@0 | 3936 | DumpLayoutData(docStr.get(), urlStr.get(), aPO->mPresContext, aDC, rootFrame, aPO->mDocShell, fd); |
michael@0 | 3937 | } |
michael@0 | 3938 | fprintf(fd, "<***************************************************>\n"); |
michael@0 | 3939 | |
michael@0 | 3940 | int32_t cnt = aPO->mKids.Length(); |
michael@0 | 3941 | for (int32_t i=0;i<cnt;i++) { |
michael@0 | 3942 | nsPrintObject* po = aPO->mKids.ElementAt(i); |
michael@0 | 3943 | NS_ASSERTION(po, "nsPrintObject can't be null!"); |
michael@0 | 3944 | DumpPrintObjectsTreeLayout(po, aDC, aLevel+1, fd); |
michael@0 | 3945 | } |
michael@0 | 3946 | } |
michael@0 | 3947 | if (aLevel == 0 && fd) { |
michael@0 | 3948 | fclose(fd); |
michael@0 | 3949 | } |
michael@0 | 3950 | } |
michael@0 | 3951 | |
michael@0 | 3952 | //------------------------------------------------------------- |
michael@0 | 3953 | static void DumpPrintObjectsListStart(const char * aStr, nsTArray<nsPrintObject*> * aDocList) |
michael@0 | 3954 | { |
michael@0 | 3955 | if (!kPrintingLogMod || kPrintingLogMod->level != DUMP_LAYOUT_LEVEL) return; |
michael@0 | 3956 | |
michael@0 | 3957 | NS_ASSERTION(aStr, "Pointer is null!"); |
michael@0 | 3958 | NS_ASSERTION(aDocList, "Pointer is null!"); |
michael@0 | 3959 | |
michael@0 | 3960 | PR_PL(("%s\n", aStr)); |
michael@0 | 3961 | DumpPrintObjectsList(aDocList); |
michael@0 | 3962 | } |
michael@0 | 3963 | |
michael@0 | 3964 | #define DUMP_DOC_LIST(_title) DumpPrintObjectsListStart((_title), mPrt->mPrintDocList); |
michael@0 | 3965 | #define DUMP_DOC_TREE DumpPrintObjectsTree(mPrt->mPrintObject); |
michael@0 | 3966 | #define DUMP_DOC_TREELAYOUT DumpPrintObjectsTreeLayout(mPrt->mPrintObject, mPrt->mPrintDC); |
michael@0 | 3967 | |
michael@0 | 3968 | #else |
michael@0 | 3969 | #define DUMP_DOC_LIST(_title) |
michael@0 | 3970 | #define DUMP_DOC_TREE |
michael@0 | 3971 | #define DUMP_DOC_TREELAYOUT |
michael@0 | 3972 | #endif |
michael@0 | 3973 | |
michael@0 | 3974 | //--------------------------------------------------------------- |
michael@0 | 3975 | //--------------------------------------------------------------- |
michael@0 | 3976 | //-- End of debug helper routines |
michael@0 | 3977 | //--------------------------------------------------------------- |