home *** CD-ROM | disk | FTP | other *** search
/ Liren Large Software Subsidy 7 / 07.iso / c / c480 / 18.ddi / MFC / SRC / DCPREV.CP_ / DCPREV.CP
Encoding:
Text File  |  1993-02-08  |  24.1 KB  |  951 lines

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