📄 dcprev.cpp
字号:
// This is a part of the Microsoft Foundation Classes C++ library.
// Copyright (C) 1992-1998 Microsoft Corporation
// All rights reserved.
//
// This source code is only intended as a supplement to the
// Microsoft Foundation Classes Reference and related
// electronic documentation provided with the library.
// See these sources for detailed information regarding the
// Microsoft Foundation Classes product.
#include "stdafx.h"
#ifdef AFX_PRINT_SEG
#pragma code_seg(AFX_PRINT_SEG)
#endif
#ifdef _DEBUG
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif
#define new DEBUG_NEW
/////////////////////////////////////////////////////////////////////////////
// Helper functions
AFX_STATIC long AFXAPI _AfxMultMultDivDiv(
int factor, int num1, int num2,
int den1, int den2)
{
#ifdef _AFX_PORTABLE
// make sure that (num1 * num2) does not overflow 31-bits.
long temp = num1 < 0 ? -num1 : num1;
for (int nBitsResult = 0; temp != 0; nBitsResult++)
temp >>= 1;
temp = num2 < 0 ? -num2 : num2;
for (; temp != 0; nBitsResult++)
temp >>= 1;
if (nBitsResult > 31)
{
num1 >>= nBitsResult - 31;
num2 >>= nBitsResult - 31;
}
// make sure that (den1 * den2) does not overflow 31-bits
temp = den1 < 0 ? -den1 : den1;
for (nBitsResult = 0; temp != 0; nBitsResult++)
temp >>= 1;
temp = den2 < 0 ? -den2 : den2;
for (; temp != 0; nBitsResult++)
temp >>= 1;
if (nBitsResult > 31)
{
den1 >>= nBitsResult - 31;
den2 >>= nBitsResult - 31;
}
long numerator = (long)num1 * (long)num2; // no overflow
long denominator = (long)den1 * (long)den2; // no overflow
#else
__int64 numerator = (__int64)num1 * (__int64)num2; // no overflow
__int64 denominator = (__int64)den1 * (__int64)den2; // no overflow
__int64 temp;
#endif
temp = numerator < 0 ? -numerator : numerator;
for (int nBitsInNum = 0; temp != 0; nBitsInNum++)
temp >>= 1;
temp = factor < 0 ? -factor : factor;
for (int nBitsInFactor = 0; temp != 0; nBitsInFactor++)
temp >>= 1;
nBitsInNum += nBitsInFactor;
//
// normalizing the denominator to positive results in an easier
// determination of whether there is overflow
//
if (denominator < 0)
{
denominator = -denominator;
numerator = -numerator;
}
// Get the product of factor * numerator representable in a long/__int64
// while distributing loss of presision across all three numerator terms
// Adjust denominator as well
//
while (nBitsInNum-- > 31)
{
numerator >>= 1;
denominator >>= 1;
if (nBitsInNum-- <= 31)
break;
numerator >>= 1;
denominator >>= 1;
if (nBitsInNum-- <= 31)
break;
factor >>= 1;
denominator >>= 1;
}
numerator *= factor;
if (denominator == 0)
return numerator < 0 ? LONG_MIN : LONG_MAX;
return (long) ((numerator + denominator/2) / denominator);
}
/////////////////////////////////////////////////////////////////////////////
// Print Preview DC (CPreviewDC)
CPreviewDC::CPreviewDC()
{
// Initial scale factor and top-left offset
m_nScaleNum = m_nScaleDen = 1;
m_sizeTopLeft.cx = m_sizeTopLeft.cy = 8;
m_hFont = m_hPrinterFont = NULL;
}
void CPreviewDC::SetOutputDC(HDC hDC)
{
ASSERT(hDC != NULL);
m_nSaveDCIndex = ::SaveDC(hDC); // restore in ReleaseOutputDC()
CDC::SetOutputDC(hDC);
if (m_hAttribDC != NULL)
{
MirrorMappingMode(FALSE);
if (m_hFont)
::SelectObject(m_hDC, m_hFont);
else
MirrorFont();
MirrorAttributes();
}
}
void CPreviewDC::ReleaseOutputDC()
{
ASSERT(m_hDC != NULL);
::RestoreDC(m_hDC, m_nSaveDCIndex); // Saved in SetOutputDC()
CDC::ReleaseOutputDC();
}
void CPreviewDC::SetAttribDC(HDC hDC)
{
ASSERT(hDC != NULL);
CDC::SetAttribDC(hDC);
MirrorMappingMode(TRUE);
MirrorFont();
MirrorAttributes();
}
CPreviewDC::~CPreviewDC()
{
ASSERT(m_hDC == NULL); // Should not have a screen DC at this time
AfxDeleteObject((HGDIOBJ*)&m_hFont);
}
void CPreviewDC::SetScaleRatio(int nNumerator, int nDenominator)
{
m_nScaleNum = nNumerator;
m_nScaleDen = nDenominator;
if (m_hAttribDC != NULL)
{
MirrorMappingMode(TRUE);
MirrorFont();
}
}
// Implementation support
#ifdef _DEBUG
void CPreviewDC::AssertValid() const
{
CDC::AssertValid();
}
void CPreviewDC::Dump(CDumpContext& dc) const
{
CDC::Dump(dc);
dc << "Scale Factor: " << m_nScaleNum << "/" << m_nScaleDen;
dc << "\n";
}
#endif
int CPreviewDC::SaveDC()
{
ASSERT(m_hAttribDC != NULL);
int nAttribIndex = ::SaveDC(m_hAttribDC);
if (m_hDC != NULL)
{
// remove font from object
::SelectObject(m_hDC, GetStockObject(SYSTEM_FONT));
m_nSaveDCDelta = ::SaveDC(m_hDC) - nAttribIndex;
// Select font back in after save
::SelectObject(m_hDC, m_hFont);
}
else
{
m_nSaveDCDelta = 0x7fff; // impossibly high value
}
return nAttribIndex;
}
BOOL CPreviewDC::RestoreDC(int nSavedDC)
{
ASSERT(m_hAttribDC != NULL);
BOOL bSuccess = ::RestoreDC(m_hAttribDC, nSavedDC);
if (bSuccess)
{
if (m_nSaveDCDelta != 0x7fff)
{
ASSERT(m_hDC != NULL); // removed Output DC after save
if (nSavedDC != -1)
nSavedDC += m_nSaveDCDelta;
bSuccess = ::RestoreDC(m_hDC, nSavedDC);
MirrorFont(); // mirror the font
}
else
{
ASSERT(m_hDC == NULL); // Added the Output DC after save
}
}
return bSuccess;
}
void CPreviewDC::MirrorAttributes()
{
ASSERT(m_hAttribDC != NULL);
if (m_hDC != NULL)
{
// extract and re-set Pen and Brush
HGDIOBJ hTemp = ::SelectObject(m_hAttribDC, ::GetStockObject(BLACK_PEN));
::SelectObject(m_hAttribDC, hTemp);
::SelectObject(m_hDC, hTemp);
hTemp = ::SelectObject(m_hAttribDC, ::GetStockObject(BLACK_BRUSH));
::SelectObject(m_hAttribDC, hTemp);
::SelectObject(m_hDC, hTemp);
SetROP2(GetROP2());
SetBkMode(GetBkMode());
SetTextAlign(GetTextAlign());
SetPolyFillMode(GetPolyFillMode());
SetStretchBltMode(GetStretchBltMode());
SetTextColor(GetNearestColor(GetTextColor()));
SetBkColor(GetNearestColor(GetBkColor()));
}
}
CGdiObject* CPreviewDC::SelectStockObject(int nIndex)
{
ASSERT(m_hAttribDC != NULL);
HGDIOBJ hObj = ::GetStockObject(nIndex);
switch (nIndex)
{
case ANSI_FIXED_FONT:
case ANSI_VAR_FONT:
case DEVICE_DEFAULT_FONT:
case OEM_FIXED_FONT:
case SYSTEM_FONT:
case SYSTEM_FIXED_FONT:
case DEFAULT_GUI_FONT:
// Handle the stock fonts correctly
{
CGdiObject* pObject = CGdiObject::FromHandle(
::SelectObject(m_hAttribDC, hObj));
// Don't re-mirror screen font if this is the same font.
if (m_hPrinterFont == (HFONT) hObj)
return pObject;
m_hPrinterFont = (HFONT) hObj;
ASSERT(m_hPrinterFont != NULL); // Do not allow infinite recursion
MirrorFont();
return pObject;
}
default:
if (m_hDC != NULL)
::SelectObject(m_hDC, hObj);
return CGdiObject::FromHandle(::SelectObject(m_hAttribDC, hObj));
}
}
void CPreviewDC::MirrorFont()
{
if (m_hAttribDC == NULL)
return; // Can't do anything without Attrib DC
if (m_hPrinterFont == NULL)
{
SelectStockObject(DEVICE_DEFAULT_FONT); // will recurse
return;
}
if (m_hDC == NULL)
return; // can't mirror font without a screen DC
LOGFONT logFont;
// Fill the logFont structure with the original info
::GetObject(m_hPrinterFont, sizeof(LOGFONT), (LPVOID)&logFont);
TEXTMETRIC tm;
GetTextFace(LF_FACESIZE, (LPTSTR)&logFont.lfFaceName[0]);
GetTextMetrics(&tm);
// Set real values based on the Printer's text metrics.
if (tm.tmHeight < 0)
logFont.lfHeight = tm.tmHeight;
else
logFont.lfHeight = -(tm.tmHeight - tm.tmInternalLeading);
logFont.lfWidth = tm.tmAveCharWidth;
logFont.lfWeight = tm.tmWeight;
logFont.lfItalic = tm.tmItalic;
logFont.lfUnderline = tm.tmUnderlined;
logFont.lfStrikeOut = tm.tmStruckOut;
logFont.lfCharSet = tm.tmCharSet;
logFont.lfPitchAndFamily = tm.tmPitchAndFamily;
HFONT hNewFont = ::CreateFontIndirect(&logFont);
::SelectObject(m_hDC, hNewFont);
::GetTextMetrics(m_hDC, &tm);
// Is the displayed font too large?
int cyDesired = -logFont.lfHeight;
int cyActual;
if (tm.tmHeight < 0)
cyActual = -tm.tmHeight;
else
cyActual = tm.tmHeight - tm.tmInternalLeading;
CSize sizeWinExt;
VERIFY(::GetWindowExtEx(m_hDC, &sizeWinExt));
CSize sizeVpExt;
VERIFY(::GetViewportExtEx(m_hDC, &sizeVpExt));
// Only interested in Extent Magnitudes, not direction
if (sizeWinExt.cy < 0)
sizeWinExt.cy = -sizeWinExt.cy;
if (sizeVpExt.cy < 0)
sizeVpExt.cy = -sizeVpExt.cy;
// Convert to screen device coordinates to eliminate rounding
// errors as a source of SmallFont aliasing
cyDesired = MulDiv(cyDesired, sizeVpExt.cy, sizeWinExt.cy);
cyActual = MulDiv(cyActual, sizeVpExt.cy, sizeWinExt.cy);
ASSERT(cyDesired >= 0 && cyActual >= 0);
if (cyDesired < cyActual)
{
logFont.lfFaceName[0] = 0; // let the mapper find a good fit
if ((logFont.lfPitchAndFamily & 0xf0) == FF_DECORATIVE)
logFont.lfPitchAndFamily = DEFAULT_PITCH | FF_DECORATIVE;
else
logFont.lfPitchAndFamily = DEFAULT_PITCH | FF_DONTCARE;
HFONT hTempFont = ::CreateFontIndirect(&logFont);
::SelectObject(m_hDC, hTempFont); // Select it in.
::DeleteObject(hNewFont);
hNewFont = hTempFont;
}
AfxDeleteObject((HGDIOBJ*)&m_hFont); // delete the old logical font
m_hFont = hNewFont; // save the new one
}
CFont* CPreviewDC::SelectObject(CFont* pFont)
{
if (pFont == NULL)
return NULL;
ASSERT(m_hAttribDC != NULL);
ASSERT_VALID(pFont);
CFont* pOldFont = (CFont*) CGdiObject::FromHandle(
::SelectObject(m_hAttribDC, pFont->m_hObject));
// If same as already selected, don't re-mirror screen font
if (m_hPrinterFont != pFont->m_hObject)
{
m_hPrinterFont = (HFONT)pFont->m_hObject;
MirrorFont();
}
return pOldFont;
}
/////////////////////////////////////////////////////////////////////////////
// Drawing-Attribute Functions
COLORREF CPreviewDC::SetBkColor(COLORREF crColor)
{
ASSERT(m_hAttribDC != NULL);
if (m_hDC != NULL)
::SetBkColor(m_hDC, ::GetNearestColor(m_hAttribDC, crColor));
return ::SetBkColor(m_hAttribDC, crColor);
}
COLORREF CPreviewDC::SetTextColor(COLORREF crColor)
{
ASSERT(m_hAttribDC != NULL);
if (m_hDC != NULL)
::SetTextColor(m_hDC, ::GetNearestColor(m_hAttribDC, crColor));
return ::SetTextColor(m_hAttribDC, crColor);
}
int CPreviewDC::SetMapMode(int nMapMode)
{
ASSERT(m_hAttribDC != NULL);
int nModeOld = ::SetMapMode(m_hAttribDC, nMapMode);
MirrorMappingMode(TRUE);
return nModeOld;
}
CPoint CPreviewDC::SetViewportOrg(int x, int y)
{
ASSERT(m_hAttribDC != NULL);
CPoint ptOrgOld;
VERIFY(::SetViewportOrgEx(m_hAttribDC, x, y, &ptOrgOld));
MirrorViewportOrg();
return ptOrgOld;
}
CPoint CPreviewDC::OffsetViewportOrg(int nWidth, int nHeight)
{
ASSERT(m_hAttribDC != NULL);
CPoint ptOrgOld;
VERIFY(::OffsetViewportOrgEx(m_hAttribDC, nWidth, nHeight, &ptOrgOld));
MirrorViewportOrg();
return ptOrgOld;
}
CSize CPreviewDC::SetViewportExt(int x, int y)
{
ASSERT(m_hAttribDC != NULL);
CSize sizeExtOld;
VERIFY(::SetViewportExtEx(m_hAttribDC, x, y, &sizeExtOld));
MirrorMappingMode(TRUE);
return sizeExtOld;
}
CSize CPreviewDC::ScaleViewportExt(int xNum, int xDenom, int yNum, int yDenom)
{
ASSERT(m_hAttribDC != NULL);
CSize sizeExtOld;
VERIFY(::ScaleViewportExtEx(m_hAttribDC, xNum, xDenom,
yNum, yDenom, &sizeExtOld));
MirrorMappingMode(TRUE);
return sizeExtOld;
}
CSize CPreviewDC::SetWindowExt(int x, int y)
{
ASSERT(m_hAttribDC != NULL);
CSize sizeExtOld;
VERIFY(::SetWindowExtEx(m_hAttribDC, x, y, &sizeExtOld));
MirrorMappingMode(TRUE);
return sizeExtOld;
}
CSize CPreviewDC::ScaleWindowExt(int xNum, int xDenom, int yNum, int yDenom)
{
ASSERT(m_hAttribDC != NULL);
CSize sizeExtOld;
VERIFY(::ScaleWindowExtEx(m_hAttribDC, xNum, xDenom, yNum, yDenom,
&sizeExtOld));
MirrorMappingMode(TRUE);
return sizeExtOld;
}
/////////////////////////////////////////////////////////////////////////////
// Text Functions
// private helpers for TextOut functions
AFX_STATIC int AFXAPI _AfxComputeNextTab(int x, UINT nTabStops, LPINT lpnTabStops,
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -