|
|
/**************************************************************************\
* * Copyright (c) 2000 Microsoft Corporation * * Module Name: * * MetaEmf.cpp * * Abstract: * * Methods for playing and recoloring an EMF. * * Created: * * 1/6/2000 DCurtis * \**************************************************************************/
#include "Precomp.hpp"
#include "MetaWmf.hpp"
//----------------------------------------------------------------------------
// File format signatures for Office Art data.
//------------------------------------------------------------------- JohnBo
#define msoszOfficeSignature "MSOFFICE"
#define msocbOfficeSignature 8
#define msoszOfficeAuthentication "9.0"
#define msocbOfficeAuthentication 3
#define msoszOfficeIdent msoszOfficeSignature msoszOfficeAuthentication
#define msocbOfficeIdent (msocbOfficeSignature+msocbOfficeAuthentication)
#define msoszOAPNGChunk "msOA"
#define msocbOAPNGChunk 4
#define msoszOADataHeader msoszOAPNGChunk msoszOfficeIdent
#define msocbOADataHeader (msocbOAPNGChunk+msocbOfficeIdent)
#define msoszOAKind "OA"
#define msocbOAKind 2
/* This defines an OZ chunk, like OA but Zlib compressed. */ #define msoszOZPNGChunk "msOZ"
#define msocbOZPNGChunk 4
#define msoszOZDataHeader msoszOZPNGChunk msoszOfficeIdent
#define msocbOZDataHeader (msocbOZPNGChunk+msocbOfficeIdent)
// These are needed for IA64 compatibility with X86
// Since we are reading this record from a stream, on IA64
// The EXTLOGPEN structure has a ULONG_PTR member which is not the same size
// on IA64 and X86. Since all output to files will keep the X86 format we need
// to make sure that we can read this format in IA64, so we make it compatible
// by changing the ULONG_PTR to a ULONG (32bit). The packing of the structure
// will them be the same and the members will be at the same offset
typedef struct tagEXTLOGPEN32 { DWORD elpPenStyle; DWORD elpWidth; UINT elpBrushStyle; COLORREF elpColor; ULONG elpHatch; DWORD elpNumEntries; DWORD elpStyleEntry[1]; } EXTLOGPEN32, *PEXTLOGPEN32;
typedef struct tagEMREXTCREATEPEN32 { EMR emr; DWORD ihPen; // Pen handle index
DWORD offBmi; // Offset to the BITMAPINFO structure if any
DWORD cbBmi; // Size of the BITMAPINFO structure if any
// The bitmap info is followed by the bitmap
// bits to form a packed DIB.
DWORD offBits; // Offset to the brush bitmap bits if any
DWORD cbBits; // Size of the brush bitmap bits if any
EXTLOGPEN32 elp; // The extended pen with the style array.
} EMREXTCREATEPEN32, *PEMREXTCREATEPEN32;
typedef struct tagEMRRCLBOUNDS { EMR emr; RECTL rclBounds; } EMRRCLBOUNDS, *PEMRRCLBOUNDS;
typedef struct EMROFFICECOMMENT { EMR emr; DWORD cbData; // Size of following fields and data
DWORD ident; // GDICOMMENT_IDENTIFIER
DWORD iComment; // Comment type e.g. GDICOMMENT_WINDOWS_METAFILE
} EMROFFICECOMMENT, *PEMROFFICECOMMENT;
RecolorStockObject RecolorStockObjectList[NUM_STOCK_RECOLOR_OBJS] = { { WHITE_BRUSH, (COLORREF)RGB(0xFF, 0xFF, 0xFF), TRUE }, { LTGRAY_BRUSH, (COLORREF)RGB(0xC0, 0xC0, 0xC0), TRUE }, { GRAY_BRUSH, (COLORREF)RGB(0x80, 0x80, 0x80), TRUE }, { DKGRAY_BRUSH, (COLORREF)RGB(0x40, 0x40 ,0x40), TRUE }, { BLACK_BRUSH, (COLORREF)RGB(0, 0, 0), TRUE }, { WHITE_PEN, (COLORREF)RGB(0xFF, 0xFF, 0xFF), FALSE }, { BLACK_PEN, (COLORREF)RGB(0, 0 ,0), FALSE } };
inline static RGBQUAD * GetDibColorTable( BITMAPINFOHEADER * dibInfo ) { return ( RGBQUAD *)(((BYTE *)dibInfo) + dibInfo->biSize); }
BOOL EmfEnumState::CreateCopyOfCurrentRecord() { if (ModifiedRecordSize > 0) { // We already made a modified record. Don't do it again.
ASSERT(ModifiedRecord != NULL); return TRUE; }
INT size = this->GetCurrentRecordSize();
if (CreateRecordToModify(size)) { ENHMETARECORD * modifiedRecord = (ENHMETARECORD *)ModifiedRecord;
modifiedRecord->iType = RecordType; modifiedRecord->nSize = size;
if (RecordDataSize > 0) { GpMemcpy(modifiedRecord->dParm, RecordData, RecordDataSize); } return TRUE; }
WARNING(("Failed to create copy of current record")); return FALSE; }
BOOL EmfEnumState::CreateAndPlayOutputDIBRecord( HDC hdc, const RECTL * bounds, INT dstX, INT dstY, INT dstWidth, INT dstHeight, INT srcX, INT srcY, INT srcWidth, INT srcHeight, UNALIGNED BITMAPINFOHEADER * dibInfo, BYTE * bits, // if NULL, this is a packed DIB
UINT usage, DWORD rop ) { ASSERT(!Globals::IsNt);
INT bitsSize = GetDibBitsSize(dibInfo); UINT sizePalEntries;
if (GetDibNumPalEntries(FALSE, dibInfo->biSize, dibInfo->biBitCount, dibInfo->biCompression, dibInfo->biClrUsed, &sizePalEntries)) { // We need to get the palette size that corresponds to the type
// If we have a DIB_PAL_COLORS then each entry is 16bits
sizePalEntries *= ((usage == DIB_PAL_COLORS)?2:sizeof(RGBQUAD)); } else { sizePalEntries = 0 ; }
// We need at least a BITMAPINFO structure in there, but if there is a
// palette, calculate the full size of the structure including the
// palette
INT bitmapHeaderSize = sizeof(BITMAPINFOHEADER) + sizePalEntries; INT size = sizeof(EMRSTRETCHDIBITS) + bitmapHeaderSize + bitsSize ;
// We cannot use the CreateRecordToModify because the record has already
// been modified
size = (size + 3) & ~3; EMRSTRETCHDIBITS* emrStretchDIBits = (EMRSTRETCHDIBITS*) GpMalloc(size); if (emrStretchDIBits != NULL) { emrStretchDIBits->emr.iType = EmfRecordTypeStretchDIBits; emrStretchDIBits->emr.nSize = size; emrStretchDIBits->rclBounds = *bounds; emrStretchDIBits->xDest = dstX; emrStretchDIBits->yDest = dstY; emrStretchDIBits->xSrc = srcX; emrStretchDIBits->ySrc = srcY; emrStretchDIBits->cxSrc = srcWidth; emrStretchDIBits->cySrc = srcHeight; emrStretchDIBits->offBmiSrc = sizeof(EMRSTRETCHDIBITS); emrStretchDIBits->cbBmiSrc = bitmapHeaderSize; emrStretchDIBits->offBitsSrc = emrStretchDIBits->offBmiSrc + emrStretchDIBits->cbBmiSrc; emrStretchDIBits->cbBitsSrc = bitsSize; emrStretchDIBits->iUsageSrc = usage; emrStretchDIBits->dwRop = rop; emrStretchDIBits->cxDest = dstWidth; emrStretchDIBits->cyDest = dstHeight; GpMemcpy((BYTE*)emrStretchDIBits + emrStretchDIBits->offBmiSrc, dibInfo, emrStretchDIBits->cbBmiSrc); GpMemcpy((BYTE*)emrStretchDIBits + emrStretchDIBits->offBitsSrc, bits, emrStretchDIBits->cbBitsSrc);
::PlayEnhMetaFileRecord(hdc, HandleTable, (ENHMETARECORD *)emrStretchDIBits, NumObjects); GpFree(emrStretchDIBits); return TRUE; } return FALSE; }
BITMAPINFOHEADER * EmfEnumState::CreateModifiedDib( BITMAPINFOHEADER * srcDibInfo, BYTE * srcBits, UINT & usage, DWORD rop ) { BITMAPINFOHEADER * dstDibInfo = NULL; UINT numPalEntries; UINT dibBitsSize;
if ((srcDibInfo->biSize >= sizeof(BITMAPINFOHEADER)) && GetDibNumPalEntries(FALSE, srcDibInfo->biSize, srcDibInfo->biBitCount, srcDibInfo->biCompression, srcDibInfo->biClrUsed, &numPalEntries) && ((dibBitsSize = GetDibBitsSize(srcDibInfo)) > 0)) { if (numPalEntries == 2 && rop != SRCCOPY) { DWORD *rgb = (DWORD*) GetDibColorTable(srcDibInfo); if (rgb[0] == 0x00000000 && rgb[1] == 0x00FFFFFF) { return dstDibInfo; } }
// We need to pass in to ModifyDib the old Usage value because we haven't modified
// the bitmap yet. Once we do then we will return the new usage of the palette.
UINT oldUsage = usage; INT dstDibSize = GetModifiedDibSize(srcDibInfo, numPalEntries, dibBitsSize, usage);
if ((dstDibSize > 0) && CreateRecordToModify(dstDibSize)) { dstDibInfo = (BITMAPINFOHEADER *)ModifiedRecord; ModifyDib(oldUsage, srcDibInfo, srcBits, dstDibInfo, numPalEntries, dibBitsSize, ColorAdjustTypeBitmap); } } return dstDibInfo; }
VOID EmfEnumState::BitBlt( ) { const EMRBITBLT * bitBltRecord = (const EMRBITBLT *)GetPartialRecord();
DWORD rop = bitBltRecord->dwRop;
// If No-Op ROP, do nothing; just return
if ((rop & 0xFFFF0000) == (GDIP_NOOP_ROP3 & 0xFFFF0000)) { return; }
// On NT4, PATCOPYs fail to draw correctly if there is a skew/rotate
// in the matrix. So use a rectangle call instead.
if ((rop == PATCOPY) && Globals::IsNt && (Globals::OsVer.dwMajorVersion <= 4)) { XFORM xform; if (::GetWorldTransform(Hdc, &xform) && ((xform.eM12 != 0.0f) || (xform.eM21 != 0.0f))) { HPEN hPenOld = (HPEN)::SelectObject(Hdc, ::GetStockObject(NULL_PEN)); DWORD dcRop = ::GetROP2(Hdc);
if (dcRop != R2_COPYPEN) { ::SetROP2(Hdc, R2_COPYPEN); } ::Rectangle(Hdc, bitBltRecord->xDest, bitBltRecord->yDest, bitBltRecord->xDest + bitBltRecord->cxDest, bitBltRecord->yDest + bitBltRecord->cyDest); ::SelectObject(Hdc, hPenOld); if (dcRop != R2_COPYPEN) { ::SetROP2(Hdc, dcRop); } return; } }
if (rop != SRCCOPY && rop != NOTSRCCOPY && rop != PATCOPY && rop != BLACKNESS && rop != WHITENESS) { RopUsed = TRUE; }
if ((bitBltRecord->cbBitsSrc > 0) && (bitBltRecord->cbBmiSrc > 0) && IsSourceInRop3(rop)) { // Should we modify the dib if it is monochrome?
// What if there is a non-identity transform for the src DC?
UINT usage = bitBltRecord->iUsageSrc; BITMAPINFOHEADER * srcDibInfo = (BITMAPINFOHEADER *)(((BYTE *)bitBltRecord) + bitBltRecord->offBmiSrc); BYTE * srcBits = ((BYTE *)bitBltRecord) + bitBltRecord->offBitsSrc; BITMAPINFOHEADER * dstDibInfo = CreateModifiedDib(srcDibInfo, srcBits, usage, rop);
if (dstDibInfo != NULL) { srcDibInfo = dstDibInfo; srcBits = NULL; }
if (SrcCopyOnly && rop != SRCCOPY) { rop = SRCCOPY; }
OutputDIB(Hdc, &bitBltRecord->rclBounds, bitBltRecord->xDest, bitBltRecord->yDest, bitBltRecord->cxDest, bitBltRecord->cyDest, bitBltRecord->xSrc, bitBltRecord->ySrc, bitBltRecord->cxDest, bitBltRecord->cyDest, srcDibInfo, srcBits, usage, rop, FALSE); } else { if (SrcCopyOnly && rop != PATCOPY && !IsSourceInRop3(rop) && CreateCopyOfCurrentRecord()) { EMRBITBLT * newBitBltRecord = (EMRBITBLT *) ModifiedEmfRecord; newBitBltRecord->dwRop = PATCOPY; } ResetRecordBounds(); this->PlayRecord(); } }
VOID EmfEnumState::StretchBlt( ) { const EMRSTRETCHBLT * stretchBltRecord = (const EMRSTRETCHBLT *)GetPartialRecord();
DWORD rop = stretchBltRecord->dwRop;
// If No-Op ROP, do nothing; just return
if ((rop & 0xFFFF0000) == (GDIP_NOOP_ROP3 & 0xFFFF0000)) { return; }
if (rop != SRCCOPY && rop != NOTSRCCOPY && rop != PATCOPY && rop != BLACKNESS && rop != WHITENESS) { RopUsed = TRUE; }
if ((stretchBltRecord->cbBitsSrc > 0) && (stretchBltRecord->cbBmiSrc > 0) && IsSourceInRop3(rop)) { // Should we modify the dib if it is monochrome?
// What if there is a non-identity transform for the src DC?
UINT usage = stretchBltRecord->iUsageSrc; BITMAPINFOHEADER * srcDibInfo = (BITMAPINFOHEADER *)(((BYTE *)stretchBltRecord) + stretchBltRecord->offBmiSrc); BYTE * srcBits = ((BYTE *)stretchBltRecord) + stretchBltRecord->offBitsSrc; BITMAPINFOHEADER * dstDibInfo = CreateModifiedDib(srcDibInfo, srcBits, usage, rop);
if (SrcCopyOnly && rop != SRCCOPY) { rop = SRCCOPY; }
ASSERT(sizeof(XFORM) == sizeof(REAL)*6);
GpMatrix xForm((REAL*) &(stretchBltRecord->xformSrc));
if (dstDibInfo != NULL) { srcDibInfo = dstDibInfo; srcBits = NULL; }
GpRectF srcRect((REAL)stretchBltRecord->xSrc, (REAL)stretchBltRecord->ySrc, (REAL)stretchBltRecord->cxSrc, (REAL)stretchBltRecord->cySrc);
if (!xForm.IsIdentity()) { // We cannot use TransformRect, because the output rect will always
// have a positive Width and Height which we don't want
GpPointF points[2]; points[0] = GpPointF(srcRect.X, srcRect.Y); points[1] = GpPointF(srcRect.GetRight(), srcRect.GetBottom()); xForm.Transform(points, 2); srcRect.X = points[0].X; srcRect.Y = points[0].Y; srcRect.Width = points[1].X - points[0].X; srcRect.Height = points[1].Y - points[0].Y; }
// StretchBlt takes as parameters the top left corner of the dest
// whereas StretchDIBits takes the offset in the source image.
// For bottom up dibs those are not the same and we need to offset
// the srcrect's Y coodinate by the difference
if (srcDibInfo->biHeight > 0 && srcRect.Height < srcDibInfo->biHeight) { srcRect.Y = srcDibInfo->biHeight - srcRect.Height - srcRect.Y; }
OutputDIB(Hdc, &stretchBltRecord->rclBounds, stretchBltRecord->xDest, stretchBltRecord->yDest, stretchBltRecord->cxDest, stretchBltRecord->cyDest, GpRound(srcRect.X), GpRound(srcRect.Y), GpRound(srcRect.Width), GpRound(srcRect.Height), srcDibInfo, srcBits, usage, rop, FALSE); } else { if (SrcCopyOnly && rop != PATCOPY && !IsSourceInRop3(rop) && CreateCopyOfCurrentRecord()) { EMRSTRETCHBLT * stretchBltRecord = (EMRSTRETCHBLT *)ModifiedEmfRecord; stretchBltRecord->dwRop = PATCOPY; } ResetRecordBounds(); this->PlayRecord(); } }
VOID EmfEnumState::StretchDIBits( ) { const EMRSTRETCHDIBITS * stretchDIBitsRecord = (const EMRSTRETCHDIBITS *)GetPartialRecord();
DWORD rop = stretchDIBitsRecord->dwRop;
// If No-Op ROP, do nothing; just return
if ((rop & 0xFFFF0000) == (GDIP_NOOP_ROP3 & 0xFFFF0000)) { return; }
if (rop != SRCCOPY && rop != NOTSRCCOPY && rop != PATCOPY && rop != BLACKNESS && rop != WHITENESS) { RopUsed = TRUE; }
if ((stretchDIBitsRecord->cbBitsSrc > 0) && (stretchDIBitsRecord->cbBmiSrc > 0) && IsSourceInRop3(rop)) { UINT usage = stretchDIBitsRecord->iUsageSrc; BITMAPINFOHEADER * srcDibInfo = (BITMAPINFOHEADER *)(((BYTE *)stretchDIBitsRecord) + stretchDIBitsRecord->offBmiSrc); BYTE * srcBits = ((BYTE *)stretchDIBitsRecord) + stretchDIBitsRecord->offBitsSrc; BITMAPINFOHEADER * dstDibInfo = CreateModifiedDib(srcDibInfo, srcBits, usage, rop);
if (dstDibInfo != NULL) { srcDibInfo = dstDibInfo; srcBits = NULL; }
if (SrcCopyOnly && rop != SRCCOPY) { rop = SRCCOPY; }
OutputDIB(Hdc, &stretchDIBitsRecord->rclBounds, stretchDIBitsRecord->xDest, stretchDIBitsRecord->yDest, stretchDIBitsRecord->cxDest, stretchDIBitsRecord->cyDest, stretchDIBitsRecord->xSrc, stretchDIBitsRecord->ySrc, stretchDIBitsRecord->cxSrc, stretchDIBitsRecord->cySrc, srcDibInfo, srcBits, usage, rop, FALSE); } else { if (SrcCopyOnly && rop != PATCOPY && !IsSourceInRop3(rop) && CreateCopyOfCurrentRecord()) { EMRSTRETCHDIBITS* stretchDIBitsRecord = (EMRSTRETCHDIBITS *)ModifiedEmfRecord; stretchDIBitsRecord->dwRop = PATCOPY; } ResetRecordBounds(); this->PlayRecord(); } }
VOID EmfEnumState::SetDIBitsToDevice( ) { // !!! to do
// In SetDIBitsToDevice, the destination width and height
// are in device units but in StretchDIBits, they are in world units.
// Plus, the DIB header is for the entire DIB, but only part of the
// DIB may be here (based on the number of scans).
// So this record requires special handling if we are to process it.
ResetRecordBounds(); this->PlayRecord(); }
VOID EmfEnumState::CreateDibPatternBrushPt( ) { const EMRCREATEDIBPATTERNBRUSHPT * brushRecord = (const EMRCREATEDIBPATTERNBRUSHPT *)GetPartialRecord(); INT objectIndex = brushRecord->ihBrush;
if (ValidObjectIndex(objectIndex) && (HandleTable != NULL)) { UINT usage = brushRecord->iUsage; BITMAPINFOHEADER * srcDibInfo = (BITMAPINFOHEADER *)(((UNALIGNED BYTE *)brushRecord) + brushRecord->offBmi); BITMAPINFOHEADER * dstDibInfo = CreateModifiedDib(srcDibInfo, NULL, usage, SRCCOPY);
if (dstDibInfo != NULL) { HandleTable->objectHandle[objectIndex] = CreateDIBPatternBrushPt((BITMAPINFO *)dstDibInfo, usage); return; } }
this->PlayRecord(); }
inline static BOOL IsOfficeArtData( UINT recordSize, const EMRGDICOMMENT * commentRecord ) { return ((recordSize >= (12 + 4 + msocbOADataHeader)) && (commentRecord->cbData >= (msocbOADataHeader + 4)) && ((GpMemcmp(commentRecord->Data, msoszOADataHeader, msocbOADataHeader) == 0) || (GpMemcmp(commentRecord->Data, msoszOZDataHeader, msocbOZDataHeader) == 0))); }
inline static const EMROFFICECOMMENT * GetEmfComment( const BYTE * emfRecord, ULONG signature, UINT kind ) { const EMROFFICECOMMENT * emfComment = (const EMROFFICECOMMENT*)(emfRecord); if ((emfComment->ident == signature) && (emfComment->iComment == kind)) { return emfComment; } return NULL; }
VOID EmfEnumState::GdiComment( ) { // Skip Office Art data when playing into another metafile
if (IsMetafile() && IsOfficeArtData( GetCurrentRecordSize(), (const EMRGDICOMMENT *)GetPartialRecord())) { return; }
if (IsPostscript()) { if (GetEmfComment((BYTE*)CurrentEmfRecord, msosignature, msocommentBeginSrcCopy)) { SrcCopyOnly = TRUE; return; } if (GetEmfComment((BYTE*)CurrentEmfRecord, msosignature, msocommentEndSrcCopy)) { SrcCopyOnly = FALSE; return; } }
this->PlayRecord(); }
BOOL IsPenCosmetic( HDC hdc, int penWidth ) { penWidth <<= 7;
INT newPenWidth = penWidth; POINT points[2];
points[0].x = 0; points[0].y = 0; points[1].x = 1 << 7; points[1].y = 0;
if (::DPtoLP(hdc, points, 2)) { newPenWidth = points[1].x - points[0].x; if (newPenWidth < 0) { newPenWidth = -newPenWidth; } } return (penWidth <= newPenWidth); }
VOID EmfEnumState::CreatePen( ) { const EMRCREATEPEN * penRecord = (const EMRCREATEPEN *)GetPartialRecord(); DWORD oldStyle = penRecord->lopn.lopnStyle;
if (oldStyle == PS_NULL) { this->PlayRecord(); } else if (IsMetafile()) { ModifyRecordColor(4, ColorAdjustTypePen); this->PlayRecord(); } else { INT objectIndex = penRecord->ihPen;
if (ValidObjectIndex(objectIndex) && (HandleTable != NULL)) { LOGBRUSH logBrush;
logBrush.lbStyle = PS_SOLID; logBrush.lbColor = ModifyColor(penRecord->lopn.lopnColor, ColorAdjustTypePen); logBrush.lbHatch = 0;
INT penWidth = penRecord->lopn.lopnWidth.x; DWORD style;
if (!Globals::IsNt && !IsMetafile()) { //IsPenCosmetic is gonna call DPtoLP... Make sure to invalidate
//the transform before
CreateAndPlayCommentRecord(); }
if (IsPenCosmetic(Hdc, penWidth)) { switch (oldStyle) { case PS_SOLID: case PS_DASH: // on Win9x, cosmetic only
case PS_DOT: // on Win9x, cosmetic only
case PS_DASHDOT: // on Win9x, cosmetic only
case PS_DASHDOTDOT: // on Win9x, cosmetic only
break;
case PS_ALTERNATE: // cosmetic only, NT only
if (Globals::IsNt) { break; } // FALLTHRU
case PS_USERSTYLE: // NT only
case PS_INSIDEFRAME: // geometric only
default: oldStyle = PS_SOLID; break; } penWidth = 1; style = PS_COSMETIC | oldStyle; } else { switch (oldStyle) { case PS_SOLID: case PS_INSIDEFRAME: // geometric only
break;
case PS_DASH: // on Win9x, cosmetic only
case PS_DOT: // on Win9x, cosmetic only
case PS_DASHDOT: // on Win9x, cosmetic only
case PS_DASHDOTDOT: // on Win9x, cosmetic only
if (Globals::IsNt) { break; } // FALLTHRU
case PS_ALTERNATE: // cosmetic only, NT only
case PS_USERSTYLE: // NT only
default: oldStyle = PS_SOLID; break; } style = PS_GEOMETRIC | oldStyle | PS_ENDCAP_ROUND | PS_JOIN_ROUND; }
HandleTable->objectHandle[objectIndex] = ::ExtCreatePen(style, penWidth, &logBrush, 0, NULL); } } }
HFONT CreateTrueTypeFont( HFONT hFont ) { if (hFont) { if (Globals::IsNt) { LOGFONT logFont; if (GetObject(hFont, sizeof(logFont), &logFont) > 0) { logFont.lfOutPrecision = OUT_TT_ONLY_PRECIS; return CreateFontIndirect(&logFont); } else { WARNING1("GetObject for hFont failed"); }
} else { LOGFONTA logFont;
if (GetObjectA(hFont, sizeof(logFont), &logFont) > 0) { logFont.lfOutPrecision = OUT_TT_ONLY_PRECIS; // We have a bug in Win9x that the OUT_TT_ONLY_PRECIS flag is
// not always respected so if the font name is MS SANS SERIF
// change it to Times New Roman
if (lstrcmpiA(logFont.lfFaceName, "MS SANS SERIF") == 0) { GpMemcpy(logFont.lfFaceName, "Times New Roman", sizeof("Times New Roman")); } return CreateFontIndirectA(&logFont); } else { WARNING1("GetObject for hFont failed"); } } } else { WARNING1("NULL hFont"); } return NULL; }
VOID EmfEnumState::ExtCreateFontIndirect( ) { const EMREXTCREATEFONTINDIRECTW * fontRecord = (const EMREXTCREATEFONTINDIRECTW *)GetPartialRecord(); BOOL recordCopied = FALSE; if (!Globals::IsNt) { // We have a bug in Win9x that the OUT_TT_ONLY_PRECIS flag is
// not always respected so if the font name is MS SANS SERIF
// change it to Times New Roman
if (UnicodeStringCompareCI(fontRecord->elfw.elfFullName, L"MS SANS SERIF") == 0) { if (CreateCopyOfCurrentRecord()) { GpMemcpy(((EMREXTCREATEFONTINDIRECTW *)ModifiedEmfRecord)->elfw.elfFullName, L"Times New Roman", sizeof(L"Times New Roman")); recordCopied = TRUE; } } }
if (fontRecord->elfw.elfLogFont.lfOutPrecision != OUT_TT_ONLY_PRECIS) { if (recordCopied || CreateCopyOfCurrentRecord()) // Instruct GDI to use only True Type fonts, since bitmap fonts
// are not scalable.
{ ((EMREXTCREATEFONTINDIRECTW *)ModifiedEmfRecord)->elfw.elfLogFont.lfOutPrecision = OUT_TT_ONLY_PRECIS; } } this->PlayRecord(); }
VOID EmfEnumState::SelectObject( ) { const EMRSELECTOBJECT * selectRecord = (const EMRSELECTOBJECT *)GetPartialRecord(); DWORD handleIndex = selectRecord->ihObject;
// See if we're selecting in a stock font
if ((handleIndex & ENHMETA_STOCK_OBJECT) != 0) { handleIndex &= (~ENHMETA_STOCK_OBJECT);
// handleIndex >= (WHITE_BRUSH==0) && <= BLACK_PEN
if ((handleIndex <= BLACK_PEN) && (Recolor != NULL)) { union { LOGBRUSH lb; LOGPEN lp; };
RecolorStockObject* stockObj; int i;
for (stockObj = &RecolorStockObjectList[0], i = 0; i < NUM_STOCK_RECOLOR_OBJS; i++, stockObj++) { if (stockObj->Handle == handleIndex) { // Already have a cached recolored handle lying around.
HGDIOBJ stockHandle = RecoloredStockHandle[i];
if (stockHandle == NULL) { // No cached recolored stock object handle, recreate
// one here.
COLORREF newColor;
if (stockObj->Brush) { newColor = ModifyColor(stockObj->Color, ColorAdjustTypeBrush);
lb.lbStyle = BS_SOLID; lb.lbColor = newColor; lb.lbHatch = 0;
stockHandle = ::CreateBrushIndirect(&lb);
RecoloredStockHandle[i] = stockHandle; } else { newColor = ModifyColor(stockObj->Color, ColorAdjustTypePen);
lp.lopnStyle = PS_SOLID; lp.lopnWidth.x = 1; lp.lopnWidth.y = 0; lb.lbColor = newColor;
stockHandle = ::CreatePenIndirect(&lp);
RecoloredStockHandle[i] = stockHandle; } }
if (stockHandle != NULL) { ::SelectObject(Hdc, stockHandle); return; } } } } else if ((handleIndex >= OEM_FIXED_FONT) && (handleIndex <= DEFAULT_GUI_FONT)) { // It is a stock font -- create a true type font, instead of
// using the stock font directly to guarantee that we don't
// use bitmap fonts which don't scale well.
HFONT hFont = StockFonts[handleIndex - OEM_FIXED_FONT];
if (hFont == NULL) { hFont = CreateTrueTypeFont((HFONT)GetStockObject(handleIndex)); StockFonts[handleIndex - OEM_FIXED_FONT] = hFont; }
if (hFont != NULL) { ::SelectObject(Hdc, hFont); return; } } } this->PlayRecord();
// In case we select a region, intersect with the destrect
if (!Globals::IsNt) { if (((handleIndex & ENHMETA_STOCK_OBJECT) == 0) && (GetObjectTypeInternal((*HandleTable).objectHandle[handleIndex]) == OBJ_REGION)) { this->IntersectDestRect(); } } }
VOID EmfEnumState::ExtCreatePen( ) { const EMREXTCREATEPEN32 * penRecord = (const EMREXTCREATEPEN32 *)GetPartialRecord(); UINT brushStyle = penRecord->elp.elpBrushStyle;
if (brushStyle != BS_HOLLOW) { if (IsMetafile()) { if ((brushStyle == BS_SOLID) || (brushStyle == BS_HATCHED)) { ModifyRecordColor(8, ColorAdjustTypePen); } // else don't worry about recoloring pattern brushes for now
this->PlayRecord(); return; }
INT objectIndex = penRecord->ihPen;
if (ValidObjectIndex(objectIndex) && (HandleTable != NULL)) { if (!Globals::IsNt && !IsMetafile()) { //IsPenCosmetic is gonna call DPtoLP... Make sure to invalidate
//the transform before
CreateAndPlayCommentRecord(); }
DWORD penWidth = penRecord->elp.elpWidth; BOOL isCosmetic = IsPenCosmetic(Hdc, penWidth); DWORD oldStyle = penRecord->elp.elpPenStyle;
if (!Globals::IsNt) { DWORD style;
if (isCosmetic) { oldStyle &= PS_STYLE_MASK;
switch (oldStyle) { case PS_SOLID: case PS_DASH: // on Win9x, cosmetic only
case PS_DOT: // on Win9x, cosmetic only
case PS_DASHDOT: // on Win9x, cosmetic only
case PS_DASHDOTDOT: // on Win9x, cosmetic only
break;
case PS_ALTERNATE: // cosmetic only, NT only
case PS_USERSTYLE: // NT only
case PS_INSIDEFRAME: // geometric only
default: oldStyle = PS_SOLID; break; } penWidth = 1; style = PS_COSMETIC | oldStyle; } else { oldStyle &= (~PS_TYPE_MASK);
switch (oldStyle & PS_STYLE_MASK) { case PS_SOLID: case PS_INSIDEFRAME: // geometric only
break;
case PS_DASH: // on Win9x, cosmetic only
case PS_DOT: // on Win9x, cosmetic only
case PS_DASHDOT: // on Win9x, cosmetic only
case PS_DASHDOTDOT: // on Win9x, cosmetic only
case PS_ALTERNATE: // cosmetic only, NT only
case PS_USERSTYLE: // NT only
default: oldStyle = (oldStyle & (~PS_STYLE_MASK)) | PS_SOLID; break; } style = PS_GEOMETRIC | oldStyle; }
COLORREF color = RGB(0,0,0);
if ((brushStyle == BS_SOLID) || (brushStyle == BS_HATCHED)) { color = penRecord->elp.elpColor; }
color = ModifyColor(color, ColorAdjustTypePen);
// Only solid brushes are supported on Win9x
LOGBRUSH logBrush; logBrush.lbStyle = PS_SOLID; logBrush.lbColor = color; logBrush.lbHatch = 0;
HandleTable->objectHandle[objectIndex] = ::ExtCreatePen(style, penWidth, &logBrush, 0, NULL); return; }
// else it is NT
if ((brushStyle == BS_SOLID) || (brushStyle == BS_HATCHED)) { ModifyRecordColor(8, ColorAdjustTypePen); } // else don't worry about recoloring pattern brushes for now
if (isCosmetic && CreateCopyOfCurrentRecord()) { oldStyle &= PS_STYLE_MASK; if (oldStyle == PS_INSIDEFRAME) // geometric only
{ oldStyle = PS_SOLID; } ((EMREXTCREATEPEN32 *)ModifiedEmfRecord)->elp.elpPenStyle = PS_COSMETIC | oldStyle; ((EMREXTCREATEPEN32 *)ModifiedEmfRecord)->elp.elpWidth = 1; } } } this->PlayRecord(); }
VOID EmfEnumState::CreateBrushIndirect( ) { const EMRCREATEBRUSHINDIRECT * brushRecord = (const EMRCREATEBRUSHINDIRECT *)GetPartialRecord();
if (brushRecord->lb.lbStyle != BS_HOLLOW) { ModifyRecordColor(2, ColorAdjustTypeBrush);
if (ModifiedEmfRecord != NULL) { brushRecord = (const EMRCREATEBRUSHINDIRECT *)ModifiedEmfRecord; }
// See if we need to halftone the color. We do if it is a solid
// color, and we have a halftone palette, and the color is not
// an exact match in the palette.
COLORREF color;
if (IsHalftonePalette && (brushRecord->lb.lbStyle == BS_SOLID) && (((color = brushRecord->lb.lbColor) & 0x02000000) == 0)) { // create a halftone brush, instead of a solid brush
INT objectIndex = brushRecord->ihBrush;
if (ValidObjectIndex(objectIndex) && (HandleTable != NULL)) { BYTE dib[sizeof(BITMAPINFOHEADER) + // DIB 8 bpp header
(8 * sizeof(RGBQUAD)) + // DIB 8 colors
(8* 8)]; // DIB 8x8 pixels
HalftoneColorRef_216(color, dib);
HandleTable->objectHandle[objectIndex] = CreateDIBPatternBrushPt(dib, DIB_RGB_COLORS); return; } } } this->PlayRecord(); }
BOOL EmfEnumState::PlayRecord( ) { const ENHMETARECORD * recordToPlay = ModifiedEmfRecord;
// See if we've modified the record
if (recordToPlay == NULL) { // We haven't. See if we have a valid current record
if (CurrentEmfRecord != NULL) { recordToPlay = CurrentEmfRecord; } else { // we don't so we have to create one
if (!CreateCopyOfCurrentRecord()) { return FALSE; } recordToPlay = ModifiedEmfRecord; } } return PlayEnhMetaFileRecord(Hdc, HandleTable, recordToPlay, NumObjects); }
VOID EmfEnumState::RestoreHdc( ) { LONG relativeCount = ((const EMRRESTOREDC *)GetPartialRecord())->iRelative;
if (SaveDcCount < 0) { if (relativeCount >= SaveDcCount) { if (relativeCount >= 0) { // Modify the record
CreateCopyOfCurrentRecord(); // guaranteed to succeed
relativeCount = -1; ((EMRRESTOREDC *)ModifiedEmfRecord)->iRelative = -1; } } else { // Modify the record
CreateCopyOfCurrentRecord(); // guaranteed to succeed
relativeCount = SaveDcCount; ((EMRRESTOREDC *)ModifiedEmfRecord)->iRelative = relativeCount; } SaveDcCount -= relativeCount; this->PlayRecord(); } else { WARNING(("RestoreDC not matched to a SaveDC")); } }
VOID EmfEnumState::ModifyRecordColor( INT paramIndex, ColorAdjustType adjustType ) { COLORREF origColor = ((COLORREF *)RecordData)[paramIndex]; COLORREF modifiedColor = ModifyColor(origColor, adjustType);
if (modifiedColor != origColor) { if (CreateCopyOfCurrentRecord()) { *((COLORREF*)&(ModifiedEmfRecord->dParm[paramIndex])) = modifiedColor; } } }
VOID EmfEnumState::ExtEscape( ) { if (IsPostscriptPrinter()) { // Bug #98743 (Windows Bugs) Gdiplus must overcome GDI limitation
// with POSTSCRIPT_INJECTION. Comments from Rammanohar Arumugam:
//
// Being in xx-centric mode means POSTSCRIPT_DATA won't work. I
// take that to mean that PlayMetaFileRecord only works in
// compatibility mode.
//
// GdiPlus will check for the printer mode. In GDI-centric and
// Postscript-centric mode, it will not do PlayMetaFileRecord for
// any record that has POSTSCRIPT_DATA. Instead, it will output
// the postscript data through a PASSTHRU (for GDI-centric mode)
// or a POSTSCRIPT_PASSTHRU (for Postscript-Centric mode).
//
// You can find out the mode by querying the escape support.
// 1. Query for POSTSCRIPT_INJECTION support. If not supported,
// it's compat mode. If supported, find out the mode by doing step 2/3
// 2. Query for PASSTHROUGH support. If supported, it's GDI-centric.
// 3. Query for POSTSCRIPT_PASSTHROUGH support. If supported, it's PS-centric.
PEMREXTESCAPE escRecord = (PEMREXTESCAPE) RecordData;
// EMR emr;
// INT iEscape; // Escape code
// INT cbEscData; // Size of escape data
// BYTE EscData[1]; // Escape data
if (escRecord->iEscape == POSTSCRIPT_DATA) { if (Globals::IsNt) { DWORD EscapeValue = POSTSCRIPT_IDENTIFY;
if (::ExtEscape(Hdc, QUERYESCSUPPORT, sizeof(DWORD), (LPSTR)&EscapeValue, 0, NULL) <= 0) { // POSTSCRIPT_IDENTITY is not supported if the mode has
// been set because it can only be set once.
EscapeValue = POSTSCRIPT_PASSTHROUGH; if (::ExtEscape(Hdc, QUERYESCSUPPORT, sizeof(DWORD), (LPSTR)&EscapeValue, 0, NULL) <= 0) { // GDI-centric mode
if (CreateCopyOfCurrentRecord()) { ((EMREXTESCAPE *)ModifiedEmfRecord)->iEscape = PASSTHROUGH; } } else { // PS-centric mode
if (CreateCopyOfCurrentRecord()) { ((EMREXTESCAPE *)ModifiedEmfRecord)->iEscape = POSTSCRIPT_PASSTHROUGH; } }
this->PlayRecord(); return; } else { // compatibility mode uses POSTSCRIPT_DATA
} } else { // Win98 doesn't distinguish between GDI & compatibility mode
if (CreateCopyOfCurrentRecord()) { ((EMREXTESCAPE *)ModifiedEmfRecord)->iEscape = PASSTHROUGH; } } } }
this->PlayRecord(); }
EmfEnumState::EmfEnumState( HDC hdc, HENHMETAFILE hEmf, const RECT * dest, const RECT * deviceRect, BOOL externalEnumeration, InterpolationMode interpolation, DpContext * context, GpRecolor * recolor, ColorAdjustType adjustType ) : MfEnumState(hdc, externalEnumeration, interpolation, recolor, adjustType, deviceRect, context) { if (IsValid()) { ClipRgn = NULL; Palette = NULL; BrushOrg.x = 0; BrushOrg.y = 0;
// Bug 166280 from Office:
// PROBLEM: If the DC has any clipping region in it, EnumEnhMetaFile
// will create a region before calling the EnumProc for the
// first time. And, this region is not deleted and cannot be
// recovered through RestoreDC. (Only on Win9x)
// FIX: Before calling EnumEnhMetafile, save the clipping region
// and set the Clipping region to NULL. Select the saved
// clipping region in the CallBack at EMR_HEADER.
// We will not do this on Metafile DC. Put clipping region
// records in Metafile may cause other rendering problems.
if (!Globals::IsNt && !IsMetafile()) { HRGN clipRgn = ::CreateRectRgn(0,0,0,0);
if (clipRgn != NULL) { switch (::GetClipRgn(hdc, clipRgn)) { case -1: // error
case 0: // no initial clip region
::DeleteObject(clipRgn); break; case 1: // has initial clip region
::SelectClipRgn(hdc, NULL); ClipRgn = clipRgn; break; } } }
// Bug 160932 from Office: Redraw problems with EMFs
// The fix is to make the drawing independent of where
// the EMF is drawn - this can be done easily by setting the
// brush origin before the first record is played (in the
// record callback proc) to a value which is the top left of the
// output rectangle of the EMF in device coordinates (i.e. LPtoDP of
// the logical coordinate top left).
BrushOrg.x = dest->left; BrushOrg.y = dest->top; LPtoDP(hdc, &BrushOrg, 1);
// EnumEnhMetafile selects in the DEFAULT_PALETTE, but we may need
// another palette to remain selected in (for halftoning, etc.)
// so save the current palette and select it back in when the
// header record is received.
HPALETTE hpal = (HPALETTE)GetCurrentObject(hdc, OBJ_PAL); if (hpal != (HPALETTE)GetStockObject(DEFAULT_PALETTE)) { Palette = hpal; } BkColor = ::GetBkColor(hdc); TextColor = ::GetTextColor(hdc); } }
VOID EmfEnumState::Header( ) { ::SetBrushOrgEx(Hdc, BrushOrg.x, BrushOrg.y, NULL); if (ClipRgn != (HRGN)0) { ::SelectClipRgn(Hdc, ClipRgn); ::DeleteObject(ClipRgn); ClipRgn = NULL; } if (Palette != NULL) { ::SelectPalette(Hdc, Palette, TRUE); }
// Bitmap fonts are not good for playing metafiles because they
// don't scale well, so use a true type font instead as the default font.
HFONT hFont = CreateTrueTypeFont((HFONT)GetCurrentObject(Hdc, OBJ_FONT));
if (hFont != NULL) { DefaultFont = hFont; ::SelectObject(Hdc, hFont); }
this->PlayRecord(); }
VOID EmfEnumState::SelectPalette(INT objectIndex) { if (objectIndex == (ENHMETA_STOCK_OBJECT | DEFAULT_PALETTE)) { CurrentPalette = (HPALETTE)::GetStockObject(DEFAULT_PALETTE); } else { MfEnumState::SelectPalette(objectIndex); } }
VOID EmfEnumState::IntersectDestRect() { if (!IsMetafile()) { // Make the transform the identity
POINT windowOrg; SIZE windowExt; POINT viewportOrg; SIZE viewportExt; ::SetViewportOrgEx(Hdc, 0, 0, &viewportOrg); ::SetViewportExtEx(Hdc, 1, 1, &viewportExt); ::SetWindowOrgEx(Hdc, 0, 0, &windowOrg); ::SetWindowExtEx(Hdc, 1, 1, &windowExt);
// We are always in device units
::IntersectClipRect(Hdc, DestRectDevice.left, DestRectDevice.top, DestRectDevice.right, DestRectDevice.bottom);
// Restore the transform
::SetViewportOrgEx(Hdc, viewportOrg.x, viewportOrg.y, NULL); ::SetViewportExtEx(Hdc, viewportExt.cx, viewportExt.cy, NULL); ::SetWindowOrgEx(Hdc, windowOrg.x, windowOrg.y, NULL); ::SetWindowExtEx(Hdc, windowExt.cx, windowExt.cy, NULL); } }
VOID EmfEnumState::SetROP2() { DWORD dwROP = ((const EMRSETROP2 *)GetPartialRecord())->iMode;
if (dwROP != R2_BLACK && dwROP != R2_COPYPEN && dwROP != R2_NOTCOPYPEN && dwROP != R2_WHITE ) { RopUsed = TRUE; } this->PlayRecord(); }
VOID EmfEnumState::ExtTextOutW() { if (!this->PlayRecord()) { BYTE* emrTextOut = (BYTE*) GetPartialRecord(); if(CreateCopyOfCurrentRecord()) { // !!! Shouldn't this use the offset in the record?
BYTE * ptr = emrTextOut + sizeof(EMREXTTEXTOUTW); AnsiStrFromUnicode ansistr((WCHAR*)ptr); INT len = strlen(ansistr); // Don't forget to copy the NULL byte
GpMemcpy((BYTE*)ModifiedEmfRecord + sizeof(EMREXTTEXTOUTW), (char*)ansistr, len+1); EMREXTTEXTOUTA *record = (EMREXTTEXTOUTA*) ModifiedEmfRecord; record->emr.iType = EmfRecordTypeExtTextOutA;
// Keep the size of the record intact because of the spacing vector
this->PlayRecord(); } } }
VOID EmfEnumState::Rectangle() { // On NT convert the rectangle call to a polygon call because rectangle
// seem to have a special case that can draw outside of the metafile
// bounds. GDI seems to Ceil the coordinates instead of rounding them for
// rectangles.
if (!Globals::IsNt || IsMetafile()) { this->PlayRecord(); return; } const EMRRECTANGLE *emrRect = (const EMRRECTANGLE*) GetPartialRecord(); POINT points[4] = {emrRect->rclBox.left, emrRect->rclBox.top, emrRect->rclBox.right, emrRect->rclBox.top, emrRect->rclBox.right, emrRect->rclBox.bottom, emrRect->rclBox.left, emrRect->rclBox.bottom};
::Polygon(Hdc, points, 4); return; }
BOOL EmfEnumState::ProcessRecord( EmfPlusRecordType recordType, UINT recordDataSize, const BYTE * recordData ) { BOOL forceCallback = FALSE;
// See if we're doing enumeration for an external app
if (ExternalEnumeration) { if (recordData == NULL) { recordDataSize = 0; } else if (recordDataSize == 0) { recordData = NULL; }
// See if the app changed the record at all.
if ((recordType != RecordType) || (recordDataSize != RecordDataSize) || ((recordDataSize > 0) && ((CurrentEmfRecord == NULL) || (recordData != (const BYTE *)(const BYTE *)CurrentEmfRecord->dParm)))) { // Yes, we need to override what happened in StartRecord
CurrentEmfRecord = NULL; RecordType = recordType; RecordData = recordData; RecordDataSize = recordDataSize; } }
GDIP_TRY
switch (recordType) { case EmfRecordTypeHeader: this->Header(); break;
#if 0
// Do we really need to do anything for PolyPolygon records?
// If so, why not for PolyPolyline too?
case EmfRecordTypePolyPolygon: this->PolyPolygon(); break;
case EmfRecordTypePolyPolygon16: this->PolyPolygon16(); break; #endif
case EmfRecordTypeExtEscape: this->ExtEscape(); break;
case EmfRecordTypeSetPixelV: this->SetPixelV(); break;
case EmfRecordTypeSetTextColor: this->SetTextColor(); break;
case EmfRecordTypeSetBkColor: this->SetBkColor(); break;
case EmfRecordTypeSetMetaRgn: // Office Bug 154881. Win9x doesn't handle MetaRgn correctly.
if (Globals::IsNt) { this->PlayRecord(); } break;
case EmfRecordTypeSaveDC: this->SaveHdc(); break;
case EmfRecordTypeRestoreDC: this->RestoreHdc(); break;
case EmfRecordTypeCreatePen: this->CreatePen(); break;
case EmfRecordTypeCreateBrushIndirect: this->CreateBrushIndirect(); break;
case EmfRecordTypeSelectPalette: // We don't select in any palettes when playing the metafile,
// because we don't want to invalidate our halftoning palette.
// Keep track of the palette so we can map from PALETTEINDEXes
// to RGB values.
this->SelectPalette(((UINT32 *)recordData)[0]); break;
case EmfRecordTypeRealizePalette: // We don't want to invalidate our halftoning palette by realizing one
// from a metafile.
break;
case EmfRecordTypeExtFloodFill: this->ExtFloodFill(); break;
case EmfRecordTypeGdiComment: this->GdiComment(); break;
case EmfRecordTypeBitBlt: this->BitBlt(); forceCallback = TRUE; break;
case EmfRecordTypeStretchBlt: this->StretchBlt(); forceCallback = TRUE; break;
case EmfRecordTypeMaskBlt: this->MaskBlt(); forceCallback = TRUE; break;
case EmfRecordTypePlgBlt: this->PlgBlt(); forceCallback = TRUE; break;
case EmfRecordTypeSetDIBitsToDevice: this->SetDIBitsToDevice(); forceCallback = TRUE; break;
case EmfRecordTypeStretchDIBits: this->StretchDIBits(); forceCallback = TRUE; break;
// case EMR_CREATEMONOBRUSH:
// A monochrome brush uses the text color and the background color,
// so we shouldn't need to make any changes to the brush itself.
case EmfRecordTypeCreateDIBPatternBrushPt: this->CreateDibPatternBrushPt(); break;
case EmfRecordTypeExtCreatePen: this->ExtCreatePen(); break;
case EmfRecordTypeSetICMMode: case EmfRecordTypeCreateColorSpace: case EmfRecordTypeSetColorSpace: case EmfRecordTypeDeleteColorSpace: case EmfRecordTypeSetICMProfileA: case EmfRecordTypeSetICMProfileW: case EmfRecordTypeCreateColorSpaceW: if (Globals::IsNt || (!this->IsScreen() && !this->IsBitmap())) { this->PlayRecord(); } // else skip the record
break;
case EmfRecordTypeAlphaBlend: this->AlphaBlend(); forceCallback = TRUE; break;
case EmfRecordTypeTransparentBlt: this->TransparentBlt(); forceCallback = TRUE; break;
case EmfRecordTypeGradientFill: this->GradientFill(); forceCallback = TRUE; break;
case EmfRecordTypeExtCreateFontIndirect: this->ExtCreateFontIndirect(); break;
case EmfRecordTypeSelectObject: this->SelectObject(); break;
case EmfRecordTypeSelectClipPath: case EmfRecordTypeExtSelectClipRgn: case EmfRecordTypeOffsetClipRgn: this->PlayRecord(); if (!Globals::IsNt) { this->IntersectDestRect(); } break;
case EmfRecordTypeSetROP2: this->SetROP2(); break;
case EmfRecordTypeFillRgn: case EmfRecordTypeFrameRgn: case EmfRecordTypeInvertRgn: case EmfRecordTypePaintRgn: this->ResetRecordBounds(); this->PlayRecord(); break;
case EmfRecordTypeExtTextOutW: this->ExtTextOutW(); break;
case EmfRecordTypeRectangle: this->Rectangle(); break;
case EmfRecordTypeSetMapMode: case EmfRecordTypeSetViewportExtEx: case EmfRecordTypeSetViewportOrgEx: case EmfRecordTypeSetWindowExtEx: case EmfRecordTypeSetWindowOrgEx: case EmfRecordTypePolyBezier: case EmfRecordTypePolygon: case EmfRecordTypePolyline: case EmfRecordTypePolyBezierTo: case EmfRecordTypePolyLineTo: case EmfRecordTypePolyPolyline: case EmfRecordTypePolyPolygon: case EmfRecordTypeSetBrushOrgEx: case EmfRecordTypeEOF: case EmfRecordTypeSetMapperFlags: case EmfRecordTypeSetBkMode: case EmfRecordTypeSetPolyFillMode: case EmfRecordTypeSetStretchBltMode: case EmfRecordTypeSetTextAlign: case EmfRecordTypeSetColorAdjustment: case EmfRecordTypeMoveToEx: case EmfRecordTypeExcludeClipRect: case EmfRecordTypeIntersectClipRect: case EmfRecordTypeScaleViewportExtEx: case EmfRecordTypeScaleWindowExtEx: case EmfRecordTypeSetWorldTransform: case EmfRecordTypeModifyWorldTransform: case EmfRecordTypeDeleteObject: case EmfRecordTypeAngleArc: case EmfRecordTypeEllipse: case EmfRecordTypeRoundRect: case EmfRecordTypeArc: case EmfRecordTypeChord: case EmfRecordTypePie: case EmfRecordTypeCreatePalette: case EmfRecordTypeSetPaletteEntries: case EmfRecordTypeResizePalette: case EmfRecordTypeLineTo: case EmfRecordTypeArcTo: case EmfRecordTypePolyDraw: case EmfRecordTypeSetArcDirection: case EmfRecordTypeSetMiterLimit: case EmfRecordTypeBeginPath: case EmfRecordTypeEndPath: case EmfRecordTypeCloseFigure: case EmfRecordTypeFillPath: case EmfRecordTypeStrokeAndFillPath: case EmfRecordTypeStrokePath: case EmfRecordTypeFlattenPath: case EmfRecordTypeWidenPath: case EmfRecordTypeAbortPath: case EmfRecordTypeReserved_069: case EmfRecordTypeExtTextOutA: case EmfRecordTypePolyBezier16: case EmfRecordTypePolygon16: case EmfRecordTypePolyline16: case EmfRecordTypePolyBezierTo16: case EmfRecordTypePolylineTo16: case EmfRecordTypePolyPolyline16: case EmfRecordTypePolyPolygon16: case EmfRecordTypePolyDraw16: case EmfRecordTypeCreateMonoBrush: case EmfRecordTypePolyTextOutA: case EmfRecordTypePolyTextOutW: case EmfRecordTypeGLSRecord: case EmfRecordTypeGLSBoundedRecord: case EmfRecordTypePixelFormat: case EmfRecordTypeDrawEscape: case EmfRecordTypeStartDoc: case EmfRecordTypeSmallTextOut: case EmfRecordTypeForceUFIMapping: case EmfRecordTypeNamedEscape: case EmfRecordTypeColorCorrectPalette: case EmfRecordTypeSetLayout: case EmfRecordTypeReserved_117: case EmfRecordTypeSetLinkedUFIs: case EmfRecordTypeSetTextJustification: case EmfRecordTypeColorMatchToTargetW: // Play the current record.
// Even if it fails, we keep playing the rest of the metafile.
this->PlayRecord(); break;
default: // unknown record -- ignore it
WARNING1("Unknown EMF Record"); break; }
GDIP_CATCH forceCallback = TRUE; GDIP_ENDCATCH
return forceCallback; }
VOID EmfEnumState::ResetRecordBounds() { if (Globals::IsNt && IsMetafile()) { if (ModifiedEmfRecord == NULL) { CreateCopyOfCurrentRecord(); } // In case the previous call failed
if (ModifiedEmfRecord != NULL) { RECTL rect = {INT_MIN, INT_MIN, INT_MAX, INT_MAX}; EMRRCLBOUNDS *record = (EMRRCLBOUNDS*) ModifiedEmfRecord; record->rclBounds = rect; } } }
|