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