dcprev.cpp 26 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988
  1. // This is a part of the Microsoft Foundation Classes C++ library.
  2. // Copyright (C) 1992-1998 Microsoft Corporation
  3. // All rights reserved.
  4. //
  5. // This source code is only intended as a supplement to the
  6. // Microsoft Foundation Classes Reference and related
  7. // electronic documentation provided with the library.
  8. // See these sources for detailed information regarding the
  9. // Microsoft Foundation Classes product.
  10. #include "stdafx.h"
  11. #ifdef AFX_PRINT_SEG
  12. #pragma code_seg(AFX_PRINT_SEG)
  13. #endif
  14. #ifdef _DEBUG
  15. #undef THIS_FILE
  16. static char THIS_FILE[] = __FILE__;
  17. #endif
  18. #define new DEBUG_NEW
  19. /////////////////////////////////////////////////////////////////////////////
  20. // Helper functions
  21. AFX_STATIC long AFXAPI _AfxMultMultDivDiv(
  22. int factor, int num1, int num2,
  23. int den1, int den2)
  24. {
  25. #ifdef _AFX_PORTABLE
  26. // make sure that (num1 * num2) does not overflow 31-bits.
  27. long temp = num1 < 0 ? -num1 : num1;
  28. for (int nBitsResult = 0; temp != 0; nBitsResult++)
  29. temp >>= 1;
  30. temp = num2 < 0 ? -num2 : num2;
  31. for (; temp != 0; nBitsResult++)
  32. temp >>= 1;
  33. if (nBitsResult > 31)
  34. {
  35. num1 >>= nBitsResult - 31;
  36. num2 >>= nBitsResult - 31;
  37. }
  38. // make sure that (den1 * den2) does not overflow 31-bits
  39. temp = den1 < 0 ? -den1 : den1;
  40. for (nBitsResult = 0; temp != 0; nBitsResult++)
  41. temp >>= 1;
  42. temp = den2 < 0 ? -den2 : den2;
  43. for (; temp != 0; nBitsResult++)
  44. temp >>= 1;
  45. if (nBitsResult > 31)
  46. {
  47. den1 >>= nBitsResult - 31;
  48. den2 >>= nBitsResult - 31;
  49. }
  50. long numerator = (long)num1 * (long)num2; // no overflow
  51. long denominator = (long)den1 * (long)den2; // no overflow
  52. #else
  53. __int64 numerator = (__int64)num1 * (__int64)num2; // no overflow
  54. __int64 denominator = (__int64)den1 * (__int64)den2; // no overflow
  55. __int64 temp;
  56. #endif
  57. temp = numerator < 0 ? -numerator : numerator;
  58. for (int nBitsInNum = 0; temp != 0; nBitsInNum++)
  59. temp >>= 1;
  60. temp = factor < 0 ? -factor : factor;
  61. for (int nBitsInFactor = 0; temp != 0; nBitsInFactor++)
  62. temp >>= 1;
  63. nBitsInNum += nBitsInFactor;
  64. //
  65. // normalizing the denominator to positive results in an easier
  66. // determination of whether there is overflow
  67. //
  68. if (denominator < 0)
  69. {
  70. denominator = -denominator;
  71. numerator = -numerator;
  72. }
  73. // Get the product of factor * numerator representable in a long/__int64
  74. // while distributing loss of presision across all three numerator terms
  75. // Adjust denominator as well
  76. //
  77. while (nBitsInNum-- > 31)
  78. {
  79. numerator >>= 1;
  80. denominator >>= 1;
  81. if (nBitsInNum-- <= 31)
  82. break;
  83. numerator >>= 1;
  84. denominator >>= 1;
  85. if (nBitsInNum-- <= 31)
  86. break;
  87. factor >>= 1;
  88. denominator >>= 1;
  89. }
  90. numerator *= factor;
  91. if (denominator == 0)
  92. return numerator < 0 ? LONG_MIN : LONG_MAX;
  93. return (long) ((numerator + denominator/2) / denominator);
  94. }
  95. /////////////////////////////////////////////////////////////////////////////
  96. // Print Preview DC (CPreviewDC)
  97. CPreviewDC::CPreviewDC()
  98. {
  99. // Initial scale factor and top-left offset
  100. m_nScaleNum = m_nScaleDen = 1;
  101. m_sizeTopLeft.cx = m_sizeTopLeft.cy = 8;
  102. m_hFont = m_hPrinterFont = NULL;
  103. }
  104. void CPreviewDC::SetOutputDC(HDC hDC)
  105. {
  106. ASSERT(hDC != NULL);
  107. m_nSaveDCIndex = ::SaveDC(hDC); // restore in ReleaseOutputDC()
  108. CDC::SetOutputDC(hDC);
  109. if (m_hAttribDC != NULL)
  110. {
  111. MirrorMappingMode(FALSE);
  112. if (m_hFont)
  113. ::SelectObject(m_hDC, m_hFont);
  114. else
  115. MirrorFont();
  116. MirrorAttributes();
  117. }
  118. }
  119. void CPreviewDC::ReleaseOutputDC()
  120. {
  121. ASSERT(m_hDC != NULL);
  122. ::RestoreDC(m_hDC, m_nSaveDCIndex); // Saved in SetOutputDC()
  123. CDC::ReleaseOutputDC();
  124. }
  125. void CPreviewDC::SetAttribDC(HDC hDC)
  126. {
  127. ASSERT(hDC != NULL);
  128. CDC::SetAttribDC(hDC);
  129. MirrorMappingMode(TRUE);
  130. MirrorFont();
  131. MirrorAttributes();
  132. }
  133. CPreviewDC::~CPreviewDC()
  134. {
  135. ASSERT(m_hDC == NULL); // Should not have a screen DC at this time
  136. AfxDeleteObject((HGDIOBJ*)&m_hFont);
  137. }
  138. void CPreviewDC::SetScaleRatio(int nNumerator, int nDenominator)
  139. {
  140. m_nScaleNum = nNumerator;
  141. m_nScaleDen = nDenominator;
  142. if (m_hAttribDC != NULL)
  143. {
  144. MirrorMappingMode(TRUE);
  145. MirrorFont();
  146. }
  147. }
  148. // Implementation support
  149. #ifdef _DEBUG
  150. void CPreviewDC::AssertValid() const
  151. {
  152. CDC::AssertValid();
  153. }
  154. void CPreviewDC::Dump(CDumpContext& dc) const
  155. {
  156. CDC::Dump(dc);
  157. dc << "Scale Factor: " << m_nScaleNum << "/" << m_nScaleDen;
  158. dc << "\n";
  159. }
  160. #endif
  161. int CPreviewDC::SaveDC()
  162. {
  163. ASSERT(m_hAttribDC != NULL);
  164. int nAttribIndex = ::SaveDC(m_hAttribDC);
  165. if (m_hDC != NULL)
  166. {
  167. // remove font from object
  168. ::SelectObject(m_hDC, GetStockObject(SYSTEM_FONT));
  169. m_nSaveDCDelta = ::SaveDC(m_hDC) - nAttribIndex;
  170. // Select font back in after save
  171. ::SelectObject(m_hDC, m_hFont);
  172. }
  173. else
  174. {
  175. m_nSaveDCDelta = 0x7fff; // impossibly high value
  176. }
  177. return nAttribIndex;
  178. }
  179. BOOL CPreviewDC::RestoreDC(int nSavedDC)
  180. {
  181. ASSERT(m_hAttribDC != NULL);
  182. BOOL bSuccess = ::RestoreDC(m_hAttribDC, nSavedDC);
  183. if (bSuccess)
  184. {
  185. if (m_nSaveDCDelta != 0x7fff)
  186. {
  187. ASSERT(m_hDC != NULL); // removed Output DC after save
  188. if (nSavedDC != -1)
  189. nSavedDC += m_nSaveDCDelta;
  190. bSuccess = ::RestoreDC(m_hDC, nSavedDC);
  191. MirrorFont(); // mirror the font
  192. }
  193. else
  194. {
  195. ASSERT(m_hDC == NULL); // Added the Output DC after save
  196. }
  197. }
  198. return bSuccess;
  199. }
  200. void CPreviewDC::MirrorAttributes()
  201. {
  202. ASSERT(m_hAttribDC != NULL);
  203. if (m_hDC != NULL)
  204. {
  205. // extract and re-set Pen and Brush
  206. HGDIOBJ hTemp = ::SelectObject(m_hAttribDC, ::GetStockObject(BLACK_PEN));
  207. ::SelectObject(m_hAttribDC, hTemp);
  208. ::SelectObject(m_hDC, hTemp);
  209. hTemp = ::SelectObject(m_hAttribDC, ::GetStockObject(BLACK_BRUSH));
  210. ::SelectObject(m_hAttribDC, hTemp);
  211. ::SelectObject(m_hDC, hTemp);
  212. SetROP2(GetROP2());
  213. SetBkMode(GetBkMode());
  214. SetTextAlign(GetTextAlign());
  215. SetPolyFillMode(GetPolyFillMode());
  216. SetStretchBltMode(GetStretchBltMode());
  217. SetTextColor(GetNearestColor(GetTextColor()));
  218. SetBkColor(GetNearestColor(GetBkColor()));
  219. }
  220. }
  221. CGdiObject* CPreviewDC::SelectStockObject(int nIndex)
  222. {
  223. ASSERT(m_hAttribDC != NULL);
  224. HGDIOBJ hObj = ::GetStockObject(nIndex);
  225. switch (nIndex)
  226. {
  227. case ANSI_FIXED_FONT:
  228. case ANSI_VAR_FONT:
  229. case DEVICE_DEFAULT_FONT:
  230. case OEM_FIXED_FONT:
  231. case SYSTEM_FONT:
  232. case SYSTEM_FIXED_FONT:
  233. case DEFAULT_GUI_FONT:
  234. // Handle the stock fonts correctly
  235. {
  236. CGdiObject* pObject = CGdiObject::FromHandle(
  237. ::SelectObject(m_hAttribDC, hObj));
  238. // Don't re-mirror screen font if this is the same font.
  239. if (m_hPrinterFont == (HFONT) hObj)
  240. return pObject;
  241. m_hPrinterFont = (HFONT) hObj;
  242. ASSERT(m_hPrinterFont != NULL); // Do not allow infinite recursion
  243. MirrorFont();
  244. return pObject;
  245. }
  246. default:
  247. if (m_hDC != NULL)
  248. ::SelectObject(m_hDC, hObj);
  249. return CGdiObject::FromHandle(::SelectObject(m_hAttribDC, hObj));
  250. }
  251. }
  252. void CPreviewDC::MirrorFont()
  253. {
  254. if (m_hAttribDC == NULL)
  255. return; // Can't do anything without Attrib DC
  256. if (m_hPrinterFont == NULL)
  257. {
  258. SelectStockObject(DEVICE_DEFAULT_FONT); // will recurse
  259. return;
  260. }
  261. if (m_hDC == NULL)
  262. return; // can't mirror font without a screen DC
  263. LOGFONT logFont;
  264. // Fill the logFont structure with the original info
  265. ::GetObject(m_hPrinterFont, sizeof(LOGFONT), (LPVOID)&logFont);
  266. TEXTMETRIC tm;
  267. GetTextFace(LF_FACESIZE, (LPTSTR)&logFont.lfFaceName[0]);
  268. GetTextMetrics(&tm);
  269. // Set real values based on the Printer's text metrics.
  270. if (tm.tmHeight < 0)
  271. logFont.lfHeight = tm.tmHeight;
  272. else
  273. logFont.lfHeight = -(tm.tmHeight - tm.tmInternalLeading);
  274. logFont.lfWidth = tm.tmAveCharWidth;
  275. logFont.lfWeight = tm.tmWeight;
  276. logFont.lfItalic = tm.tmItalic;
  277. logFont.lfUnderline = tm.tmUnderlined;
  278. logFont.lfStrikeOut = tm.tmStruckOut;
  279. logFont.lfCharSet = tm.tmCharSet;
  280. logFont.lfPitchAndFamily = tm.tmPitchAndFamily;
  281. HFONT hNewFont = ::CreateFontIndirect(&logFont);
  282. ::SelectObject(m_hDC, hNewFont);
  283. ::GetTextMetrics(m_hDC, &tm);
  284. // Is the displayed font too large?
  285. int cyDesired = -logFont.lfHeight;
  286. int cyActual;
  287. if (tm.tmHeight < 0)
  288. cyActual = -tm.tmHeight;
  289. else
  290. cyActual = tm.tmHeight - tm.tmInternalLeading;
  291. CSize sizeWinExt;
  292. VERIFY(::GetWindowExtEx(m_hDC, &sizeWinExt));
  293. CSize sizeVpExt;
  294. VERIFY(::GetViewportExtEx(m_hDC, &sizeVpExt));
  295. // Only interested in Extent Magnitudes, not direction
  296. if (sizeWinExt.cy < 0)
  297. sizeWinExt.cy = -sizeWinExt.cy;
  298. if (sizeVpExt.cy < 0)
  299. sizeVpExt.cy = -sizeVpExt.cy;
  300. // Convert to screen device coordinates to eliminate rounding
  301. // errors as a source of SmallFont aliasing
  302. cyDesired = MulDiv(cyDesired, sizeVpExt.cy, sizeWinExt.cy);
  303. cyActual = MulDiv(cyActual, sizeVpExt.cy, sizeWinExt.cy);
  304. ASSERT(cyDesired >= 0 && cyActual >= 0);
  305. if (cyDesired < cyActual)
  306. {
  307. logFont.lfFaceName[0] = 0; // let the mapper find a good fit
  308. if ((logFont.lfPitchAndFamily & 0xf0) == FF_DECORATIVE)
  309. logFont.lfPitchAndFamily = DEFAULT_PITCH | FF_DECORATIVE;
  310. else
  311. logFont.lfPitchAndFamily = DEFAULT_PITCH | FF_DONTCARE;
  312. HFONT hTempFont = ::CreateFontIndirect(&logFont);
  313. ::SelectObject(m_hDC, hTempFont); // Select it in.
  314. ::DeleteObject(hNewFont);
  315. hNewFont = hTempFont;
  316. }
  317. AfxDeleteObject((HGDIOBJ*)&m_hFont); // delete the old logical font
  318. m_hFont = hNewFont; // save the new one
  319. }
  320. CFont* CPreviewDC::SelectObject(CFont* pFont)
  321. {
  322. if (pFont == NULL)
  323. return NULL;
  324. ASSERT(m_hAttribDC != NULL);
  325. ASSERT_VALID(pFont);
  326. CFont* pOldFont = (CFont*) CGdiObject::FromHandle(
  327. ::SelectObject(m_hAttribDC, pFont->m_hObject));
  328. // If same as already selected, don't re-mirror screen font
  329. if (m_hPrinterFont != pFont->m_hObject)
  330. {
  331. m_hPrinterFont = (HFONT)pFont->m_hObject;
  332. MirrorFont();
  333. }
  334. return pOldFont;
  335. }
  336. /////////////////////////////////////////////////////////////////////////////
  337. // Drawing-Attribute Functions
  338. COLORREF CPreviewDC::SetBkColor(COLORREF crColor)
  339. {
  340. ASSERT(m_hAttribDC != NULL);
  341. if (m_hDC != NULL)
  342. ::SetBkColor(m_hDC, ::GetNearestColor(m_hAttribDC, crColor));
  343. return ::SetBkColor(m_hAttribDC, crColor);
  344. }
  345. COLORREF CPreviewDC::SetTextColor(COLORREF crColor)
  346. {
  347. ASSERT(m_hAttribDC != NULL);
  348. if (m_hDC != NULL)
  349. ::SetTextColor(m_hDC, ::GetNearestColor(m_hAttribDC, crColor));
  350. return ::SetTextColor(m_hAttribDC, crColor);
  351. }
  352. int CPreviewDC::SetMapMode(int nMapMode)
  353. {
  354. ASSERT(m_hAttribDC != NULL);
  355. int nModeOld = ::SetMapMode(m_hAttribDC, nMapMode);
  356. MirrorMappingMode(TRUE);
  357. return nModeOld;
  358. }
  359. CPoint CPreviewDC::SetViewportOrg(int x, int y)
  360. {
  361. ASSERT(m_hAttribDC != NULL);
  362. CPoint ptOrgOld;
  363. VERIFY(::SetViewportOrgEx(m_hAttribDC, x, y, &ptOrgOld));
  364. MirrorViewportOrg();
  365. return ptOrgOld;
  366. }
  367. CPoint CPreviewDC::OffsetViewportOrg(int nWidth, int nHeight)
  368. {
  369. ASSERT(m_hAttribDC != NULL);
  370. CPoint ptOrgOld;
  371. VERIFY(::OffsetViewportOrgEx(m_hAttribDC, nWidth, nHeight, &ptOrgOld));
  372. MirrorViewportOrg();
  373. return ptOrgOld;
  374. }
  375. CSize CPreviewDC::SetViewportExt(int x, int y)
  376. {
  377. ASSERT(m_hAttribDC != NULL);
  378. CSize sizeExtOld;
  379. VERIFY(::SetViewportExtEx(m_hAttribDC, x, y, &sizeExtOld));
  380. MirrorMappingMode(TRUE);
  381. return sizeExtOld;
  382. }
  383. CSize CPreviewDC::ScaleViewportExt(int xNum, int xDenom, int yNum, int yDenom)
  384. {
  385. ASSERT(m_hAttribDC != NULL);
  386. CSize sizeExtOld;
  387. VERIFY(::ScaleViewportExtEx(m_hAttribDC, xNum, xDenom,
  388. yNum, yDenom, &sizeExtOld));
  389. MirrorMappingMode(TRUE);
  390. return sizeExtOld;
  391. }
  392. CSize CPreviewDC::SetWindowExt(int x, int y)
  393. {
  394. ASSERT(m_hAttribDC != NULL);
  395. CSize sizeExtOld;
  396. VERIFY(::SetWindowExtEx(m_hAttribDC, x, y, &sizeExtOld));
  397. MirrorMappingMode(TRUE);
  398. return sizeExtOld;
  399. }
  400. CSize CPreviewDC::ScaleWindowExt(int xNum, int xDenom, int yNum, int yDenom)
  401. {
  402. ASSERT(m_hAttribDC != NULL);
  403. CSize sizeExtOld;
  404. VERIFY(::ScaleWindowExtEx(m_hAttribDC, xNum, xDenom, yNum, yDenom,
  405. &sizeExtOld));
  406. MirrorMappingMode(TRUE);
  407. return sizeExtOld;
  408. }
  409. /////////////////////////////////////////////////////////////////////////////
  410. // Text Functions
  411. // private helpers for TextOut functions
  412. AFX_STATIC int AFXAPI _AfxComputeNextTab(int x, UINT nTabStops, LPINT lpnTabStops,
  413. int nTabOrigin, int nTabWidth)
  414. {
  415. x -= nTabOrigin; // normalize position to tab origin
  416. for (UINT i = 0; i < nTabStops; i++, lpnTabStops++)
  417. {
  418. if (*lpnTabStops > x)
  419. return *lpnTabStops + nTabOrigin;
  420. }
  421. return (x / nTabWidth + 1) * nTabWidth + nTabOrigin;
  422. }
  423. // Compute a character delta table for correctly positioning the screen
  424. // font characters where the printer characters will appear on the page
  425. CSize CPreviewDC::ComputeDeltas(int& x, LPCTSTR lpszString, UINT &nCount,
  426. BOOL bTabbed, UINT nTabStops, LPINT lpnTabStops, int nTabOrigin,
  427. LPTSTR lpszOutputString, int* pnDxWidths, int& nRightFixup)
  428. {
  429. ASSERT_VALID(this);
  430. TEXTMETRIC tmAttrib;
  431. TEXTMETRIC tmScreen;
  432. ::GetTextMetrics(m_hAttribDC, &tmAttrib);
  433. ::GetTextMetrics(m_hDC, &tmScreen);
  434. CSize sizeExtent;
  435. ::GetTextExtentPoint32A(m_hAttribDC, "A", 1, &sizeExtent);
  436. CPoint ptCurrent;
  437. UINT nAlignment = ::GetTextAlign(m_hAttribDC);
  438. BOOL bUpdateCP = (nAlignment & TA_UPDATECP) != 0;
  439. if (bUpdateCP)
  440. {
  441. ::GetCurrentPositionEx(m_hDC, &ptCurrent);
  442. x = ptCurrent.x;
  443. }
  444. LPCTSTR lpszCurChar = lpszString;
  445. LPCTSTR lpszStartRun = lpszString;
  446. int* pnCurDelta = pnDxWidths;
  447. int nStartRunPos = x;
  448. int nCurrentPos = x;
  449. int nStartOffset = 0;
  450. int nTabWidth = 0;
  451. if (bTabbed)
  452. {
  453. if (nTabStops == 1)
  454. {
  455. nTabWidth = lpnTabStops[0];
  456. }
  457. else
  458. {
  459. // Get default size of a tab
  460. nTabWidth = LOWORD(::GetTabbedTextExtentA(m_hAttribDC,
  461. "\t", 1, 0, NULL));
  462. }
  463. }
  464. for (UINT i = 0; i < nCount; i++)
  465. {
  466. BOOL bSpace = ((_TUCHAR)*lpszCurChar == (_TUCHAR)tmAttrib.tmBreakChar);
  467. if (bSpace || (bTabbed && *lpszCurChar == '\t'))
  468. {
  469. // bSpace will be either TRUE (==1) or FALSE (==0). For spaces
  470. // we want the space included in the GetTextExtent, for tabs we
  471. // do not want the tab included
  472. int nRunLength = (int)(lpszCurChar - lpszStartRun) + bSpace;
  473. CSize sizeExtent;
  474. ::GetTextExtentPoint32(m_hAttribDC, lpszStartRun, nRunLength,
  475. &sizeExtent);
  476. int nNewPos = nStartRunPos + sizeExtent.cx
  477. - tmAttrib.tmOverhang;
  478. // now, if this is a Tab (!bSpace), compute the next tab stop
  479. if (!bSpace)
  480. {
  481. nNewPos = _AfxComputeNextTab(nNewPos, nTabStops, lpnTabStops,
  482. nTabOrigin, nTabWidth);
  483. }
  484. // Add this width to previous width
  485. if (pnCurDelta == pnDxWidths)
  486. nStartOffset += nNewPos - nCurrentPos;
  487. else
  488. *(pnCurDelta-1) += nNewPos - nCurrentPos;
  489. nCurrentPos = nNewPos;
  490. nStartRunPos = nCurrentPos; // set start of run
  491. // *lpszCurChar must be SBC: tmBreakChar or '\t'
  492. lpszStartRun = lpszCurChar + 1;
  493. }
  494. else
  495. {
  496. // For the non-tabbed or non-tab-character case
  497. int cxScreen;
  498. if (_istlead(*lpszCurChar))
  499. {
  500. cxScreen = tmScreen.tmAveCharWidth;
  501. *pnCurDelta = tmAttrib.tmAveCharWidth;
  502. }
  503. else
  504. {
  505. ::GetCharWidth(m_hDC, (_TUCHAR)*lpszCurChar,
  506. (_TUCHAR)*lpszCurChar, &cxScreen);
  507. if (!::GetCharWidth(m_hAttribDC, (_TUCHAR)*lpszCurChar,
  508. (_TUCHAR)*lpszCurChar, pnCurDelta))
  509. {
  510. // If printer driver fails the above call, use the average width
  511. *pnCurDelta = tmAttrib.tmAveCharWidth;
  512. }
  513. }
  514. *pnCurDelta -= tmAttrib.tmOverhang;
  515. cxScreen -= tmScreen.tmOverhang;
  516. nCurrentPos += *pnCurDelta; // update current position
  517. // Center character in allotted space
  518. if (pnCurDelta != pnDxWidths)
  519. {
  520. int diff = (*pnCurDelta - cxScreen) / 2;
  521. *pnCurDelta -= diff;
  522. *(pnCurDelta - 1) += diff;
  523. }
  524. *lpszOutputString++ = *lpszCurChar;
  525. if (_istlead(*lpszCurChar))
  526. {
  527. *lpszOutputString++ = *(lpszCurChar+1); // copy trailing byte
  528. *(pnCurDelta + 1) = *pnCurDelta; // double wide
  529. nCurrentPos += *pnCurDelta;
  530. pnCurDelta++;
  531. i++;
  532. }
  533. pnCurDelta++;
  534. }
  535. lpszCurChar = _tcsinc(lpszCurChar);
  536. }
  537. nAlignment &= TA_CENTER|TA_RIGHT;
  538. sizeExtent.cx = nCurrentPos - x;
  539. nRightFixup = 0;
  540. if (nAlignment == TA_LEFT)
  541. x += nStartOffset; // Full left side adjustment
  542. else if (nAlignment == TA_CENTER)
  543. x += nStartOffset/2; // Adjust Center by 1/2 left side adjustment
  544. else if (nAlignment == TA_RIGHT)
  545. nRightFixup = nStartOffset; // Right adjust needed later if TA_UPDATECP
  546. if (bUpdateCP)
  547. ::MoveToEx(m_hDC, x, ptCurrent.y, NULL);
  548. nCount = (UINT)(pnCurDelta - pnDxWidths); // number of characters output
  549. return sizeExtent;
  550. }
  551. BOOL CPreviewDC::TextOut(int x, int y, LPCTSTR lpszString, int nCount)
  552. {
  553. return ExtTextOut(x, y, 0, NULL, lpszString, nCount, NULL);
  554. }
  555. BOOL CPreviewDC::ExtTextOut(int x, int y, UINT nOptions, LPCRECT lpRect,
  556. LPCTSTR lpszString, UINT nCount, LPINT lpDxWidths)
  557. {
  558. ASSERT(m_hDC != NULL);
  559. ASSERT(m_hAttribDC != NULL);
  560. ASSERT(lpszString != NULL);
  561. ASSERT(lpDxWidths == NULL ||
  562. AfxIsValidAddress(lpDxWidths, sizeof(int) * nCount, FALSE));
  563. ASSERT(AfxIsValidAddress(lpszString, nCount, FALSE));
  564. int* pDeltas = NULL;
  565. LPTSTR pOutputString = NULL;
  566. int nRightFixup = 0;
  567. if (lpDxWidths == NULL)
  568. {
  569. if (nCount == 0) // Do nothing
  570. return TRUE;
  571. TRY
  572. {
  573. pDeltas = new int[nCount];
  574. pOutputString = new TCHAR[nCount];
  575. }
  576. CATCH_ALL(e)
  577. {
  578. delete[] pDeltas; // in case it was allocated
  579. // Note: DELETE_EXCEPTION(e) not required
  580. return FALSE; // Could not allocate buffer, cannot display
  581. }
  582. END_CATCH_ALL
  583. ComputeDeltas(x, (LPTSTR)lpszString, nCount, FALSE, 0, NULL, 0,
  584. pOutputString, pDeltas, nRightFixup);
  585. lpDxWidths = pDeltas;
  586. lpszString = pOutputString;
  587. }
  588. BOOL bSuccess = ::ExtTextOut(m_hDC, x, y, nOptions, lpRect, lpszString,
  589. nCount, lpDxWidths);
  590. if (nRightFixup != 0 && bSuccess && (GetTextAlign() & TA_UPDATECP))
  591. {
  592. CPoint pt;
  593. ::GetCurrentPositionEx(m_hDC, &pt);
  594. MoveTo(pt.x - nRightFixup, pt.y);
  595. }
  596. delete[] pDeltas;
  597. delete[] pOutputString;
  598. return bSuccess;
  599. }
  600. CSize CPreviewDC::TabbedTextOut(int x, int y, LPCTSTR lpszString, int nCount,
  601. int nTabPositions, LPINT lpnTabStopPositions, int nTabOrigin)
  602. {
  603. ASSERT(m_hAttribDC != NULL);
  604. ASSERT(m_hDC != NULL);
  605. ASSERT(lpszString != NULL);
  606. ASSERT(AfxIsValidAddress(lpszString, nCount, FALSE));
  607. ASSERT(lpnTabStopPositions == NULL ||
  608. AfxIsValidAddress(lpnTabStopPositions, sizeof(int) * nTabPositions,
  609. FALSE));
  610. if (nCount <= 0)
  611. return 0; // nCount is zero, there is nothing to print
  612. int* pDeltas = NULL;
  613. LPTSTR pOutputString = NULL;
  614. int nRightFixup;
  615. TRY
  616. {
  617. pDeltas = new int[nCount];
  618. pOutputString = new TCHAR[nCount];
  619. }
  620. CATCH_ALL(e)
  621. {
  622. delete[] pDeltas;
  623. // Note: DELETE_EXCEPTION(e) not required
  624. return 0; // signify error
  625. }
  626. END_CATCH_ALL
  627. UINT uCount = nCount;
  628. CSize sizeFinalExtent = ComputeDeltas(x, lpszString, uCount, TRUE,
  629. nTabPositions, lpnTabStopPositions, nTabOrigin,
  630. pOutputString, pDeltas, nRightFixup);
  631. BOOL bSuccess = ExtTextOut(x, y, 0, NULL, pOutputString, uCount, pDeltas);
  632. delete[] pDeltas;
  633. delete[] pOutputString;
  634. if (bSuccess && (GetTextAlign() & TA_UPDATECP))
  635. {
  636. CPoint pt;
  637. ::GetCurrentPositionEx(m_hDC, &pt);
  638. MoveTo(pt.x - nRightFixup, pt.y);
  639. }
  640. return sizeFinalExtent;
  641. }
  642. // This one is too complicated to do character-by-character output positioning
  643. // All we really need to do here is mirror the current position
  644. int CPreviewDC::DrawText(LPCTSTR lpszString, int nCount, LPRECT lpRect,
  645. UINT nFormat)
  646. {
  647. ASSERT(m_hAttribDC != NULL);
  648. ASSERT(m_hDC != NULL);
  649. ASSERT(lpszString != NULL);
  650. ASSERT(lpRect != NULL);
  651. ASSERT(AfxIsValidAddress(lpRect, sizeof(RECT)));
  652. ASSERT(nCount == -1 ?
  653. AfxIsValidString(lpszString) :
  654. AfxIsValidAddress(lpszString, nCount, FALSE));
  655. int retVal = ::DrawText(m_hDC, lpszString, nCount, lpRect, nFormat);
  656. CPoint pos;
  657. ::GetCurrentPositionEx(m_hDC, &pos);
  658. ::MoveToEx(m_hAttribDC, pos.x, pos.y, NULL);
  659. return retVal;
  660. }
  661. BOOL CPreviewDC::GrayString(CBrush*,
  662. BOOL (CALLBACK *)(HDC, LPARAM, int),
  663. LPARAM lpData, int nCount, int x, int y, int, int)
  664. {
  665. TRACE0("TextOut() substituted for GrayString() in Print Preview.\n");
  666. return TextOut(x, y, (LPCTSTR)lpData, nCount);
  667. }
  668. int CPreviewDC::Escape(int nEscape, int nCount, LPCSTR lpszInData, void* lpOutData)
  669. {
  670. // The tact here is to NOT allow any of the document control escapes
  671. // to be passed through. Elimination of StartDoc and EndDoc should
  672. // eliminate anything actually going to the printer. Also anything
  673. // that actually draws something will be filtered.
  674. ASSERT(m_hAttribDC != NULL);
  675. switch (nEscape)
  676. {
  677. case NEXTBAND:
  678. case SETCOLORTABLE:
  679. case GETCOLORTABLE:
  680. case FLUSHOUTPUT:
  681. case DRAFTMODE:
  682. case QUERYESCSUPPORT:
  683. case GETPHYSPAGESIZE:
  684. case GETPRINTINGOFFSET:
  685. case GETSCALINGFACTOR:
  686. case GETPENWIDTH:
  687. case SETCOPYCOUNT:
  688. case SELECTPAPERSOURCE:
  689. case GETTECHNOLOGY:
  690. case SETLINECAP:
  691. case SETLINEJOIN:
  692. case SETMITERLIMIT:
  693. case BANDINFO:
  694. case GETVECTORPENSIZE:
  695. case GETVECTORBRUSHSIZE:
  696. case ENABLEDUPLEX:
  697. case GETSETPAPERBINS:
  698. case GETSETPRINTORIENT:
  699. case ENUMPAPERBINS:
  700. case SETDIBSCALING:
  701. case ENUMPAPERMETRICS:
  702. case GETSETPAPERMETRICS:
  703. case GETEXTENDEDTEXTMETRICS:
  704. case GETEXTENTTABLE:
  705. case GETPAIRKERNTABLE:
  706. case GETTRACKKERNTABLE:
  707. case ENABLERELATIVEWIDTHS:
  708. case ENABLEPAIRKERNING:
  709. case SETKERNTRACK:
  710. case SETALLJUSTVALUES:
  711. case SETCHARSET:
  712. case SET_BACKGROUND_COLOR:
  713. case SET_SCREEN_ANGLE:
  714. case SET_SPREAD:
  715. return ::Escape(m_hAttribDC, nEscape, nCount, lpszInData, lpOutData);
  716. default:
  717. return 0;
  718. }
  719. }
  720. void CPreviewDC::MirrorMappingMode(BOOL bCompute)
  721. {
  722. ASSERT(m_hAttribDC != NULL);
  723. if (bCompute)
  724. {
  725. //
  726. // The following formula is used to compute the screen's viewport extent
  727. // From the printer and screen information and the Printer's Viewport
  728. // Extents. (Note: This formula is used twice, once for horizontal
  729. // and once for vertical)
  730. //
  731. // It is assumed that the Window Extents are maintained as equal.
  732. //
  733. // m * LogPixPerInch(Screen) * VpExt(Printer)
  734. // VpExt(Screen) = -------------------------------------------------
  735. // n * LogPixPerInch(Printer)
  736. //
  737. // Where m/n is the scaling factor. (m/n > 1 is expansion)
  738. //
  739. VERIFY(::GetViewportExtEx(m_hAttribDC, &m_sizeVpExt));
  740. VERIFY(::GetWindowExtEx(m_hAttribDC, &m_sizeWinExt));
  741. while (m_sizeWinExt.cx > -0x4000 && m_sizeWinExt.cx < 0x4000 &&
  742. m_sizeVpExt.cx > -0x4000 && m_sizeVpExt.cx < 0x4000)
  743. {
  744. m_sizeWinExt.cx <<= 1;
  745. m_sizeVpExt.cx <<= 1;
  746. }
  747. while (m_sizeWinExt.cy > -0x4000 && m_sizeWinExt.cy < 0x4000 &&
  748. m_sizeVpExt.cy > -0x4000 && m_sizeVpExt.cy < 0x4000)
  749. {
  750. m_sizeWinExt.cy <<= 1;
  751. m_sizeVpExt.cy <<= 1;
  752. }
  753. long lTempExt = _AfxMultMultDivDiv(m_sizeVpExt.cx,
  754. m_nScaleNum, afxData.cxPixelsPerInch,
  755. m_nScaleDen, ::GetDeviceCaps(m_hAttribDC, LOGPIXELSX));
  756. ASSERT(m_sizeWinExt.cx != 0);
  757. m_sizeVpExt.cx = (int)lTempExt;
  758. lTempExt = _AfxMultMultDivDiv(m_sizeVpExt.cy,
  759. m_nScaleNum, afxData.cyPixelsPerInch,
  760. m_nScaleDen, ::GetDeviceCaps(m_hAttribDC, LOGPIXELSY));
  761. ASSERT(m_sizeWinExt.cy != 0);
  762. m_sizeVpExt.cy = (int)lTempExt;
  763. }
  764. if (m_hDC != NULL)
  765. {
  766. ::SetMapMode(m_hDC, MM_ANISOTROPIC);
  767. ::SetWindowExtEx(m_hDC, m_sizeWinExt.cx, m_sizeWinExt.cy, NULL);
  768. ::SetViewportExtEx(m_hDC, m_sizeVpExt.cx, m_sizeVpExt.cy, NULL);
  769. // Now that the Logical Units are synchronized, we can set the Viewport Org
  770. MirrorViewportOrg();
  771. }
  772. }
  773. void CPreviewDC::MirrorViewportOrg()
  774. {
  775. if (m_hAttribDC == NULL || m_hDC == NULL)
  776. return;
  777. CPoint ptVpOrg;
  778. VERIFY(::GetViewportOrgEx(m_hAttribDC, &ptVpOrg));
  779. PrinterDPtoScreenDP(&ptVpOrg);
  780. ptVpOrg += m_sizeTopLeft;
  781. ::SetViewportOrgEx(m_hDC, ptVpOrg.x, ptVpOrg.y, NULL);
  782. CPoint ptWinOrg;
  783. VERIFY(::GetWindowOrgEx(m_hAttribDC, &ptWinOrg));
  784. ::SetWindowOrgEx(m_hDC, ptWinOrg.x, ptWinOrg.y, NULL);
  785. }
  786. void CPreviewDC::SetTopLeftOffset(CSize sizeTopLeft)
  787. {
  788. ASSERT(m_hAttribDC != NULL);
  789. m_sizeTopLeft = sizeTopLeft;
  790. MirrorViewportOrg();
  791. }
  792. void CPreviewDC::ClipToPage()
  793. {
  794. ASSERT(m_hAttribDC != NULL);
  795. ASSERT(m_hDC != NULL);
  796. // Create a rect in Screen Device coordinates that is one pixel larger
  797. // on all sides than the actual page. This is to hide the fact that
  798. // the printer to screen mapping mode is approximate and may result
  799. // in rounding error.
  800. CPoint pt(::GetDeviceCaps(m_hAttribDC, HORZRES),
  801. ::GetDeviceCaps(m_hAttribDC, VERTRES));
  802. PrinterDPtoScreenDP(&pt);
  803. // Set the screen dc to MM_TEXT and no WindowOrg for the interesection
  804. ::SetMapMode(m_hDC, MM_TEXT);
  805. ::SetWindowOrgEx(m_hDC, 0, 0, NULL);
  806. ::SetViewportOrgEx(m_hDC, m_sizeTopLeft.cx, m_sizeTopLeft.cy, NULL);
  807. ::IntersectClipRect(m_hDC, -1, -1, pt.x + 2, pt.y + 2);
  808. // Resynchronize the mapping mode
  809. MirrorMappingMode(FALSE);
  810. }
  811. // these conversion functions can be used without an attached screen DC
  812. void CPreviewDC::PrinterDPtoScreenDP(LPPOINT lpPoint) const
  813. {
  814. ASSERT(m_hAttribDC != NULL);
  815. CSize sizePrinterVpExt;
  816. VERIFY(::GetViewportExtEx(m_hAttribDC, &sizePrinterVpExt));
  817. CSize sizePrinterWinExt;
  818. VERIFY(::GetWindowExtEx(m_hAttribDC, &sizePrinterWinExt));
  819. long xScreen = _AfxMultMultDivDiv(lpPoint->x,
  820. sizePrinterWinExt.cx, m_sizeVpExt.cx,
  821. sizePrinterVpExt.cx, m_sizeWinExt.cx);
  822. lpPoint->x = (int)xScreen;
  823. long yScreen = _AfxMultMultDivDiv(lpPoint->y,
  824. sizePrinterWinExt.cy, m_sizeVpExt.cy,
  825. sizePrinterVpExt.cy, m_sizeWinExt.cy);
  826. lpPoint->y = (int)yScreen;
  827. }
  828. #ifdef AFX_INIT_SEG
  829. #pragma code_seg(AFX_INIT_SEG)
  830. #endif
  831. IMPLEMENT_DYNAMIC(CPreviewDC, CDC)
  832. /////////////////////////////////////////////////////////////////////////////