nsPrintEngine.cpp 136 KB

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