Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

298 lines
7.1 KiB

  1. /*
  2. * @doc INTERNAL
  3. *
  4. * @module dispprt.cpp -- Special logic for printer object |
  5. *
  6. * Authors:
  7. * Original RichEdit code: David R. Fulmer
  8. * Christian Fortini
  9. * Jon Matousek
  10. */
  11. #include "_common.h"
  12. #include "_dispprt.h"
  13. #include "_edit.h"
  14. #include "_font.h"
  15. #include "_measure.h"
  16. #include "_render.h"
  17. #include "_select.h"
  18. #define PARA_NUMBER_NOT_SET ((WORD) -1)
  19. ASSERTDATA
  20. /*
  21. * CDisplayPrinter::CDisplayPrinter(ped, hdc, x, y, prtcon)
  22. *
  23. * @mfunc
  24. * Contructs a object that can be used to print a text control
  25. */
  26. CDisplayPrinter::CDisplayPrinter (
  27. CTxtEdit* ped,
  28. HDC hdc, //@parm HDC for drawing
  29. LONG x, //@parm Max width to draw
  30. LONG y, //@parm Max height to draw
  31. SPrintControl prtcon//@parm Special controls for this print object
  32. )
  33. : CDisplayML( ped ), _prtcon(prtcon)
  34. {
  35. TRACEBEGIN(TRCSUBSYSPRT, TRCSCOPEINTERN, "CDisplayPrinter::CDisplayPrinter");
  36. Assert ( hdc );
  37. _fNoUpdateView = TRUE;
  38. _xWidthMax = x;
  39. _yHeightMax = y;
  40. _wNumber = PARA_NUMBER_NOT_SET;
  41. }
  42. /*
  43. * CDisplayPrinter::SetPrintDimensions(prc)
  44. *
  45. * @mfunc
  46. * Set area to print.
  47. */
  48. void CDisplayPrinter::SetPrintDimensions(
  49. RECT *prc) //@parm dimensions of current area to print to.
  50. {
  51. _xWidthMax = prc->right - prc->left;
  52. _yHeightMax = prc->bottom - prc->top;
  53. }
  54. /*
  55. * CDisplayPrinter::FormatRange(cpFirst, cpMost)
  56. *
  57. * @mfunc
  58. * Format a range of text into this display and used only for printing.
  59. *
  60. * @rdesc
  61. * actual end of range position (updated)
  62. */
  63. LONG CDisplayPrinter::FormatRange(
  64. LONG cpFirst, //@parm Start of text range
  65. LONG cpMost, //@parm End of text range
  66. BOOL fWidowOrphanControl) //@parm If TRUE, suppress widow/orphan
  67. {
  68. TRACEBEGIN(TRCSUBSYSPRT, TRCSCOPEINTERN, "CDisplayPrinter::FormatRange");
  69. LONG cch;
  70. WCHAR ch;
  71. BOOL fFirstInPara = TRUE;
  72. CLine liTarget;
  73. CLine * pliNew = NULL;
  74. LONG yHeightRnd;
  75. LONG yHeightTgt;
  76. BOOL fBindCp = FALSE;
  77. const CDevDesc *pdd = GetDdTarget() ? GetDdTarget() : this;
  78. // Set client height for zooming
  79. _yHeightClient = this->LYtoDY(_yHeightMax);
  80. // Set maximum in terms of target DC.
  81. LONG yMax = pdd->LYtoDY(_yHeightMax);
  82. if(cpMost < 0)
  83. cpMost = _ped->GetTextLength();
  84. CMeasurer me(this);
  85. cpFirst = me.SetCp(cpFirst); // Validate cpFirst while setting me
  86. ch = me.GetChar();
  87. // TODO: COMPATIBILITY ISSUE: Richedit 1.0 adjusted to before a
  88. // CRLF/CRCRLF boundary. if_ped->fUseCRLF(), adjust accordingly
  89. if(fBindCp)
  90. {
  91. cpFirst = me.GetCp();
  92. me._rpCF.BindToCp(cpFirst);
  93. me._rpPF.BindToCp(cpFirst);
  94. }
  95. _cpMin = cpFirst;
  96. _cpFirstVisible = cpFirst;
  97. yHeightTgt = 0;
  98. yHeightRnd = 0;
  99. if(me.GetCp())
  100. fFirstInPara = me._rpTX.IsAfterEOP();
  101. // Clear line CArray
  102. Clear(AF_DELETEMEM);
  103. // Assume that we will break on words
  104. UINT uiBreakAtWord = MEASURE_BREAKATWORD;
  105. if(_prtcon._fPrintFromDraw)
  106. {
  107. // This is from Draw so we want to take inset into account
  108. LONG xWidthView = _xWidthMax;
  109. GetViewDim(xWidthView, yMax);
  110. _xWidthView = (SHORT) xWidthView;
  111. // Restore client height
  112. _yHeightClient = this->LYtoDY(_yHeightMax);
  113. }
  114. else // Message-based printing always does word wrap
  115. SetWordWrap(TRUE);
  116. // Set paragraph numbering. This is a fairly difficult problem
  117. // because printing can start anywhere and end anywhere. However,
  118. // most printing will involve a contiguous range of pages. Therefore,
  119. // we cache the paragraph number and the cp for that number and
  120. // only resort to looking in the line array if the cached information
  121. // has become invalid.
  122. if ((PARA_NUMBER_NOT_SET == _wNumber) || (cpFirst != _cpForNumber))
  123. {
  124. CLinePtr rp(_ped->_pdp);
  125. rp.RpSetCp(cpFirst, FALSE);
  126. _wNumber = rp.GetNumber();
  127. _cpForNumber = cpFirst;
  128. }
  129. me.SetNumber(_wNumber);
  130. while(me.GetCp() < cpMost)
  131. {
  132. // Add one new line
  133. pliNew = Add(1, NULL);
  134. if(!pliNew)
  135. {
  136. _ped->GetCallMgr()->SetOutOfMemory();
  137. goto err;
  138. }
  139. // Store the current number of the paragraph. We do it
  140. // here because we have to measure and that potentially
  141. // updates the number of the paragraph in the measurer
  142. // for a line that might not be on the page.
  143. _wNumber = me.GetNumber();
  144. // Stuff some text into this new line
  145. if(!pliNew->Measure(me, cpMost - me.GetCp(), -1,
  146. uiBreakAtWord | (fFirstInPara ? MEASURE_FIRSTINPARA : 0),
  147. &liTarget))
  148. {
  149. Assert(FALSE);
  150. goto err;
  151. }
  152. // Note, we always put at least one line on a page. Otherwise, if the
  153. // first line is too big, we would cause our client to infinite loop
  154. // because we would never advance the print cp.
  155. if(_cel > 1 && (yHeightTgt + liTarget._yHeight > yMax))
  156. {
  157. cch = -pliNew->_cch; // Bump last line to next page
  158. _cel--; // One less line
  159. #if 0
  160. CLine *pli = pliNew - 1; // Point at previous line
  161. // If this line and the previous one are in the same para and
  162. // either this one ends in an EOP or the previous one starts
  163. // a para, bump both to following page (widow/orphan)
  164. if(fWidowOrphanControl)
  165. {
  166. if(_cel > 1 && !fFirstInPara &&
  167. (pli->_bFlags & fliFirstInPara || (pliNew->_bFlags & fliHasEOP)))
  168. {
  169. cch -= pli->_cch;
  170. _cel--; // One less line
  171. pli--; // Point to previous line
  172. }
  173. if(_cel > 1 && pli->_nHeading)
  174. { // Don't end page with a heading
  175. cch -= pli->_cch;
  176. _cel--; // One less line
  177. }
  178. }
  179. #endif
  180. me.Advance(cch); // Move back over lines discarded
  181. break;
  182. }
  183. fFirstInPara = (pliNew->_bFlags & fliHasEOP);
  184. yHeightTgt += liTarget._yHeight;
  185. yHeightRnd += pliNew->_yHeight;
  186. if (me.GetPrevChar() == FF)
  187. break;
  188. }
  189. // If there was no text, then add a single blank line
  190. if(!pliNew)
  191. {
  192. pliNew = Add(1, NULL);
  193. if(!pliNew)
  194. {
  195. _ped->GetCallMgr()->SetOutOfMemory();
  196. goto err;
  197. }
  198. me.NewLine(fFirstInPara);
  199. *pliNew = me._li;
  200. }
  201. // Update display height
  202. _yHeight = yHeightRnd;
  203. // Update display width
  204. _xWidth = CalcDisplayWidth();
  205. cpMost = me.GetCp();
  206. _cpCalcMax = cpMost;
  207. _yCalcMax = _yHeight;
  208. // Update paragraph caching information.
  209. _cpForNumber = cpMost;
  210. return cpMost;
  211. err:
  212. Clear(AF_DELETEMEM);
  213. _xWidth = 0;
  214. _yHeight = 0;
  215. return -1;
  216. }
  217. /*
  218. * CDisplayPrinter::GetNaturalSize(hdcDraw, hicTarget, dwMode, pwidth, pheight)
  219. *
  220. * @mfunc
  221. * Recalculate display to input width & height for TXTNS_FITTOCONTENT.
  222. *
  223. * @rdesc
  224. * S_OK - Call completed successfully <nl>
  225. *
  226. * @devnote
  227. * This assumes that FormatRange was called just prior to this.
  228. */
  229. HRESULT CDisplayPrinter::GetNaturalSize(
  230. HDC hdcDraw, //@parm DC for drawing
  231. HDC hicTarget, //@parm DC for information
  232. DWORD dwMode, //@parm Type of natural size required
  233. LONG *pwidth, //@parm Width in device units to use for fitting
  234. LONG *pheight) //@parm Height in device units to use for fitting
  235. {
  236. TRACEBEGIN(TRCSUBSYSDISP, TRCSCOPEINTERN, "CDisplayPrinter::GetNaturalSize");
  237. *pwidth = _xWidth;
  238. *pheight = _yHeight;
  239. return S_OK;
  240. }
  241. /*
  242. * CDisplayPrinter::IsPrinter()
  243. *
  244. * @mfunc
  245. * Returns whether this is a printer
  246. *
  247. * @rdesc
  248. * TRUE - is a display to a printer
  249. * FALSE - is not a display to a printer
  250. */
  251. BOOL CDisplayPrinter::IsPrinter() const
  252. {
  253. AssertSz(_hdc, "CDisplayPrinter::IsPrinter no hdc set");
  254. return GetDeviceCaps(_hdc, TECHNOLOGY) == DT_RASPRINTER;
  255. }