📄 scemfgdiparser.cpp
字号:
SCFinishTextout(pRec, pTextRec, pwStr, uiOptions);
return SC_BRK_NOERROR;
}
void CSCEMFgdiParser::SCFinishTextout(EMREXTTEXTOUTA* pRec, EMRTEXT* pTextRec, LPWSTR pwStr, UINT uiOptions)
{
ASSERT(m_pRenderer);
INT iNbChars = pTextRec->nChars;
// Get intercharacter spacing array.
DWORD OffDx = pTextRec->offDx;
INT *lpDx = (INT*)((BYTE*)pRec + OffDx);
if (0==OffDx)
{
// Compute intercharacter spacing, based on each character width.
lpDx = new INT[iNbChars];
BOOL bOk = SCGetTextCharWidthsW(m_hPlayDC, pwStr, iNbChars, lpDx);
ASSERT(bOk);
}
else
{ // else use distances between origins of adjacent character cells as passed to ExtTextOut.
// except that, sometimes, the last character is given a spacing of 0, which is not good for us.
if (0==lpDx[iNbChars-1])
{
INT* pInts = new INT[iNbChars];
memmove(pInts, lpDx, iNbChars*sizeof(INT));
// compute only the last character's width
BOOL bOk = SCGetTextCharWidthsW(m_hPlayDC, pwStr+iNbChars-1, 1, pInts+iNbChars-1);
ASSERT(bOk);
lpDx = pInts;
OffDx = 0; // for cleanup
ASSERT(lpDx[iNbChars-1]);
}
}
if (GM_COMPATIBLE==pRec->iGraphicsMode)
m_pRenderer->SCDrawText(pTextRec->ptlReference.x, pTextRec->ptlReference.y, uiOptions,
(LPCRECT)&pTextRec->rcl, pwStr, iNbChars, lpDx, pRec->exScale, pRec->eyScale);
else
m_pRenderer->SCDrawText(pTextRec->ptlReference.x, pTextRec->ptlReference.y, uiOptions,
(LPCRECT)&pTextRec->rcl, pwStr, iNbChars, lpDx, 1, 1);
// Clean up
if (0==OffDx)
delete [] lpDx;
}
///////////////////////////////////////////////////////////////////////////////////////////
SC_BRKRESULT CSCEMFgdiParser::OnEmfEXTTEXTOUTW()
{
// TRACE0("**EMR_EXTTEXTOUTW\n");
//EMREXTTEXTOUTW *pRec = (EMREXTTEXTOUTW*)m_pRecord;
// pass the record to
return OnEmfEXTTEXTOUTA();
}
SC_BRKRESULT CSCEMFgdiParser::OnEmfPOLYBEZIER16()
{
// TRACE0("**EMR_POLYBEZIER16\n");
ASSERT(m_pRenderer);
m_pRenderer->SCDrawBezierS(((EMRPOLYBEZIER16*)m_pRecord)->apts,
((EMRPOLYBEZIER16*)m_pRecord)->cpts);
return SC_BRK_NOERROR;
}
SC_BRKRESULT CSCEMFgdiParser::OnEmfPOLYGON16()
{
// TRACE0("**EMR_POLYGON16\n");
ASSERT(m_pRenderer);
m_pRenderer->SCDrawPolygonS(((EMRPOLYGON16*)m_pRecord)->apts,
((EMRPOLYGON16*)m_pRecord)->cpts);
return SC_BRK_NOERROR;
}
SC_BRKRESULT CSCEMFgdiParser::OnEmfPOLYLINE16()
{
// TRACE0("**EMR_POLYLINE16\n");
ASSERT(m_pRenderer);
m_pRenderer->SCDrawLinesS(((EMRPOLYLINE16*)m_pRecord)->apts,
((EMRPOLYLINE16*)m_pRecord)->cpts);
return SC_BRK_NOERROR;
}
SC_BRKRESULT CSCEMFgdiParser::OnEmfPOLYBEZIERTO16()
{
// TRACE0("**EMR_POLYBEZIERTO16\n");
ASSERT(m_pRenderer);
m_pRenderer->SCDrawBezierToS(((EMRPOLYBEZIERTO16*)m_pRecord)->apts,
((EMRPOLYBEZIERTO16*)m_pRecord)->cpts);
return SC_BRK_NOERROR;
}
SC_BRKRESULT CSCEMFgdiParser::OnEmfPOLYLINETO16()
{
// TRACE0("**EMR_POLYLINETO16\n");
ASSERT(m_pRenderer);
m_pRenderer->SCDrawLinesToS(((EMRPOLYLINETO16*)m_pRecord)->apts,
((EMRPOLYLINETO16*)m_pRecord)->cpts);
return SC_BRK_NOERROR;
}
SC_BRKRESULT CSCEMFgdiParser::OnEmfPOLYPOLYLINE16()
{
// TRACE0("**EMR_POLYPOLYLINE16\n");
ASSERT(m_pRenderer);
EMRPOLYPOLYLINE16 *pRec = (EMRPOLYPOLYLINE16*)m_pRecord;
LPPOINTS pPts = (LPPOINTS)((DWORD*)pRec->aPolyCounts + pRec->nPolys);
m_pRenderer->SCDrawPolyPolylineS(pPts, pRec->cpts, (DWORD*)pRec->aPolyCounts, pRec->nPolys);
return SC_BRK_NOERROR;
}
SC_BRKRESULT CSCEMFgdiParser::OnEmfPOLYPOLYGON16()
{
// TRACE0("**EMR_POLYPOLYGON16\n");
ASSERT(m_pRenderer);
EMRPOLYPOLYGON16 *pRec = (EMRPOLYPOLYGON16*)m_pRecord;
LPPOINTS pPts = (LPPOINTS)((DWORD*)pRec->aPolyCounts + pRec->nPolys);
m_pRenderer->SCDrawPolyPolygonS(pPts, pRec->cpts, (DWORD*)pRec->aPolyCounts, pRec->nPolys);
return SC_BRK_NOERROR;
}
SC_BRKRESULT CSCEMFgdiParser::OnEmfPOLYDRAW16()
{
// TRACE0("**EMR_POLYDRAW16\n");
ASSERT(m_pRenderer);
EMRPOLYDRAW16 *pRec = (EMRPOLYDRAW16*)m_pRecord;
BYTE* pTypes = (BYTE*)((POINTS*)pRec->apts + pRec->cpts);
m_pRenderer->SCDrawPolyDrawS(pRec->apts,
pRec->cpts,
pTypes);
return SC_BRK_NOERROR;
}
SC_BRKRESULT CSCEMFgdiParser::OnEmfCREATEMONOBRUSH()
{
// TRACE0("**EMR_CREATEMONOBRUSH\n");
ASSERT(m_pRenderer);
EMRCREATEMONOBRUSH *pRec = (EMRCREATEMONOBRUSH*)m_pRecord;
// SCPlayRecord() won't work: the brush will reference a deleted bitmap (XP specific bug?).
// See comments in the final block.
SCPlayRecord();
#ifndef DIB_PAL_INDICES
#define DIB_PAL_INDICES 2
#endif
ASSERT(DIB_PAL_INDICES==pRec->iUsage);
// DIB_PAL_INDICES management. Special case: the DIB has no color table.
BITMAPINFO *pBmi = (BITMAPINFO *) ((BYTE *)pRec + pRec->offBmi);
DWORD *pBitsDW = (DWORD *) ((BYTE *) pRec + pRec->offBits);
// Attach a monochrome palette to the DIB specification,
// and create a device-dependent bitmap
HBITMAP hBm = NULL;
DWORD dwSize = pBmi->bmiHeader.biSize + 2*sizeof(RGBQUAD);
BITMAPINFO* pBmi2 = (BITMAPINFO*) new BYTE[dwSize];
memmove(pBmi2, pBmi, dwSize);
HDC hMonoDC = CreateCompatibleDC(m_hPlayDC); // must be monochrome
ASSERT(hMonoDC);
SCFillMonochromePalette(hMonoDC, (PPALETTEENTRY)pBmi2->bmiColors);
// May create resource leak, as we don't call DeleteObject on hBm (see comments in the final block)
hBm = CreateDIBitmap(hMonoDC, &pBmi2->bmiHeader, CBM_INIT, pBitsDW, pBmi2, DIB_RGB_COLORS);
DeleteDC(hMonoDC);
delete [] (BYTE*)pBmi2;
ASSERT(hBm);
#ifdef _DEBUG
{// check
BITMAP bm;
int iRes = GetObject(hBm, sizeof(BITMAP), &bm);
ASSERT(iRes);
}
#endif
HBRUSH hBrush = CreatePatternBrush(hBm);
ASSERT(hBrush);
m_lpEnumHandleTable->objectHandle[pRec->ihBrush] = hBrush;
#if 0
// Don't do this normal step of the code:
// DeleteObject(hBm);
// It seems that XP's CreatePatternBrush does not make a copy of the given bitmap.
// To prove it, activate this code, and you will see that GetObjectType
// will fail on the LogBrushVerif2.lbHatch handle returned by GetObject.
{
// Check before delete
LOGBRUSH LogBrushVerif1;
ASSERT(::GetObject(hBrush, sizeof(LogBrushVerif1), &LogBrushVerif1));
ASSERT(LogBrushVerif1.lbStyle==BS_PATTERN);
int iType1 = GetObjectType((HGDIOBJ)LogBrushVerif1.lbHatch);
ASSERT(iType1==OBJ_BITMAP);
// Suppose we delete it
DeleteObject(hBm);
// Check after delete
LOGBRUSH LogBrushVerif2;
ASSERT(::GetObject(hBrush, sizeof(LogBrushVerif2), &LogBrushVerif2));
ASSERT(LogBrushVerif2.lbStyle==BS_PATTERN);
int iType2 = GetObjectType((HGDIOBJ)LogBrushVerif2.lbHatch);
ASSERT(iType2==OBJ_BITMAP); // fails
}
#endif
return SC_BRK_NOERROR;
}
SC_BRKRESULT CSCEMFgdiParser::OnEmfCREATEDIBPATTERNBRUSHPT()
{
// TRACE0("**EMR_CREATEDIBPATTERNBRUSHPT\n");
ASSERT(m_pRenderer);
#if 0
// On NT.SP5, Same problem as monobrush
SCPlayRecord();
#else
EMRCREATEDIBPATTERNBRUSHPT *pRec = (EMRCREATEDIBPATTERNBRUSHPT*)m_pRecord;
ASSERT(DIB_PAL_COLORS==pRec->iUsage || DIB_RGB_COLORS==pRec->iUsage);
BITMAPINFO *pBmi = (BITMAPINFO *) ((BYTE *)pRec + pRec->offBmi);
// Note: On Windows 95 and Windows 98, "creating brushes from bitmaps or DIBs
// larger than 8x8 pixels is not supported". So we should restrict the pattern to 8x8.
// But what if the EMF was created on NT/2K/XP? It seems that GDI doesn't shrink the
// pattern in order to render the EMF OS-independently.
DWORD dwSize = pRec->cbBmi + pRec->cbBits;
// should agree with:
// BITMAPINFOHEADER* pBmih = &pBmi->bmiHeader;
// DWORD dwSize = pBmih->biSize +
// ColorTableSize(pBmih) +
// ((pBmih->biSizeImage) ? pBmih->biSizeImage :
// abs(pBmih->biHeight)*WIDTHBYTES(pBmih->biWidth*pBmih->biBitCount));
// May create resource leak, as we don't call GlobalFree on hMem
// (in fact, this is the sole purpose of this code)
HGLOBAL hMem = GlobalAlloc(GPTR, dwSize);
BITMAPINFO* pBmi2 = (BITMAPINFO*)GlobalLock(hMem);
memmove(pBmi2, pBmi, dwSize);
HBRUSH hBrush = CreateDIBPatternBrushPt(pBmi2, pRec->iUsage);
GlobalUnlock(hMem);
ASSERT(hBrush);
m_lpEnumHandleTable->objectHandle[pRec->ihBrush] = hBrush;
#ifdef _DEBUG
{// Check after play
LOGBRUSH LogBrushVerif;
ASSERT(::GetObject((HBRUSH)m_lpEnumHandleTable->objectHandle[pRec->ihBrush], sizeof(LogBrushVerif), &LogBrushVerif));
ASSERT(LogBrushVerif.lbStyle==BS_DIBPATTERN);
}
#endif
#endif
return SC_BRK_NOERROR;
}
SC_BRKRESULT CSCEMFgdiParser::OnEmfEXTCREATEPEN()
{
// TRACE0("**EMR_EXTCREATEPEN\n");
ASSERT(m_pRenderer);
SCPlayRecord();
// EMREXTCREATEPEN *pRec = (EMREXTCREATEPEN*)m_pRecord;
return SC_BRK_NOERROR;
}
SC_BRKRESULT CSCEMFgdiParser::OnEmfPOLYTEXTOUTA()
{
// TRACE0("**EMR_POLYTEXTOUTA\n");
ASSERT(m_pRenderer);
EMRPOLYTEXTOUTA *pRec = (EMRPOLYTEXTOUTA*)m_pRecord;
for (int i=0; (i<pRec->cStrings); i++)
{
SCEmfTextoutA((EMREXTTEXTOUTA*)pRec, &pRec->aemrtext[i]);
}
return SC_BRK_NOERROR;
}
SC_BRKRESULT CSCEMFgdiParser::OnEmfPOLYTEXTOUTW()
{
// TRACE0("**EMR_POLYTEXTOUTW\n");
ASSERT(m_pRenderer);
EMRPOLYTEXTOUTW *pRec = (EMRPOLYTEXTOUTW*)m_pRecord;
for (int i=0; (i<pRec->cStrings); i++)
{
SCEmfTextoutW((EMREXTTEXTOUTW*)pRec, &pRec->aemrtext[i]);
}
return SC_BRK_NOERROR;
}
SC_BRKRESULT CSCEMFgdiParser::OnEmfSETICMMODE()
{
// TRACE0("**EMR_SETICMMODE\n");
ASSERT(m_pRenderer);
// EMRSETICMMODE *pRec = (EMRSETICMMODE*)m_pRecord;
// MSDN: see "DIBINFO.C"
// TODO_EMF: Place code here to handle EMF record
SCPlayRecord();
return SC_BRK_NOERROR;
}
SC_BRKRESULT CSCEMFgdiParser::OnEmfCREATECOLORSPACE()
{
// TRACE0("**EMR_CREATECOLORSPACE\n");
ASSERT(m_pRenderer);
// EMRCREATECOLORSPACE *pRec = (EMRCREATECOLORSPACE*)m_pRecord;
// MSDN: see "Basic ICM 2.0 Functions for Use Within a Device Context"
// TODO_EMF: Place code here to handle EMF record
SCPlayRecord();
return SC_BRK_NOERROR;
}
SC_BRKRESULT CSCEMFgdiParser::OnEmfCREATECOLORSPACEW()
{
// TRACE0("**EMR_CREATECOLORSPACE\n");
ASSERT(m_pRenderer);
//EMRCREATECOLORSPACEW *pRec = (EMRCREATECOLORSPACEW*)m_pRecord;
// MSDN: see "Basic ICM 2.0 Functions for Use Within a Device Context"
// TODO_EMF: Place code here to handle EMF record
SCPlayRecord();
return SC_BRK_NOERROR;
}
SC_BRKRESULT CSCEMFgdiParser::OnEmfSETCOLORSPACE()
{
// TRACE0("**EMR_SETCOLORSPACE\n");
ASSERT(m_pRenderer);
// EMRSELECTCOLORSPACE *pRec = (EMRSELECTCOLORSPACE*)m_pRecord;
// MSDN: see "Basic ICM 2.0 Functions for Use Within a Device Context"
// TODO_EMF: Place code here to handle EMF record
SCPlayRecord();
return SC_BRK_NOERROR;
}
SC_BRKRESULT CSCEMFgdiParser::OnEmfDELETECOLORSPACE()
{
// TRACE0("**EMR_DELETECOLORSPACE\n");
ASSERT(m_pRenderer);
// EMRDELETECOLORSPACE *pRec = (EMRDELETECOLORSPACE*)m_pRecord;
// MSDN: see "Basic ICM 2.0 Functions for Use Within a Device Context"
// TODO_EMF: Place code here to handle EMF record
SCPlayRecord();
return SC_BRK_NOERROR;
}
SC_BRKRESULT CSCEMFgdiParser::OnEmfGLSRECORD()
{
// TRACE0("**EMR_GLSRECORD\n");
ASSERT(m_pRenderer);
SC_BRKRESULT error(SC_BRK_NOERROR);
EMRGLSRECORD *pRec = (EMRGLSRECORD*)m_pRecord;
// TODO_EMF: Place code here to handle EMF record
SCPlayRecord();
return error;
}
SC_BRKRESULT CSCEMFgdiParser::OnEmfGLSBOUNDEDRECORD()
{
// TRACE0("**EMR_GLSBOUNDEDRECORD\n");
ASSERT(m_pRenderer);
// EMRGLSBOUNDEDRECORD *pRec = (EMRGLSBOUNDEDRECORD*)m_pRecord;
// TODO_EMF: Place code here to handle EMF record
SCPlayRecord();
return SC_BRK_NOERROR;
}
SC_BRKRESULT CSCEMFgdiParser::OnEmfPIXELFORMAT()
{
// TRACE0("**EMR_PIXELFORMAT\n");
ASSERT(m_pRenderer);
// EMRPIXELFORMAT *pRec = (EMRPIXELFORMAT*)m_pRecord;
// TODO_EMF: Place code here to handle EMF record
SCPlayRecord();
return SC_BRK_NOERROR;
}
SC_BRKRESULT CSCEMFgdiParser::OnEmfDRAWESCAPE()
{
// TRACE0("**EMR_DRAWESCAPE\n");
ASSERT(m_pRenderer);
// EMR *pRec = (EMR*)m_pRecord;
// Do not play Escape
// Anyway, now it's SCEMF_RESERVED_105
return SC_BRK_NOERROR;
}
SC_BRKRESULT CSCEMFgdiParser::OnEmfEXTESCAPE()
{
// TRACE0("**EMR_EXTESCAPE\n");
ASSERT(m_pRenderer);
// EMR *pRec = (EMR*)m_pRecord;
// Do not play Escape
// Anyway, now it's SCEMF_RESERVED_106
return SC_BRK_NOERROR;
}
SC_BRKRESULT CSCEMFgdiParser::OnEmfSTARTDOC()
{
// TRACE0("**EMR_STARTDOC\n");
ASSERT(m_pRenderer);
// EMR *pRec = (EMR*)m_pRecord;
// Do not play Escape
// Anyway, now it's SCEMF_RESERVED_107
return SC_BRK_NOERROR;
}
SC_BRKRESULT CSCEMFgdiParser::OnEmfSMALLTEXTOUT()
{
// TRACE0("**EMR_SMALLTEXTOUT\n");
ASSERT(m_pRenderer);
// WARNING: it's SCEMF_RESERVED_108
SCEMRSMALLTEXTOUTA *pRec = (SCEMRSMALLTEXTOUTA*)m_pRecord;
// TODO: review this line
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -