📄 scemfdcrenderer.cpp
字号:
);
m_States.Add(pStat);
}
///
/// Pop the indicated graphic state, and discard all states from its index to top of stack.
///
void CSCEMFdcRenderer::SCOnDCRestored(INT iRelative)
{
ASSERT(m_pGraphics);
INT iPos;
if (iRelative<0)
iPos = m_States.GetSize() + iRelative; // count from top of stack
else
iPos = iRelative; // count from bottom of stack
//ASSERT(iPos>=0 && iPos<m_States.GetSize());
if (iPos<0 || iPos>=m_States.GetSize())
return;
// GDI+ state
CSCGDIState* pStat = m_States[iPos];
m_pGraphics->Restore(pStat->m_SvdGraphicsState);
// Additional state information
// Get flat data
m_PtCurPos = pStat->m_PtSvdCurPos;
m_dwMapMode = pStat->m_dwSvdMapMode;
m_dwBkMode = pStat->m_dwSvdBkMode;
m_dwFillMode = pStat->m_dwSvdFillMode;
m_dwStretchBltMode = pStat->m_dwSvdStretchBltMode;
m_dwTextAlign = pStat->m_dwSvdTextAlign;
m_dwROP2 = pStat->m_dwSvdROP2;
m_BkColor = pStat->m_SvdBkColor;
m_TextColor = pStat->m_SvdTextColor;
m_dwArcDirection = pStat->m_dwSvdArcDirection;
m_fMiterLimit = pStat->m_fSvdMiterLimit;
m_WinSize = pStat->m_SvdWinSize;
m_ViewSize = pStat->m_SvdViewSize;
m_PtWinOrg = pStat->m_PtSvdWinOrg;
m_PtViewOrg = pStat->m_PtSvdViewOrg;
CopyRect(&m_RcClipBox, &pStat->m_RcSvdClipBox);
// Get objects
SC_OBJHOLDER_RESTORE_T(m_pPenHolder, m_pPen, pStat->m_pSvdPenHolder, GDPPen);
SC_OBJCONTAINER_RESTORE_T(m_pBrushHolder, m_pBrush, pStat->m_pSvdBrushHolder, GDPBrush, SCBrush);
SC_OBJHOLDER_RESTORE_T(m_pFontHolder, m_pFont, pStat->m_pSvdFontHolder, SCFont);
SC_OBJHOLDER_RESTORE_T(m_pPathHolder, m_pPath, pStat->m_pSvdPathHolder, SCPath);
// Delete all states, starting from iPos
INT iLen = m_States.GetSize();
for (INT i=iPos; (i<iLen); i++)
{
delete m_States[i];
}
m_States.RemoveAt(iPos, iLen - iPos);
#ifdef _DEBUG
// Check dangling pointers
SC_CHECKGDIP_OBJ(m_pPen);
SC_CHECKGDIP_OBJ(m_pBrush);
SC_CHECKGDIP_OBJ(m_pFont);
SC_CHECKGDIP_OBJ(m_pPath);
#endif
}
///
/// Move the current position.
///
void CSCEMFdcRenderer::SCMoveToEx(POINTL& PtDest)
{
if (m_pPath)
{
if (m_pPath->SCGetEnd())
SC_OBJHOLDER_RELEASE_T(m_pPathHolder, m_pPath, SCPath);
else
m_pPath->StartFigure();
}
m_PtCurPos.X = PtDest.x;
m_PtCurPos.Y = PtDest.y;
}
///
/// Change the background mode and update hatched brush transparency.
///
void CSCEMFdcRenderer::SCSetBkMode(DWORD dwMode)
{
ASSERT(m_pGraphics);
m_dwBkMode = dwMode;
if (m_pBrush && m_pBrush->GetType()==BrushTypeHatchFill)
{// We must update transparency
SCColor FgColor;
((HatchBrush*)m_pBrush)->GetForegroundColor(&FgColor);
SCColor BkColor;
((HatchBrush*)m_pBrush)->GetBackgroundColor(&BkColor);
BkColor.SCSetAlpha(((TRANSPARENT==m_dwBkMode) ? 0 : 255));
HatchBrush* pBrush = new HatchBrush(((HatchBrush*)m_pBrush)->GetHatchStyle(), FgColor, BkColor);
// Refresh the brush object
SCRefreshBrush(pBrush);
}
}
///
/// Change the text color and update monochrome brush color.
///
void CSCEMFdcRenderer::SCSetBkColor(COLORREF BkColor)
{
m_BkColor = SCGetFinalColor(BkColor);
if (!m_pBrushHolder)
return;
SCBrush* pSCBrush = m_pBrushHolder->SCGetSubObj();
ASSERT(pSCBrush);
if (!pSCBrush->SCIsMonoPattern())
return;
HBRUSH hBrush;
if (hBrush = pSCBrush->SCGetHandle())
{
SCOnChangeBrush(hBrush);
}
}
///
/// Change the background color and update monochrome brush color.
///
void CSCEMFdcRenderer::SCSetTextColor(COLORREF TxtColor)
{
m_TextColor = SCGetFinalColor(TxtColor);
if (!m_pBrushHolder)
return;
SCBrush* pSCBrush = m_pBrushHolder->SCGetSubObj();
ASSERT(pSCBrush);
if (!pSCBrush->SCIsMonoPattern())
return;
HBRUSH hBrush;
if (hBrush = pSCBrush->SCGetHandle())
{
SCOnChangeBrush(hBrush);
}
}
///////////////////////////////////////////////////////////////////////////////////
// Drawing objects
//
///
/// Convert the newly selected pen in m_hDC to its corresponding GDI+ object.
///
void CSCEMFdcRenderer::SCOnChangePen(HPEN hPen)
{
ASSERT(m_pGraphics);
SC_OBJHOLDER_RELEASE_T(m_pPenHolder, m_pPen, GDPPen);
ASSERT(hPen);
LOGPEN LogPen;
if (::GetObject(hPen, sizeof(LogPen), &LogPen))
{
LogPen.lopnColor = SCGetFinalColor(LogPen.lopnColor);
m_pPen = SCPenFromLogPen(LogPen);
} else
{// most likely the handle is not valid (maybe a deleted object)
TRACE0("Invalid pen handle in DC");
}
SC_OBJHOLDER_RENEW_T(m_pPenHolder, m_pPen, GDPPen);
}
///
/// Convert the newly selected pen in m_hDC to its corresponding GDI+ object.
///
void CSCEMFdcRenderer::SCOnChangeExtPen(HPEN hPen)
{
ASSERT(m_pGraphics);
SC_OBJHOLDER_RELEASE_T(m_pPenHolder, m_pPen, GDPPen);
ASSERT(hPen);
DWORD dwSize = ::GetObject(hPen, sizeof(EXTLOGPEN), NULL);
BYTE* pBytes = new BYTE[dwSize];
if (::GetObject(hPen, dwSize, pBytes))
{
EXTLOGPEN* pExtLogPen = (EXTLOGPEN*)pBytes;
if (BS_SOLID==pExtLogPen->elpBrushStyle || BS_HATCHED==pExtLogPen->elpBrushStyle)
{
pExtLogPen->elpColor = SCGetFinalColor(pExtLogPen->elpColor);
}
SCShortDCState TmpDCState(m_bMonochrome, m_dwROP2, m_TextColor, m_BkColor, m_dwBkMode);
m_pPen = SCPenFromExtLogPen(pExtLogPen, TmpDCState);
// Since a GDI+ pen has its own matrix, scaling problems may arise some day
// (see comments in SCOnChangeBrush). In that event, think about something like:
// m_pPen->SetTransform(&BogusMatrix);
// This looks as if, after giving the width of a pen, we should give a matrix
// to scale it. Poor us, we don't have such information.
}
else
{// most likely the handle is not valid (maybe a deleted object)
TRACE0("Invalid extpen handle in DC");
}
delete [] pBytes;
SC_OBJHOLDER_RENEW_T(m_pPenHolder, m_pPen, GDPPen);
}
///
/// Convert the newly selected brush in m_hDC to its corresponding GDI+ object.
///
void CSCEMFdcRenderer::SCOnChangeBrush(HBRUSH hBrush)
{
ASSERT(m_pGraphics);
SC_OBJCONTAINER_RELEASE_T(m_pBrushHolder, m_pBrush, GDPBrush, SCBrush);
ASSERT(hBrush);
LOGBRUSH LogBrush;
LogBrush.lbHatch = 0;
BOOL bMonoBrush = FALSE;
if (::GetObject(hBrush, sizeof(LogBrush), &LogBrush))
{
if (BS_SOLID==LogBrush.lbStyle)
{
LogBrush.lbColor = SCGetFinalColor(LogBrush.lbColor);
}
SCShortDCState TmpDCState(m_bMonochrome, m_dwROP2, m_TextColor, m_BkColor, m_dwBkMode);
m_pBrush = SCBrushFromLogBrush(LogBrush, TmpDCState);
bMonoBrush = TmpDCState.bMonoBrush; // for brush update
#if 1
// Strange!!
if (m_pBrush && m_pBrush->GetType()==BrushTypeTextureFill)
{
// Note: When the brush is used, GDI+ won't use the transform in m_pGraphics
// to properly display the brush.
// I must exerce a strong moral on myself to just say that:
// - GDI+ is a BS_... PATTERN!
// Back to civilization.
// Try to guess what these lines are doing.
Matrix CurMatrix;
m_pGraphics->GetTransform(&CurMatrix);
if (CurMatrix.IsInvertible())
{
// Note: unexpected results in perspective, as we are setting up this
// brush with the CURRENT state of m_pGraphics
CurMatrix.Invert();
((TextureBrush*)m_pBrush)->SetTransform(&CurMatrix);
} else
{ // else, let things fall down
ASSERT(0);
}
}
#endif
} else
{// most likely the handle is not valid (maybe a deleted object)
TRACE0("Invalid brush handle in DC");
}
SCBrush* pSCbrush = m_pBrush ? new SCBrush(hBrush, bMonoBrush) : NULL;
SC_OBJCONTAINER_RENEW_T(m_pBrushHolder, m_pBrush, GDPBrush, pSCbrush, SCBrush);
// Brush origin should be set. But it seems to have no effect on GDI+.
// See comments in SCSetBrushOrg.
}
void CSCEMFdcRenderer::SCSetBrushOrg(POINTL& PtOrg)
{
ASSERT(m_pGraphics);
#if 0
// won't work? Maybe a device/world units problem (PtOrg is in device units)
m_pGraphics->SetRenderingOrigin(PtOrg.x, PtOrg.y);
#else
// won't work either. TODO: find the bug.
Point Pts[2];
Pts[1].X = PtOrg.x;
Pts[1].Y = PtOrg.y;
Pts[0].X = 0;
Pts[0].Y = 0;
Matrix matrix;
m_pGraphics->GetTransform(&matrix);
matrix.Invert();
matrix.TransformPoints((Point*)&Pts, 2);
Pts[1].X -= Pts[0].X;
Pts[1].Y -= Pts[0].Y;
m_pGraphics->SetRenderingOrigin(Pts[1].X, Pts[1].Y);
#endif
// Origin should be stored for brush update. But since SetRenderingOrigin is called
// on GDPGraphics, not on the brush, the setting is likely to stay until the next
// SCSetBrushOrg call.
}
void CSCEMFdcRenderer::SCSelectPrivateFont(LOGFONT& rLogFont, SCFontCollection* pFontCollection, DWORD dwSimul)
{
ASSERT(pFontCollection);
// VC6 compiler won't accept the assignment OR with an enum (and that's correct).
// FontStyle Style = FontStyleRegular;
INT Style = FontStyleRegular;
if (rLogFont.lfWeight>=FW_BOLD)
Style = FontStyleBold;
if (rLogFont.lfItalic)
Style |= FontStyleItalic;
#if 0
// You know what? The text would disappear as well (see attributes simulation).
if (rLogFont.lfUnderline)
Style |= FontStyleUnderline;
if (rLogFont.lfStrikeOut)
Style |= FontStyleStrikeout;
#endif
#ifdef _UNICODE
WCHAR* wFaceName = (WCHAR*)rLogFont.lfFaceName;
#else
WCHAR wFaceName[LF_FACESIZE];
MultiByteToWideChar(CP_ACP, 0, (LPSTR)rLogFont.lfFaceName, LF_FACESIZE, wFaceName, LF_FACESIZE);
#endif
TEXTMETRIC tm;
GetTextMetrics(m_hDC, &tm);
m_pFont = new SCFont(wFaceName, (REAL)(tm.tmHeight - tm.tmInternalLeading), (FontStyle)Style, pFontCollection);
if (m_pFont)
{
if (m_pFont->IsAvailable())
{
m_pFont->SCFinalInit(m_hDC, rLogFont.lfEscapement, dwSimul, NULL);
SC_OBJHOLDER_RENEW_T(m_pFontHolder, m_pFont, SCFont);
} else
{
SMC_SAFEDELETE(m_pFont);
}
}
}
///
/// Convert the newly selected font in m_hDC to its corresponding GDI+ object.
///
void CSCEMFdcRenderer::SCOnChangeFont(HFONT hFont)
{
ASSERT(m_pGraphics);
SC_OBJHOLDER_RELEASE_T(m_pFontHolder, m_pFont, SCFont);
// get the logfont
ASSERT(hFont);
LOGFONT LogFont;
INT iRes = ::GetObject(hFont, sizeof(LogFont), &LogFont);
if (!iRes)
{// most likely the handle is not valid (maybe a deleted object)
TRACE0("Invalid font handle in DC");
SC_OBJHOLDER_RENEW_T(m_pFontHolder, m_pFont, SCFont);
return;
}
ASSERT(abs(LogFont.lfEscapement)<=3600);
// TODO: solve the case of GM_ADVANCED. For now, assume GM_COMPATIBLE.
ASSERT((LogFont.lfEscapement==LogFont.lfOrientation)||
(GetGraphicsMode(m_hDC)==GM_ADVANCED));
DWORD dwSimul = 0;
// 0) Check attributes
// We can't do:
// m_pFont = new SCFont(m_hDC);
// GDI+ does not support underlined/overstriked/symbol fonts (this is not a joke).
// We must remove unsupported attributes. Otherwise, the text would simply disappear,
// though m_pFont->IsAvailable() would return TRUE.
if (LogFont.lfUnderline)
{
LogFont.lfUnderline = 0;
dwSimul |= SC_FONT_SIMUL_UNDERLINE;
// I know, I can use FontStyleUnderline in a FontStyle.
// But, what am I doing here? Am I creating a font? What is a font now?
}
if (LogFont.lfStrikeOut)
{
LogFont.lfStrikeOut = 0;
dwSimul |= SC_FONT_SIMUL_OVERSTRIKE;
// I know, I can use FontStyleStrikeout in a FontStyle.
}
// 1) Check application installed fonts
// GDI+ is unable to recognize a temporary/private GDI TT font installed by the
// application. It bogusly replies: 'NotTrueTypeFont!'
// So the caller must install temporary fonts in a SCFontCollection and pass it
// to the renderer. And we check this collection first.
if (m_pFontCollection &&
m_pFontCollection->SCIsInstalledFacename((LPTSTR)LogFont.lfFaceName))
{
SCSelectPrivateFont(LogFont, m_pFontCollection, dwSimul);
ASSERT(m_pFont);
return;
}
// 2) Check DC font. Don't forget, We can't do: m_pFont = new SCFont(m_hDC);
m_pFont = new SCFont(m_hDC, &LogFont);
if (m_pFont)
{
if (m_pFont->IsAvailable())
{
m_pFont->SCFinalInit(m_hDC, LogFont.lfEscapement, dwSimul, NULL);
SC_OBJHOLDER_RENEW_T(m_pFontHolder, m_pFont, SCFont);
return;
}
SMC_SAFEDELETE(m_pFont);
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -