home *** CD-ROM | disk | FTP | other *** search
/ Supercompiler 1997 / SUPERCOMPILER97.iso / MS_VC.50 / VC / MFC / SRC / DCPREV.CPP < prev    next >
Encoding:
C/C++ Source or Header  |  1996-10-30  |  26.0 KB  |  1,000 lines

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