You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
2190 lines
79 KiB
2190 lines
79 KiB
/****************************** Module Header ******************************\
|
|
* Module Name: MfPlay16.c
|
|
*
|
|
* This file contains the routines for playing the GDI metafile. Most of these
|
|
* routines are adopted from windows gdi code. Most of the code is from
|
|
* win3.0 except for the GetEvent code which is taken from win2.1
|
|
*
|
|
* Created: 11-Oct-1989
|
|
*
|
|
* Copyright (c) 1985-1999 Microsoft Corporation
|
|
*
|
|
*
|
|
* Public Functions:
|
|
* PlayMetaFile
|
|
* PlayMetaFileRecord
|
|
* GetMetaFile
|
|
* DeleteMetaFile
|
|
* Private Functions:
|
|
* GetEvent
|
|
* IsDIBBlackAndWhite
|
|
*
|
|
* History:
|
|
* 02-Jul-1991 -by- John Colleran [johnc]
|
|
* Combined From Win 3.1 and WLO 1.0 sources
|
|
\***************************************************************************/
|
|
|
|
#include "precomp.h"
|
|
#pragma hdrstop
|
|
|
|
#include "mf16.h"
|
|
|
|
|
|
BOOL AddToHandleTable(LPHANDLETABLE lpHandleTable, HANDLE hObject, UINT noObjs);
|
|
BOOL CommonEnumMetaFile(HDC hdc, HMETAFILE hmf, MFENUMPROC proc, LPARAM lpData);
|
|
HANDLE CreateBitmapForDC (HDC hMemDC, LPBITMAPINFOHEADER lpDIBInfo);
|
|
WORD GetSizeOfColorTable (LPBITMAPINFOHEADER lpDIBInfo);
|
|
BOOL IsDIBBlackAndWhite(LPBITMAPINFOHEADER lpDIBInfo);
|
|
BOOL PlayIntoAMetafile(LPMETARECORD lpMR, HDC hdcDest);
|
|
|
|
#if DBG
|
|
UINT curRecord; // debuging helpers
|
|
UINT iBreakRecord = 0xFFFFFFFF;
|
|
#endif
|
|
|
|
/***************************** Public Function ****************************\
|
|
* BOOL APIENTRY PlayMetaFile(hdc, hmf)
|
|
* HDC hDC;
|
|
* HMETAFILE hMF;
|
|
*
|
|
* Play a windows metafile.
|
|
*
|
|
* History:
|
|
* 02-Jul-1991 -by- John Colleran [johnc]
|
|
* Ported from Windows and WLO
|
|
\***************************************************************************/
|
|
|
|
BOOL APIENTRY PlayMetaFile(HDC hdc, HMETAFILE hmf)
|
|
{
|
|
return (CommonEnumMetaFile(hdc, hmf, (MFENUMPROC)NULL, (LPARAM)0));
|
|
}
|
|
|
|
/******************************** Public Function **************************\
|
|
* BOOL EnumMetaFile(hmf)
|
|
*
|
|
* The EnumMetaFile function enumerates the GDI calls within the metafile
|
|
* identified by the hMF parameter. The EnumMetaFile function retrieves each
|
|
* GDI call within the metafile and passes it to the function pointed to by the
|
|
* pCallbackFunc parameter. This callback function, an application-supplied
|
|
* function, can process each GDI call as desired. Enumeration continues until
|
|
* there are no more GDI calls or the callback function returns zero.
|
|
*
|
|
*
|
|
* Effects:
|
|
*
|
|
\***************************************************************************/
|
|
|
|
BOOL EnumMetaFile(HDC hdc, HMETAFILE hmf, MFENUMPROC pCallBackFunction, LPARAM pClientData)
|
|
{
|
|
// Make sure that the callback function is given. CommonEnumMetaFile expects
|
|
// it to be given in EnumMetaFile.
|
|
|
|
if (!pCallBackFunction)
|
|
{
|
|
GdiSetLastError(ERROR_INVALID_PARAMETER );
|
|
return(FALSE);
|
|
}
|
|
|
|
return (CommonEnumMetaFile(hdc, hmf, pCallBackFunction, pClientData));
|
|
}
|
|
|
|
BOOL CommonEnumMetaFile(HDC hdc, HMETAFILE hmf, MFENUMPROC pCallBack, LPARAM pClientData)
|
|
{
|
|
BOOL fStatus = FALSE; // assume it fails
|
|
UINT ii;
|
|
UINT noObjs;
|
|
PMETAFILE16 pMF;
|
|
INT oldMapMode = -1;
|
|
PMETARECORD pMR = (PMETARECORD) NULL;
|
|
LPHANDLETABLE pht = (LPHANDLETABLE) NULL;
|
|
HFONT hLFont;
|
|
HBRUSH hLBrush;
|
|
HPALETTE hLPal;
|
|
HPEN hLPen;
|
|
HRGN hClipRgn = (HRGN)NULL;
|
|
SIZE sizeOldWndExt;
|
|
SIZE sizeOldVprtExt;
|
|
PDC_ATTR pDcAttr;
|
|
PLDC pldc;
|
|
int iGraphicsModeOld;
|
|
BOOL bMetaDC16 = FALSE;
|
|
FLONG flPlayMetaFile = (FLONG) 0;
|
|
|
|
// First validate the DC type and note whether or not we
|
|
// are playing into a 16bit metafile.Null hdc is allowed
|
|
// in win3.0 but disallowed in win3.1.
|
|
|
|
|
|
if(LO_TYPE(hdc) == LO_METADC16_TYPE)
|
|
{
|
|
bMetaDC16 = TRUE;
|
|
}
|
|
else if ((hdc == NULL) && pCallBack)
|
|
{
|
|
// Actually win9x can take NULL hdc. There are some image filter
|
|
// that actually pass in us NULL hdc. Only let NULL hdc thru if there is a
|
|
// callback routine. [bug 102767]
|
|
|
|
bMetaDC16 = TRUE;
|
|
}
|
|
else
|
|
if((LO_TYPE(hdc) != LO_DC_TYPE ) &&
|
|
(LO_TYPE(hdc) != LO_ALTDC_TYPE))
|
|
{
|
|
WARNING("CommonEnumMetaFile: bogus DC\n");
|
|
return(FALSE);
|
|
}
|
|
|
|
// need a pointer to pDcAttr for DC_PLAYMETAFILE flag
|
|
|
|
PSHARED_GET_VALIDATE((PVOID)pDcAttr,hdc,DC_TYPE);
|
|
|
|
if(!bMetaDC16 && !pDcAttr) {
|
|
WARNING("CommonEnumMetaFile: Couldn't Validate DC\n");
|
|
return(FALSE);
|
|
}
|
|
|
|
// we still need to PLDC in the case that we are printing and there is
|
|
// an abort proc
|
|
|
|
pldc = GET_PLDC(hdc);
|
|
|
|
PUTS("CommonEnumMetaFile\n");
|
|
|
|
#if DBG
|
|
curRecord = 0;
|
|
#endif
|
|
|
|
// Validate the 16 bit MetaFile
|
|
|
|
pMF = GET_PMF16(hmf);
|
|
if (pMF == NULL)
|
|
{
|
|
GdiSetLastError(ERROR_INVALID_HANDLE);
|
|
return(FALSE);
|
|
}
|
|
|
|
// Allocate memory for the handle table.
|
|
|
|
if ((noObjs = pMF->metaHeader.mtNoObjects) > 0)
|
|
if (!(pht = (LPHANDLETABLE) LocalAlloc(
|
|
LMEM_FIXED | LMEM_ZEROINIT,
|
|
sizeof(HANDLE) * pMF->metaHeader.mtNoObjects
|
|
+ sizeof(WORD)))) // need extra word?
|
|
return(FALSE);
|
|
|
|
// Save the old objects so we can put them back if this is not a metafile.
|
|
// Only do object save/reselect for real DC's.
|
|
|
|
if( !bMetaDC16 )
|
|
{
|
|
hLBrush = (HBRUSH) GetDCObject(hdc, LO_BRUSH_TYPE);
|
|
hLFont = (HFONT) GetDCObject(hdc, LO_FONT_TYPE);
|
|
hLPal = (HPALETTE) GetDCObject(hdc, LO_PALETTE_TYPE);
|
|
hLPen = (HPEN) GetDCObject(hdc, LO_PEN_TYPE);
|
|
|
|
// Set a bit in the DC to indicate that we are playing the metafile.
|
|
// This bit is cleared by CancelDC() to stop playing the metafile.
|
|
// At the same time, remember the previous DC_PLAYMETAFILE bit.
|
|
|
|
try
|
|
{
|
|
flPlayMetaFile = pDcAttr->ulDirty_ & DC_PLAYMETAFILE;
|
|
if (flPlayMetaFile)
|
|
{
|
|
PUTS("CommonEnumMetaFile: DC_PLAYMETAFILE bit is set!\n");
|
|
}
|
|
pDcAttr->ulDirty_ |= DC_PLAYMETAFILE;
|
|
}
|
|
except(EXCEPTION_EXECUTE_HANDLER)
|
|
{
|
|
WARNING("except in SetBkMode\n");
|
|
GdiSetLastError(ERROR_INVALID_PARAMETER);
|
|
return(FALSE);
|
|
}
|
|
|
|
// Create a region in case there is a clip region to receive from GetClipRgn
|
|
|
|
if (!(hClipRgn = CreateRectRgn(0,0,0,0)))
|
|
goto pmf_cleanup;
|
|
|
|
switch (GetClipRgn(hdc, hClipRgn))
|
|
{
|
|
case -1: // error
|
|
ASSERTGDI(FALSE, "GetClipRgn failed");
|
|
goto pmf_cleanup;
|
|
case 0: // no initial clip region
|
|
if (!DeleteObject(hClipRgn))
|
|
ASSERTGDI(FALSE, "CommonEnumMetaFile: Detele region failed\n");
|
|
hClipRgn = (HRGN) 0;
|
|
break;
|
|
case 1: // has initial clip region
|
|
break;
|
|
}
|
|
|
|
// The metafile is to be played in the compatible graphics mode only.
|
|
|
|
iGraphicsModeOld = GetGraphicsMode(hdc);
|
|
if (iGraphicsModeOld != GM_COMPATIBLE)
|
|
SetGraphicsMode(hdc, GM_COMPATIBLE);
|
|
}
|
|
|
|
// Are we doing an EnumMetaFile or PlayMetaFile
|
|
|
|
if (pCallBack)
|
|
{
|
|
fStatus = TRUE; // assume success
|
|
|
|
// EnumMetaFile
|
|
|
|
while (pMR = (PMETARECORD) GetEvent(pMF, pMR))
|
|
{
|
|
if (pMR == (PMETARECORD) -1)
|
|
{
|
|
fStatus = FALSE;
|
|
break;
|
|
}
|
|
|
|
if (!bMetaDC16 && !( pDcAttr->ulDirty_ & DC_PLAYMETAFILE))
|
|
{
|
|
WARNING("CommonEnumMetaFile: CancelDC called\n");
|
|
fStatus = FALSE;
|
|
break;
|
|
}
|
|
|
|
if (!(fStatus = (*pCallBack)(hdc, pht, (METARECORD FAR *) pMR,
|
|
(int) noObjs, pClientData)))
|
|
break;
|
|
|
|
#if DBG
|
|
curRecord++;
|
|
if (curRecord == iBreakRecord)
|
|
ASSERTGDI(FALSE, "CommonEnumMetaFile: iBreakRecord reached\n");
|
|
#endif
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// PlayMetaFile
|
|
|
|
fStatus = TRUE; // assume success
|
|
|
|
while (pMR = (PMETARECORD) GetEvent(pMF, pMR))
|
|
{
|
|
if (pMR == (PMETARECORD) -1)
|
|
{
|
|
fStatus = FALSE;
|
|
break;
|
|
}
|
|
|
|
if (!bMetaDC16 && !( pDcAttr->ulDirty_ & DC_PLAYMETAFILE))
|
|
{
|
|
WARNING("CommonEnumMetaFile: CancelDC called\n");
|
|
fStatus = FALSE;
|
|
break;
|
|
}
|
|
|
|
if (pldc && pldc->pfnAbort != NULL)
|
|
{
|
|
if (!(*pldc->pfnAbort)(hdc, 0))
|
|
{
|
|
fStatus = FALSE;
|
|
break;
|
|
}
|
|
}
|
|
|
|
// For win3.1 compatability, ignore the return value from PlayMetaFileRecord
|
|
|
|
PlayMetaFileRecord(hdc, pht, pMR, noObjs);
|
|
|
|
#if DBG
|
|
curRecord++;
|
|
if (curRecord == iBreakRecord)
|
|
ASSERTGDI(FALSE, "CommonEnumMetaFile: iBreakRecord reached\n");
|
|
#endif
|
|
}
|
|
}
|
|
|
|
// if we fail restoring an object, we need to select some
|
|
// default object so that we can DeleteObject any Metafile-
|
|
// selected objects
|
|
|
|
if( !bMetaDC16 )
|
|
{
|
|
if (iGraphicsModeOld != GM_COMPATIBLE)
|
|
SetGraphicsMode(hdc, iGraphicsModeOld);
|
|
|
|
if (!SelectObject(hdc,hLPen))
|
|
SelectObject(hdc,GetStockObject(BLACK_PEN));
|
|
|
|
if (!SelectObject(hdc,hLBrush))
|
|
SelectObject(hdc,GetStockObject(BLACK_BRUSH));
|
|
|
|
if (!SelectPalette(hdc, hLPal, FALSE))
|
|
SelectPalette(hdc, GetStockObject(DEFAULT_PALETTE), FALSE);
|
|
|
|
if (hLFont != (HFONT) GetDCObject(hdc, LO_FONT_TYPE))
|
|
{
|
|
if (!SelectObject(hdc,hLFont))
|
|
{
|
|
// if we cannot select the original font back in, we
|
|
// select the system font. this will allow us to delete
|
|
// the metafile font selected. to insure that the system
|
|
// font gets selected, we reset the DC's transform to
|
|
// default. after the selection, we restore this stuff
|
|
//
|
|
|
|
GetWindowExtEx(hdc, &sizeOldWndExt);
|
|
GetViewportExtEx(hdc, &sizeOldVprtExt);
|
|
oldMapMode = SetMapMode(hdc, MM_TEXT);
|
|
|
|
SelectObject(hdc,GetStockObject(SYSTEM_FONT));
|
|
|
|
SetMapMode(hdc,oldMapMode);
|
|
SetWindowExtEx( hdc, sizeOldWndExt.cx, sizeOldWndExt.cy, NULL);
|
|
SetViewportExtEx(hdc, sizeOldVprtExt.cx, sizeOldVprtExt.cy, NULL);
|
|
}
|
|
}
|
|
|
|
if (SelectClipRgn(hdc, hClipRgn) == RGN_ERROR)
|
|
SelectClipRgn(hdc, (HRGN) 0);
|
|
}
|
|
|
|
// Cleanup all created objects
|
|
|
|
for (ii = 0; ii < noObjs; ii++)
|
|
{
|
|
if (pht->objectHandle[ii])
|
|
if (!DeleteObject(pht->objectHandle[ii]))
|
|
ERROR_ASSERT(FALSE,
|
|
"CommonEnumMetaFile: DeleteObject(objectHandle) failed\n");
|
|
}
|
|
|
|
// if we fiddled with the map mode because we could not
|
|
// restore the original font, then maybe we can restore the
|
|
// font now
|
|
|
|
if (oldMapMode > 0)
|
|
SelectObject(hdc,hLFont);
|
|
|
|
pmf_cleanup:
|
|
|
|
if (pldc)
|
|
{
|
|
// Preserve the DC_PLAYMETAFILE bit.
|
|
// If we hit a CancelDC, then we will leave the bit clear.
|
|
|
|
ASSERTGDI(!(flPlayMetaFile & ~DC_PLAYMETAFILE),
|
|
"CommonEnumMetaFile: bad flPlayMetaFile\n");
|
|
|
|
if (!bMetaDC16 && !( pDcAttr->ulDirty_ & DC_PLAYMETAFILE) )
|
|
{
|
|
pDcAttr->ulDirty_ &= ~DC_PLAYMETAFILE;
|
|
pDcAttr->ulDirty_ |= flPlayMetaFile; // restore the original flag
|
|
}
|
|
}
|
|
|
|
if (hClipRgn)
|
|
if (!DeleteObject(hClipRgn))
|
|
ASSERTGDI(FALSE, "CommonEnumMetaFile: Delete region 2 failed\n");
|
|
|
|
if (pht)
|
|
if (LocalFree((HANDLE) pht))
|
|
ASSERTGDI(FALSE, "CommonEnumMetaFile: LocalFree failed\n");
|
|
|
|
return(fStatus);
|
|
}
|
|
|
|
/***************************** Internal Function **************************\
|
|
* BOOL NEAR PASCAL IsDIBBlackAndWhite
|
|
*
|
|
* Check to see if this DIB is a black and white DIB (and should be
|
|
* converted into a mono bitmap as opposed to a color bitmap).
|
|
*
|
|
* Returns: TRUE it is a B&W bitmap
|
|
* FALSE this is for color
|
|
*
|
|
* Effects: ?
|
|
*
|
|
* Warnings: ?
|
|
*
|
|
* History:
|
|
\***************************************************************************/
|
|
|
|
BOOL IsDIBBlackAndWhite(LPBITMAPINFOHEADER lpDIBInfo)
|
|
{
|
|
LPDWORD lpRGB;
|
|
|
|
PUTS("IsDIBBlackAndWhite\n");
|
|
|
|
ASSERTGDI(!((ULONG_PTR) lpDIBInfo & 0x3), "IsDIBBlackAndWhite: dword alignment error\n");
|
|
|
|
/* pointer color table */
|
|
lpRGB = (LPDWORD)((LPBITMAPINFO)lpDIBInfo)->bmiColors;
|
|
|
|
return (lpDIBInfo->biBitCount == 1
|
|
&& lpDIBInfo->biPlanes == 1
|
|
&& lpRGB[0] == (DWORD) 0
|
|
&& lpRGB[1] == (DWORD) 0xFFFFFF);
|
|
}
|
|
|
|
/***************************** Internal Function **************************\
|
|
* UseStretchDIBits
|
|
*
|
|
* set this directly to the device using StretchDIBits.
|
|
* if DIB is black&white, don't do this.
|
|
*
|
|
* Returns:
|
|
* TRUE --- operation successful
|
|
* FALSE -- decided not to use StretchDIBits
|
|
*
|
|
* History:
|
|
\***************************************************************************/
|
|
|
|
BOOL UseStretchDIB(HDC hDC, WORD magic, LPMETARECORD lpMR)
|
|
{
|
|
LPBITMAPINFOHEADER lpDIBInfo;
|
|
INT sExtX, sExtY;
|
|
INT sSrcX, sSrcY;
|
|
INT DstX, DstY, DstXE, DstYE;
|
|
|
|
if (magic == META_DIBBITBLT)
|
|
{
|
|
lpDIBInfo = (LPBITMAPINFOHEADER)&lpMR->rdParm[8];
|
|
|
|
DstX = (INT) (SHORT) lpMR->rdParm[7];
|
|
DstY = (INT) (SHORT) lpMR->rdParm[6];
|
|
sSrcX = (INT) (SHORT) lpMR->rdParm[3];
|
|
sSrcY = (INT) (SHORT) lpMR->rdParm[2];
|
|
DstXE = sExtX = (INT) (SHORT) lpMR->rdParm[5];
|
|
DstYE = sExtY = (INT) (SHORT) lpMR->rdParm[4];
|
|
}
|
|
else
|
|
{
|
|
lpDIBInfo = (LPBITMAPINFOHEADER)&lpMR->rdParm[10];
|
|
|
|
DstX = (INT) (SHORT) lpMR->rdParm[9];
|
|
DstY = (INT) (SHORT) lpMR->rdParm[8];
|
|
DstXE = (INT) (SHORT) lpMR->rdParm[7];
|
|
DstYE = (INT) (SHORT) lpMR->rdParm[6];
|
|
sSrcX = (INT) (SHORT) lpMR->rdParm[5];
|
|
sSrcY = (INT) (SHORT) lpMR->rdParm[4];
|
|
sExtX = (INT) (SHORT) lpMR->rdParm[3];
|
|
sExtY = (INT) (SHORT) lpMR->rdParm[2];
|
|
}
|
|
|
|
ASSERTGDI(!((ULONG_PTR) lpDIBInfo & 0x3), "UseStretchDIB: dword alignment error\n");
|
|
|
|
/* if DIB is black&white, we don't really want to do this */
|
|
if (IsDIBBlackAndWhite(lpDIBInfo))
|
|
return(FALSE);
|
|
|
|
// Need to flip the source y coordinates to call StretchDIBits.
|
|
|
|
sSrcY = ABS(lpDIBInfo->biHeight) - sSrcY - sExtY;
|
|
|
|
StretchDIBits(hDC, DstX, DstY, DstXE, DstYE,
|
|
sSrcX, sSrcY, sExtX, sExtY,
|
|
(LPBYTE)((LPSTR)lpDIBInfo + lpDIBInfo->biSize
|
|
+ GetSizeOfColorTable(lpDIBInfo)),
|
|
(LPBITMAPINFO)lpDIBInfo, DIB_RGB_COLORS,
|
|
(MAKELONG(lpMR->rdParm[0], lpMR->rdParm[1])));
|
|
return(TRUE);
|
|
}
|
|
|
|
BOOL
|
|
bValidExtent(PMETAFILE16 pmf16, LPMETARECORD lpMR, DWORD cbSize)
|
|
{
|
|
#if 0
|
|
// No absolute pointer validations as the records can be copied and played back.
|
|
BYTE *pB = (BYTE*)pmf16->hMem;
|
|
BYTE *pE = (BYTE*)lpMR + cbSize;
|
|
#endif
|
|
if (pmf16->fl & MF16_DISKFILE)
|
|
{
|
|
UINT64 fileSize;
|
|
if (!GetFileSizeEx(pmf16->hFile, (PLARGE_INTEGER)&fileSize))
|
|
{
|
|
EMFVALFAIL(("GetFileSize(%p) failed\n", pmf16->hFile));
|
|
return(FALSE);
|
|
}
|
|
|
|
if (cbSize > fileSize)
|
|
{
|
|
EMFVALFAIL(("Record Size (%d) larger than file size (%d)!\n", cbSize, (UINT32)fileSize));
|
|
return(FALSE);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (cbSize > (((PMETAHEADER)pmf16->hMem)->mtSize * sizeof(WORD)))
|
|
{
|
|
EMFVALFAIL(("Record Size (%d) larger than file size (%d)!\n", cbSize, (UINT32)(((PMETAHEADER)pmf16->hMem)->mtSize * sizeof(WORD))));
|
|
return(FALSE);
|
|
}
|
|
}
|
|
|
|
#if 0
|
|
// No absolute pointer validations as the records can be copied and played back.
|
|
if (pE < pB)
|
|
{
|
|
EMFVALFAIL(("End pointer(%p) is less than Begin pointer (%p). Arithmetic wrap around!\n", pE, pB));
|
|
return(FALSE);
|
|
}
|
|
#endif
|
|
return (TRUE);
|
|
}
|
|
|
|
/***************************** Internal Function **************************\
|
|
* GetEvent
|
|
*
|
|
* This routine will now open a disk metafile in READ_ONLY mode. This will
|
|
* allow us to play read-only metafiles or to share such file.
|
|
*
|
|
* To start the enumeration, the first lpMR must be NULL.
|
|
* It does not enumerate the first (header) and last (terminator) records.
|
|
*
|
|
* Returns: Next MetaFile Record to be played
|
|
* NULL if the next metafile record is the EOF record
|
|
* -1 if an error occurs.
|
|
*
|
|
\***************************************************************************/
|
|
|
|
PMETARECORD GetEvent(PMETAFILE16 pmf16, PMETARECORD lpMR)
|
|
{
|
|
PMETARECORD lpMRNext;
|
|
|
|
PUTS("GetEvent\n");
|
|
|
|
if (lpMR == (PMETARECORD) NULL)
|
|
{
|
|
if (!bValidExtent(pmf16, (PMETARECORD)pmf16, sizeof(METAHEADER)))
|
|
{
|
|
EMFVALFAIL(("GetEvent: bValidExtent(%p) (%p) (%08x) failed\n", pmf16, pmf16, sizeof(METAHEADER)));
|
|
return((PMETARECORD) -1);
|
|
}
|
|
pmf16->iMem = sizeof(METAHEADER);
|
|
}
|
|
else
|
|
{
|
|
if (lpMR->rdSize * sizeof(WORD) < lpMR->rdSize)
|
|
{
|
|
EMFVALFAIL(("GetEvent: arithmetic overflow\n"));
|
|
return((PMETARECORD) -1);
|
|
}
|
|
if (lpMR->rdSize == 0 || !bValidExtent(pmf16, lpMR, lpMR->rdSize * sizeof(WORD)))
|
|
{
|
|
EMFVALFAIL(("GetEvent: bValidExtent(%p) (%p) (%08x) failed\n", pmf16, lpMR, lpMR->rdSize * sizeof(WORD)));
|
|
return((PMETARECORD) -1);
|
|
}
|
|
pmf16->iMem += (lpMR->rdSize * sizeof(WORD));
|
|
}
|
|
// Make sure that we don't read past the EOF. A minimal record includes
|
|
// rdSize (DWORD) and rdFunction (WORD).
|
|
|
|
if (pmf16->iMem > pmf16->metaHeader.mtSize * sizeof(WORD) - sizeof(DWORD) - sizeof(WORD))
|
|
{
|
|
VERIFYGDI(FALSE, "GetEvent: Metafile contains bad data\n");
|
|
return((PMETARECORD) -1);
|
|
}
|
|
|
|
lpMRNext = (PMETARECORD) ((LPBYTE) pmf16->hMem + pmf16->iMem);
|
|
|
|
// If we are at the end of the metafile then return NULL.
|
|
|
|
if (lpMRNext->rdFunction == 0)
|
|
return((PMETARECORD) NULL);
|
|
|
|
return(lpMRNext);
|
|
}
|
|
|
|
/***************************** Internal Function **************************\
|
|
* BOOL GDIENTRY PlayMetaFileRecord
|
|
*
|
|
* Plays a metafile record by executing the GDI function call contained
|
|
* withing the metafile record
|
|
*
|
|
* Effects:
|
|
*
|
|
\***************************************************************************/
|
|
|
|
//LPSTR lpZapfDingbats = "ZAPFDINGBATS";
|
|
//LPSTR lpZapf_Dingbats = "ZAPF DINGBATS";
|
|
//LPSTR lpSymbol = "SYMBOL";
|
|
//LPSTR lpTmsRmn = "TMS RMN";
|
|
//LPSTR lpHelv = "HELV";
|
|
|
|
#define PITCH_MASK ( FIXED_PITCH | VARIABLE_PITCH )
|
|
|
|
BOOL
|
|
APIENTRY PlayMetaFileRecord(
|
|
HDC hdc,
|
|
LPHANDLETABLE lpHandleTable,
|
|
LPMETARECORD lpMR,
|
|
UINT noObjs
|
|
)
|
|
{
|
|
BOOL fStatus = FALSE;
|
|
LPMETARECORD lpMRdup = (LPMETARECORD) NULL;
|
|
WORD magic;
|
|
HANDLE hObject;
|
|
HANDLE hOldObject;
|
|
HBRUSH hBrush;
|
|
HRGN hRgn;
|
|
HANDLE hPal;
|
|
|
|
PUTSX("PlayMetaFileRecord 0x%p\n", lpMR);
|
|
|
|
magic = lpMR->rdFunction;
|
|
|
|
switch (magic & 255)
|
|
{
|
|
case (META_BITBLT & 255):
|
|
case (META_STRETCHBLT & 255):
|
|
{
|
|
HDC hSDC;
|
|
HANDLE hBitmap;
|
|
PBITMAP16 lpBitmap16;
|
|
INT delta = 0;
|
|
DWORD rop;
|
|
|
|
WARNING("PlayMetaFileRecord: obsolete META_BITBLT/META_STRETCHBLT record\n");
|
|
|
|
/* if playing into another Metafile, do direct copy */
|
|
if (PlayIntoAMetafile(lpMR, hdc))
|
|
{
|
|
fStatus = TRUE;
|
|
break;
|
|
}
|
|
|
|
if ((lpMR->rdSize - 3) == ((DWORD) magic >> 8))
|
|
{
|
|
hSDC = hdc;
|
|
delta = 1;
|
|
}
|
|
else
|
|
{
|
|
LPMETARECORD lpMRtmp;
|
|
|
|
// Make the bitmap bits dword aligned. To do this,
|
|
// lpMR has to fall on a dword aligned even address so that
|
|
// the bitmap bits (&lpMR->rdParm[8+5] or &lpMR->rdParm[10+5])
|
|
// will fall on the dword aligned addresses.
|
|
|
|
if (!(lpMRdup = (LPMETARECORD) LocalAlloc(LMEM_FIXED,
|
|
(UINT) lpMR->rdSize * sizeof(WORD))))
|
|
break;
|
|
lpMRtmp = lpMRdup;
|
|
RtlCopyMemory((PBYTE) lpMRtmp,
|
|
(PBYTE) lpMR,
|
|
(UINT) lpMR->rdSize * sizeof(WORD));
|
|
|
|
if (hSDC = CreateCompatibleDC(hdc))
|
|
{
|
|
if (magic == META_BITBLT)
|
|
lpBitmap16 = (PBITMAP16) &lpMRtmp->rdParm[8];
|
|
else
|
|
lpBitmap16 = (PBITMAP16) &lpMRtmp->rdParm[10];
|
|
|
|
if (hBitmap = CreateBitmap(lpBitmap16->bmWidth,
|
|
lpBitmap16->bmHeight,
|
|
lpBitmap16->bmPlanes,
|
|
lpBitmap16->bmBitsPixel,
|
|
(LPBYTE)&lpBitmap16->bmBits))
|
|
hOldObject = SelectObject(hSDC, hBitmap);
|
|
else
|
|
goto PMFR_BitBlt_cleanup;
|
|
}
|
|
else
|
|
break;
|
|
}
|
|
|
|
rop = MAKELONG(lpMR->rdParm[0], lpMR->rdParm[1]);
|
|
|
|
if (magic == META_BITBLT)
|
|
fStatus = BitBlt(hdc,
|
|
(int) (SHORT) lpMR->rdParm[7 + delta],
|
|
(int) (SHORT) lpMR->rdParm[6 + delta],
|
|
(int) (SHORT) lpMR->rdParm[5 + delta],
|
|
(int) (SHORT) lpMR->rdParm[4 + delta],
|
|
(delta && !ISSOURCEINROP3(rop)) ? 0 : hSDC,
|
|
(int) (SHORT) lpMR->rdParm[3],
|
|
(int) (SHORT) lpMR->rdParm[2],
|
|
rop);
|
|
else
|
|
fStatus = StretchBlt(hdc,
|
|
(int) (SHORT) lpMR->rdParm[9 + delta],
|
|
(int) (SHORT) lpMR->rdParm[8 + delta],
|
|
(int) (SHORT) lpMR->rdParm[7 + delta],
|
|
(int) (SHORT) lpMR->rdParm[6 + delta],
|
|
(delta && !ISSOURCEINROP3(rop)) ? 0 : hSDC,
|
|
(int) (SHORT) lpMR->rdParm[5],
|
|
(int) (SHORT) lpMR->rdParm[4],
|
|
(int) (SHORT) lpMR->rdParm[3],
|
|
(int) (SHORT) lpMR->rdParm[2],
|
|
rop);
|
|
|
|
if (hSDC != hdc)
|
|
{
|
|
if (!SelectObject(hSDC, hOldObject))
|
|
ASSERTGDI(FALSE, "PlayMetaFileRecord: SelectObject Bitblt Failed\n");
|
|
if (!DeleteObject(hBitmap))
|
|
ASSERTGDI(FALSE, "PlayMetaFileRecord: DeleteObject Bitblt Failed\n");
|
|
PMFR_BitBlt_cleanup:
|
|
if (!DeleteDC(hSDC))
|
|
ASSERTGDI(FALSE, "PlayMetaFileRecord: DeleteDC BitBlt Failed\n");
|
|
}
|
|
}
|
|
break;
|
|
|
|
case (META_DIBBITBLT & 255):
|
|
case (META_DIBSTRETCHBLT & 255):
|
|
{
|
|
HDC hSDC;
|
|
HANDLE hBitmap;
|
|
LPBITMAPINFOHEADER lpDIBInfo ;
|
|
INT delta = 0;
|
|
HANDLE hOldPal;
|
|
|
|
/* if playing into another metafile, do direct copy */
|
|
if (PlayIntoAMetafile(lpMR, hdc))
|
|
{
|
|
fStatus = TRUE;
|
|
break;
|
|
}
|
|
|
|
if ((lpMR->rdSize - 3) == ((DWORD) magic >> 8))
|
|
{
|
|
hSDC = hdc;
|
|
delta = 1;
|
|
}
|
|
else
|
|
{
|
|
LPMETARECORD lpMRtmp;
|
|
|
|
// Make the bitmap info and bits dword aligned. To do this,
|
|
// lpMR has to fall on a non dword aligned even address so that
|
|
// the bitmap info (&lpMR->rdParm[8] or &lpMR->rdParm[10]) and
|
|
// the bitmap bits will fall on the dword aligned addresses.
|
|
// Note that the size of the bitmap info is always a multiple
|
|
// of 4.
|
|
|
|
if (!(lpMRdup = (LPMETARECORD) LocalAlloc(LMEM_FIXED,
|
|
(UINT) lpMR->rdSize * sizeof(WORD) + sizeof(WORD))))
|
|
break;
|
|
lpMRtmp = (LPMETARECORD) &((PWORD) lpMRdup)[1];
|
|
RtlCopyMemory((PBYTE) lpMRtmp,
|
|
(PBYTE) lpMR,
|
|
(UINT) lpMR->rdSize * sizeof(WORD));
|
|
|
|
if (UseStretchDIB(hdc, magic, lpMRtmp))
|
|
{
|
|
fStatus = TRUE;
|
|
break;
|
|
}
|
|
|
|
if (hSDC = CreateCompatibleDC(hdc))
|
|
{
|
|
/* set up the memDC to have the same palette */
|
|
hOldPal = SelectPalette(hSDC, GetCurrentObject(hdc,OBJ_PAL), TRUE);
|
|
|
|
if (magic == META_DIBBITBLT)
|
|
lpDIBInfo = (LPBITMAPINFOHEADER)&lpMRtmp->rdParm[8];
|
|
else
|
|
lpDIBInfo = (LPBITMAPINFOHEADER)&lpMRtmp->rdParm[10];
|
|
|
|
/* now create the bitmap for the MemDC and fill in the bits */
|
|
/* the processing for old and new format of metafiles is
|
|
different here (till hBitmap is obtained) */
|
|
|
|
/* new metafile version */
|
|
hBitmap = CreateBitmapForDC (hdc,lpDIBInfo);
|
|
|
|
if (hBitmap)
|
|
hOldObject = SelectObject (hSDC, hBitmap) ;
|
|
else
|
|
goto PMFR_DIBBITBLT_cleanup;
|
|
}
|
|
else
|
|
break;
|
|
}
|
|
|
|
if (magic == META_DIBBITBLT)
|
|
fStatus = BitBlt(hdc,
|
|
(int) (SHORT) lpMR->rdParm[7 + delta],
|
|
(int) (SHORT) lpMR->rdParm[6 + delta],
|
|
(int) (SHORT) lpMR->rdParm[5 + delta],
|
|
(int) (SHORT) lpMR->rdParm[4 + delta],
|
|
delta ? 0 : hSDC,
|
|
(int) (SHORT) lpMR->rdParm[3],
|
|
(int) (SHORT) lpMR->rdParm[2],
|
|
MAKELONG(lpMR->rdParm[0], lpMR->rdParm[1]));
|
|
else
|
|
fStatus = StretchBlt(hdc,
|
|
(int) (SHORT) lpMR->rdParm[9 + delta],
|
|
(int) (SHORT) lpMR->rdParm[8 + delta],
|
|
(int) (SHORT) lpMR->rdParm[7 + delta],
|
|
(int) (SHORT) lpMR->rdParm[6 + delta],
|
|
delta ? 0 : hSDC,
|
|
(int) (SHORT) lpMR->rdParm[5],
|
|
(int) (SHORT) lpMR->rdParm[4],
|
|
(int) (SHORT) lpMR->rdParm[3],
|
|
(int) (SHORT) lpMR->rdParm[2],
|
|
MAKELONG(lpMR->rdParm[0], lpMR->rdParm[1]));
|
|
|
|
if (hSDC != hdc)
|
|
{
|
|
/* Deselect hDC's palette from memDC */
|
|
SelectPalette(hSDC, hOldPal, TRUE);
|
|
if (!SelectObject(hSDC, hOldObject))
|
|
ASSERTGDI(FALSE, "PlayMetaFileRecord: SelectObject DIBBitBlt Failed\n");
|
|
if (!DeleteObject(hBitmap))
|
|
ASSERTGDI(FALSE, "PlayMetaFileRecord: DeleteObject(hBitmap) DIBBitBlt Failed\n");
|
|
PMFR_DIBBITBLT_cleanup:
|
|
if (!DeleteDC(hSDC))
|
|
ASSERTGDI(FALSE, "PlayMetaFileRecord DeleteDC DIBBitblt failed\n");
|
|
}
|
|
}
|
|
break;
|
|
|
|
case (META_SELECTOBJECT & 255):
|
|
{
|
|
if (hObject = lpHandleTable->objectHandle[lpMR->rdParm[0]])
|
|
{
|
|
fStatus = SelectObject(hdc, hObject) != (HANDLE)0;
|
|
|
|
// new in win3.1
|
|
if (!fStatus)
|
|
{
|
|
switch (GetObjectType(hObject))
|
|
{
|
|
case OBJ_PAL:
|
|
SelectObject(hdc, (HGDIOBJ) GetStockObject(DEFAULT_PALETTE));
|
|
break;
|
|
case OBJ_BRUSH:
|
|
SelectObject(hdc, (HGDIOBJ) GetStockObject(WHITE_BRUSH));
|
|
break;
|
|
case OBJ_PEN:
|
|
SelectObject(hdc, (HGDIOBJ) GetStockObject(BLACK_PEN));
|
|
break;
|
|
case OBJ_FONT:
|
|
SelectObject(hdc, (HGDIOBJ) GetStockObject(DEVICE_DEFAULT_FONT));
|
|
break;
|
|
case OBJ_REGION:
|
|
SelectClipRgn(hdc, 0);
|
|
break;
|
|
default:
|
|
ASSERTGDI(FALSE,
|
|
"PlayMetaFileRecord:SELECTOBJECT unknown object\n");
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
|
|
case (META_CREATEPENINDIRECT & 255):
|
|
{
|
|
LOGPEN lp;
|
|
|
|
LOGPEN32FROMLOGPEN16(&lp, (PLOGPEN16) &lpMR->rdParm[0]);
|
|
if (hObject = CreatePenIndirect(&lp))
|
|
fStatus = AddToHandleTable(lpHandleTable, hObject, noObjs);
|
|
}
|
|
break;
|
|
|
|
case (META_CREATEFONTINDIRECT & 255):
|
|
{
|
|
LOGFONTA lf;
|
|
PLOGFONT16 plf16 = (PLOGFONT16) &lpMR->rdParm[0];
|
|
CHAR achCapString[LF_FACESIZE];
|
|
|
|
LOGFONT32FROMLOGFONT16(&lf, (PLOGFONT16) &lpMR->rdParm[0]);
|
|
|
|
// Capitalize the string for faster compares.
|
|
|
|
lstrcpynA(achCapString, lf.lfFaceName, LF_FACESIZE);
|
|
CharUpperBuffA(achCapString, LF_FACESIZE);
|
|
|
|
// Here we are going to implement a bunch of Win 3.1 hacks rather
|
|
// than contaminate the 32-bit engine. These same hacks can be found
|
|
// in WOW (in the CreateFont/CreateFontIndirect code).
|
|
//
|
|
// These hacks are keyed off the facename in the LOGFONTA. String
|
|
// comparisons have been unrolled for maximal performance.
|
|
|
|
// Win 3.1 facename-based hack. Some apps, like
|
|
// Publisher, create a "Helv" font but have the lfPitchAndFamily
|
|
// set to specify FIXED_PITCH. To work around this, we will patch
|
|
// the pitch field for a "Helv" font to be variable.
|
|
|
|
// if ( !lstrcmp(achCapString, lpHelv) )
|
|
|
|
if ( ((achCapString[0] == 'H') &&
|
|
(achCapString[1] == 'E') &&
|
|
(achCapString[2] == 'L') &&
|
|
(achCapString[3] == 'V') &&
|
|
(achCapString[4] == '\0')) )
|
|
{
|
|
lf.lfPitchAndFamily |= ( (lf.lfPitchAndFamily & ~PITCH_MASK) | VARIABLE_PITCH );
|
|
}
|
|
else
|
|
{
|
|
// Win 3.1 hack for Legacy 2.0. When a printer does not enumerate
|
|
// a "Tms Rmn" font, the app enumerates and gets the LOGFONTA for
|
|
// "Script" and then create a font with the name "Tms Rmn" but with
|
|
// the lfCharSet and lfPitchAndFamily taken from the LOGFONTA for
|
|
// "Script". Here we will over the lfCharSet to be ANSI_CHARSET.
|
|
|
|
// if ( !lstrcmp(achCapString, lpTmsRmn) )
|
|
|
|
if ( ((achCapString[0] == 'T') &&
|
|
(achCapString[1] == 'M') &&
|
|
(achCapString[2] == 'S') &&
|
|
(achCapString[3] == ' ') &&
|
|
(achCapString[4] == 'R') &&
|
|
(achCapString[5] == 'M') &&
|
|
(achCapString[6] == 'N') &&
|
|
(achCapString[7] == '\0')) )
|
|
{
|
|
lf.lfCharSet = ANSI_CHARSET;
|
|
}
|
|
else
|
|
{
|
|
// If the lfFaceName is "Symbol", "Zapf Dingbats", or "ZapfDingbats",
|
|
// enforce lfCharSet to be SYMBOL_CHARSET. Some apps (like Excel) ask
|
|
// for a "Symbol" font but have the char set set to ANSI. PowerPoint
|
|
// has the same problem with "Zapf Dingbats".
|
|
|
|
//if ( !lstrcmp(achCapString, lpSymbol) ||
|
|
// !lstrcmp(achCapString, lpZapfDingbats) ||
|
|
// !lstrcmp(achCapString, lpZapf_Dingbats) )
|
|
|
|
if ( ((achCapString[0] == 'S') &&
|
|
(achCapString[1] == 'Y') &&
|
|
(achCapString[2] == 'M') &&
|
|
(achCapString[3] == 'B') &&
|
|
(achCapString[4] == 'O') &&
|
|
(achCapString[5] == 'L') &&
|
|
(achCapString[6] == '\0')) ||
|
|
|
|
((achCapString[0] == 'Z') &&
|
|
(achCapString[1] == 'A') &&
|
|
(achCapString[2] == 'P') &&
|
|
(achCapString[3] == 'F') &&
|
|
(achCapString[4] == 'D') &&
|
|
(achCapString[5] == 'I') &&
|
|
(achCapString[6] == 'N') &&
|
|
(achCapString[7] == 'G') &&
|
|
(achCapString[8] == 'B') &&
|
|
(achCapString[9] == 'A') &&
|
|
(achCapString[10] == 'T') &&
|
|
(achCapString[11] == 'S') &&
|
|
(achCapString[12] == '\0')) ||
|
|
|
|
((achCapString[0] == 'Z') &&
|
|
(achCapString[1] == 'A') &&
|
|
(achCapString[2] == 'P') &&
|
|
(achCapString[3] == 'F') &&
|
|
(achCapString[4] == ' ') &&
|
|
(achCapString[5] == 'D') &&
|
|
(achCapString[6] == 'I') &&
|
|
(achCapString[7] == 'N') &&
|
|
(achCapString[8] == 'G') &&
|
|
(achCapString[9] == 'B') &&
|
|
(achCapString[10] == 'A') &&
|
|
(achCapString[11] == 'T') &&
|
|
(achCapString[12] == 'S') &&
|
|
(achCapString[13] == '\0')) )
|
|
{
|
|
lf.lfCharSet = SYMBOL_CHARSET;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (hObject = CreateFontIndirectA(&lf))
|
|
{
|
|
fStatus = AddToHandleTable(lpHandleTable, hObject, noObjs);
|
|
}
|
|
}
|
|
break;
|
|
|
|
case (META_CREATEPATTERNBRUSH & 255):
|
|
{
|
|
HANDLE hBitmap;
|
|
BITMAP Bitmap;
|
|
LPMETARECORD lpMRtmp;
|
|
|
|
WARNING("PlayMetaFileRecord: obsolete META_CREATEPATTERNBRUSH record\n");
|
|
|
|
// Make the bitmap bits dword aligned. To do this,
|
|
// lpMR has to fall on a non dword aligned even address so that
|
|
// the bitmap bits (bmBits) will fall on the dword aligned address.
|
|
|
|
if (!(lpMRdup = (LPMETARECORD) LocalAlloc(LMEM_FIXED,
|
|
(UINT) lpMR->rdSize * sizeof(WORD) + sizeof(WORD))))
|
|
break;
|
|
lpMRtmp = (LPMETARECORD) &((PWORD) lpMRdup)[1];
|
|
RtlCopyMemory((PBYTE) lpMRtmp,
|
|
(PBYTE) lpMR,
|
|
(UINT) lpMR->rdSize * sizeof(WORD));
|
|
|
|
BITMAP32FROMBITMAP16(&Bitmap, (PBITMAP16) &lpMRtmp->rdParm[0]);
|
|
// The magic number 18 is based on the IPBITMAP structure in win3.1
|
|
Bitmap.bmBits = (PBYTE) &lpMRtmp->rdParm + sizeof(BITMAP16) + 18;
|
|
|
|
if (hBitmap = CreateBitmapIndirect(&Bitmap))
|
|
{
|
|
if (hObject = CreatePatternBrush(hBitmap))
|
|
fStatus = AddToHandleTable(lpHandleTable, hObject, noObjs);
|
|
|
|
if (!DeleteObject(hBitmap))
|
|
ASSERTGDI(FALSE, "PlayMetaFileRecord: DeleteObject(hBitmap) CreatePatternBrush Failed\n");
|
|
}
|
|
}
|
|
break;
|
|
|
|
case (META_DIBCREATEPATTERNBRUSH & 255):
|
|
{
|
|
HDC hMemDC ;
|
|
HANDLE hBitmap;
|
|
LPBITMAPINFOHEADER lpDIBInfo ;
|
|
LPMETARECORD lpMRtmp;
|
|
|
|
// Make the bitmap info and bits dword aligned. To do this,
|
|
// lpMR has to fall on a non dword aligned even address so that
|
|
// the bitmap info (&lpMR->rdParm[2]) and
|
|
// the bitmap bits will fall on the dword aligned addresses.
|
|
// Note that the size of the bitmap info is always a multiple
|
|
// of 4.
|
|
|
|
if (!(lpMRdup = (LPMETARECORD) LocalAlloc(LMEM_FIXED,
|
|
(UINT) lpMR->rdSize * sizeof(WORD) + sizeof(WORD))))
|
|
break;
|
|
lpMRtmp = (LPMETARECORD) &((PWORD) lpMRdup)[1];
|
|
RtlCopyMemory((PBYTE) lpMRtmp,
|
|
(PBYTE) lpMR,
|
|
(UINT) lpMR->rdSize * sizeof(WORD));
|
|
|
|
|
|
if (lpMRtmp->rdParm[0] == BS_PATTERN)
|
|
{
|
|
/* the address of the second paramter is the address of the DIB
|
|
header, extract it */
|
|
lpDIBInfo = (LPBITMAPINFOHEADER) &lpMRtmp->rdParm[2];
|
|
|
|
/* now create a device dependend bitmap compatible to the default
|
|
screen DC - hScreenDC and extract the bits from the DIB into it.
|
|
The following function does all these, and returns a HANDLE
|
|
to the device dependent BItmap. */
|
|
|
|
/* we will use a dummy memory DC compatible to the screen DC */
|
|
hMemDC = CreateCompatibleDC((HDC)NULL);
|
|
|
|
if (!hMemDC)
|
|
{
|
|
ERROR_ASSERT(FALSE, "PlayMetaRecord: CreateCompDC Failed\n");
|
|
break;
|
|
}
|
|
|
|
hBitmap = CreateBitmapForDC(hMemDC,lpDIBInfo);
|
|
|
|
if (hBitmap)
|
|
{
|
|
if (hObject = CreatePatternBrush(hBitmap))
|
|
fStatus = AddToHandleTable(lpHandleTable, hObject, noObjs);
|
|
|
|
if (!DeleteObject(hBitmap))
|
|
ASSERTGDI(FALSE, "PlayMetaFileRecord: DeleteObject(hBitmap) DIBCreatePatternBrush Failed\n");
|
|
}
|
|
|
|
/* delete the dummy memory DC for new version Metafiles*/
|
|
if (!DeleteDC (hMemDC))
|
|
ASSERTGDI(FALSE, "PlayMetaRecord: DeleteDC DIBCreatePatternBrush Failed\n");
|
|
}
|
|
|
|
/* this is a DIBPattern brush */
|
|
else
|
|
{
|
|
if (hObject = CreateDIBPatternBrushPt((LPVOID)&lpMRtmp->rdParm[2],
|
|
(DWORD) lpMRtmp->rdParm[1]))
|
|
fStatus = AddToHandleTable(lpHandleTable, hObject, noObjs);
|
|
|
|
}
|
|
}
|
|
break;
|
|
|
|
case (META_CREATEBRUSHINDIRECT & 255):
|
|
{
|
|
LOGBRUSH lb;
|
|
|
|
LOGBRUSH32FROMLOGBRUSH16(&lb, (PLOGBRUSH16) &lpMR->rdParm[0]);
|
|
if (hObject = CreateBrushIndirect(&lb))
|
|
fStatus = AddToHandleTable(lpHandleTable, hObject, noObjs);
|
|
}
|
|
break;
|
|
|
|
case (META_POLYLINE & 255):
|
|
case (META_POLYGON & 255):
|
|
{
|
|
PPOINTL pptl;
|
|
UINT cpts = lpMR->rdParm[0];
|
|
|
|
if (!(pptl = (PPOINTL) LocalAlloc
|
|
(LMEM_FIXED, (UINT) cpts * sizeof(POINTL))))
|
|
break;
|
|
|
|
INT32FROMINT16(pptl, &lpMR->rdParm[1], cpts * 2);
|
|
|
|
switch (magic)
|
|
{
|
|
case META_POLYGON:
|
|
fStatus = Polygon(hdc, (LPPOINT) pptl, (int) cpts);
|
|
break;
|
|
case META_POLYLINE:
|
|
fStatus = Polyline(hdc, (LPPOINT) pptl, (int) cpts);
|
|
break;
|
|
default:
|
|
ASSERTGDI(FALSE, "Bad record type");
|
|
break;
|
|
}
|
|
|
|
if (LocalFree(pptl))
|
|
ASSERTGDI(FALSE, "PlayMetaRecord: LocalFree failed\n");
|
|
}
|
|
break;
|
|
|
|
case (META_POLYPOLYGON & 255):
|
|
{
|
|
PPOINTL pptl;
|
|
LPINT lpPolyCount;
|
|
PBYTE pb;
|
|
UINT ii;
|
|
UINT cpts = 0;
|
|
UINT cPoly = lpMR->rdParm[0];
|
|
|
|
for (ii = 0; ii < cPoly; ii++)
|
|
cpts += ((LPWORD)&lpMR->rdParm[1])[ii];
|
|
|
|
if (!(pb = (PBYTE) LocalAlloc
|
|
(
|
|
LMEM_FIXED,
|
|
cPoly * sizeof(INT) + cpts * sizeof(POINTL)
|
|
)
|
|
)
|
|
)
|
|
break;
|
|
|
|
lpPolyCount = (LPINT) pb;
|
|
pptl = (PPOINTL) (pb + cPoly * sizeof(INT));
|
|
|
|
for (ii = 0; ii < cPoly; ii++)
|
|
lpPolyCount[ii] = (INT) (UINT) ((LPWORD)&lpMR->rdParm[1])[ii];
|
|
|
|
INT32FROMINT16(pptl, &lpMR->rdParm[1] + cPoly, cpts * 2);
|
|
|
|
fStatus = PolyPolygon(hdc, (LPPOINT) pptl, lpPolyCount, (int) cPoly);
|
|
|
|
if (LocalFree((HANDLE) pb))
|
|
ASSERTGDI(FALSE, "PlayMetaRecord: LocalFree failed\n");
|
|
}
|
|
break;
|
|
|
|
case (META_EXTTEXTOUT & 255):
|
|
{
|
|
PSHORT lpdx16;
|
|
LPINT lpdx;
|
|
LPSTR lpch;
|
|
RECT rc;
|
|
LPRECT lprc;
|
|
|
|
lprc = (lpMR->rdParm[3] & (ETO_OPAQUE|ETO_CLIPPED))
|
|
? (LPRECT) &lpMR->rdParm[4]
|
|
: (LPRECT) NULL;
|
|
|
|
if (lprc)
|
|
{
|
|
rc.left = ((PRECT16)lprc)->left;
|
|
rc.right = ((PRECT16)lprc)->right;
|
|
rc.top = ((PRECT16)lprc)->top;
|
|
rc.bottom = ((PRECT16)lprc)->bottom;
|
|
lprc = &rc;
|
|
}
|
|
|
|
lpch = (LPSTR)&lpMR->rdParm[4] + ((lprc) ? sizeof(RECT16) : 0);
|
|
|
|
/* dx array starts at next word boundary after char string */
|
|
lpdx16 = (PSHORT) (lpch + ((lpMR->rdParm[2] + 1) / 2 * 2));
|
|
|
|
/* check to see if there is a Dx array by seeing if
|
|
structure ends after the string itself
|
|
*/
|
|
if (((DWORD)((LPWORD)lpdx16 - (LPWORD)(lpMR))) >= lpMR->rdSize)
|
|
lpdx = NULL;
|
|
else
|
|
{
|
|
lpdx = (LPINT)LocalAlloc(LMEM_FIXED, lpMR->rdParm[2]*sizeof(INT));
|
|
if (!lpdx)
|
|
{
|
|
ERROR_ASSERT(FALSE, "PlayMetaFileRecord: out of memory exttextout");
|
|
break;
|
|
}
|
|
INT32FROMINT16(lpdx, lpdx16, (UINT) lpMR->rdParm[2]);
|
|
}
|
|
|
|
// Mask off bit 0x80 that an old Excel used to add to its
|
|
// Metafiles and the GDI errors on.
|
|
fStatus = ExtTextOutA(hdc,
|
|
(int) (SHORT) lpMR->rdParm[1],
|
|
(int) (SHORT) lpMR->rdParm[0],
|
|
gbLpk ?
|
|
((UINT) lpMR->rdParm[3]) :
|
|
((UINT) lpMR->rdParm[3] & ~ETO_RTLREADING),
|
|
lprc,
|
|
lpch,
|
|
(UINT) lpMR->rdParm[2],
|
|
lpdx);
|
|
|
|
if (lpdx)
|
|
if (LocalFree((HANDLE)lpdx))
|
|
ASSERTGDI(FALSE, "PlayMetaRecord: LocalFree failed\n");
|
|
break;
|
|
}
|
|
|
|
case (META_TEXTOUT & 255):
|
|
fStatus = TextOutA(hdc,
|
|
(int) (SHORT) lpMR->rdParm[lpMR->rdSize-4],
|
|
(int) (SHORT) lpMR->rdParm[lpMR->rdSize-5],
|
|
(LPSTR) &lpMR->rdParm[1],
|
|
(int) (UINT) lpMR->rdParm[0]);
|
|
break;
|
|
|
|
case (META_ESCAPE & 255):
|
|
if (!(fStatus = PlayIntoAMetafile(lpMR, hdc)))
|
|
{
|
|
if ((int)(UINT)lpMR->rdParm[0] != MFCOMMENT)
|
|
{
|
|
fStatus = Escape(hdc,
|
|
(int) (UINT) lpMR->rdParm[0],
|
|
(int) (UINT) lpMR->rdParm[1],
|
|
(LPCSTR) &lpMR->rdParm[2],
|
|
(LPVOID) NULL) != 0;
|
|
}
|
|
else
|
|
{
|
|
fStatus = TRUE;
|
|
}
|
|
}
|
|
break;
|
|
|
|
case (META_FRAMEREGION & 255):
|
|
if ((hRgn = lpHandleTable->objectHandle[lpMR->rdParm[0]])
|
|
&& (hBrush = lpHandleTable->objectHandle[lpMR->rdParm[1]]))
|
|
fStatus = FrameRgn(hdc,
|
|
hRgn,
|
|
hBrush,
|
|
(int) (SHORT) lpMR->rdParm[3],
|
|
(int) (SHORT) lpMR->rdParm[2]);
|
|
break;
|
|
|
|
case (META_PAINTREGION & 255):
|
|
if (hRgn = lpHandleTable->objectHandle[lpMR->rdParm[0]])
|
|
fStatus = PaintRgn(hdc, hRgn);
|
|
break;
|
|
|
|
case (META_INVERTREGION & 255):
|
|
if (hRgn = lpHandleTable->objectHandle[lpMR->rdParm[0]])
|
|
fStatus = InvertRgn(hdc, hRgn);
|
|
break;
|
|
|
|
case (META_FILLREGION & 255):
|
|
if ((hRgn = lpHandleTable->objectHandle[lpMR->rdParm[0]])
|
|
&& (hBrush = lpHandleTable->objectHandle[lpMR->rdParm[1]]))
|
|
fStatus = FillRgn(hdc, hRgn, hBrush);
|
|
break;
|
|
|
|
/*
|
|
*** in win2, METACREATEREGION records contained an entire region object,
|
|
*** including the full header. this header changed in win3.
|
|
***
|
|
*** to remain compatible, the region records will be saved with the
|
|
*** win2 header. here we read a win2 header with region, and actually
|
|
*** create a win3 header with same region internals
|
|
*/
|
|
|
|
case (META_CREATEREGION & 255):
|
|
{
|
|
HRGN hrgn;
|
|
PSHORT pXs;
|
|
PWIN3REGION pW3Rgn = (PWIN3REGION) lpMR->rdParm;
|
|
UINT ii, jj;
|
|
UINT cscn;
|
|
PSCAN pscn;
|
|
DWORD nrcl;
|
|
PRECTL prcl;
|
|
UINT cRgnData;
|
|
PRGNDATA pRgnData;
|
|
|
|
cscn = (UINT) pW3Rgn->cScans;
|
|
|
|
// Handle the empty region.
|
|
|
|
if (!cscn)
|
|
{
|
|
hrgn = CreateRectRgn(0, 0, 0, 0);
|
|
fStatus = AddToHandleTable(lpHandleTable, hrgn, noObjs);
|
|
break;
|
|
}
|
|
|
|
// Count the number of rectangles in the region.
|
|
|
|
nrcl = 0;
|
|
pscn = pW3Rgn->aScans;
|
|
for (ii = 0; ii < cscn; ii++)
|
|
{
|
|
nrcl += pscn->scnPntCnt / 2;
|
|
pscn = (PSCAN) ((PBYTE) pscn
|
|
+ sizeof(SCAN)
|
|
- 2 * sizeof(WORD)
|
|
+ (int) (UINT) pscn->scnPntCnt * sizeof(WORD));
|
|
}
|
|
|
|
cRgnData = sizeof(RGNDATAHEADER) + nrcl * sizeof(RECTL);
|
|
if (!(pRgnData = (PRGNDATA) LocalAlloc(LMEM_FIXED, cRgnData)))
|
|
break;
|
|
|
|
pRgnData->rdh.dwSize = sizeof(RGNDATAHEADER);
|
|
pRgnData->rdh.iType = RDH_RECTANGLES;
|
|
pRgnData->rdh.nCount = nrcl;
|
|
pRgnData->rdh.nRgnSize = 0;
|
|
pRgnData->rdh.rcBound.left = (LONG) pW3Rgn->rcBounding.left ;
|
|
pRgnData->rdh.rcBound.top = (LONG) pW3Rgn->rcBounding.top ;
|
|
pRgnData->rdh.rcBound.right = (LONG) pW3Rgn->rcBounding.right ;
|
|
pRgnData->rdh.rcBound.bottom = (LONG) pW3Rgn->rcBounding.bottom ;
|
|
|
|
prcl = (PRECTL) pRgnData->Buffer;
|
|
pscn = pW3Rgn->aScans;
|
|
for (ii = 0; ii < cscn; ii++)
|
|
{
|
|
pXs = (PSHORT) pscn->scnPntsX;
|
|
for (jj = pscn->scnPntCnt / 2; jj; jj--)
|
|
{
|
|
prcl->left = (LONG) (*pXs++);
|
|
prcl->top = (LONG) (SHORT) pscn->scnPntTop;
|
|
prcl->right = (LONG) (*pXs++);
|
|
prcl->bottom = (LONG) (SHORT) pscn->scnPntBottom;
|
|
prcl++;
|
|
}
|
|
pscn = (PSCAN) ((PBYTE) pscn
|
|
+ sizeof(SCAN)
|
|
- 2 * sizeof(WORD)
|
|
+ (int) (UINT) pscn->scnPntCnt * sizeof(WORD));
|
|
}
|
|
|
|
hrgn = ExtCreateRegion((LPXFORM) NULL, cRgnData, pRgnData);
|
|
fStatus = AddToHandleTable(lpHandleTable, hrgn, noObjs);
|
|
|
|
if (LocalFree((HANDLE) pRgnData))
|
|
ASSERTGDI(FALSE, "PlayMetaRecord: LocalFree failed\n");
|
|
}
|
|
break;
|
|
|
|
case (META_DELETEOBJECT & 255):
|
|
{
|
|
HANDLE h;
|
|
|
|
if (h = lpHandleTable->objectHandle[lpMR->rdParm[0]])
|
|
{
|
|
if (!(fStatus = DeleteObject(h)))
|
|
ERROR_ASSERT(FALSE, "PlayMetaFileRecord: DeleteObject(h) Failed\n");
|
|
lpHandleTable->objectHandle[lpMR->rdParm[0]] = NULL;
|
|
}
|
|
}
|
|
break;
|
|
|
|
case (META_CREATEPALETTE & 255):
|
|
{
|
|
LPMETARECORD lpMRtmp;
|
|
|
|
// Make the logical palette dword aligned. To do this,
|
|
// lpMR has to fall on a non dword aligned even address so that
|
|
// the logical palette (&lpMR->rdParm[0]) will fall on the
|
|
// dword aligned address.
|
|
|
|
if (!(lpMRdup = (LPMETARECORD) LocalAlloc(LMEM_FIXED,
|
|
(UINT) lpMR->rdSize * sizeof(WORD) + sizeof(WORD))))
|
|
break;
|
|
lpMRtmp = (LPMETARECORD) &((PWORD) lpMRdup)[1];
|
|
RtlCopyMemory((PBYTE) lpMRtmp,
|
|
(PBYTE) lpMR,
|
|
(UINT) lpMR->rdSize * sizeof(WORD));
|
|
|
|
if (hObject = CreatePalette((LPLOGPALETTE)&lpMRtmp->rdParm[0]))
|
|
fStatus = AddToHandleTable(lpHandleTable, hObject, noObjs);
|
|
}
|
|
break;
|
|
|
|
case (META_SELECTPALETTE & 255):
|
|
if (hPal = lpHandleTable->objectHandle[lpMR->rdParm[0]])
|
|
fStatus = SelectPalette(hdc, hPal, 0) != 0;
|
|
break;
|
|
|
|
case (META_REALIZEPALETTE & 255):
|
|
fStatus = RealizePalette(hdc) != -1;
|
|
break;
|
|
|
|
case (META_SETPALENTRIES & 255):
|
|
case (META_ANIMATEPALETTE & 255):
|
|
{
|
|
LPMETARECORD lpMRtmp;
|
|
|
|
// Make the palette entry array dword aligned. To do this,
|
|
// lpMR has to fall on a non dword aligned even address so that
|
|
// the palette entry array (&lpMR->rdParm[2]) will fall on the
|
|
// dword aligned address.
|
|
|
|
if (!(lpMRdup = (LPMETARECORD) LocalAlloc(LMEM_FIXED,
|
|
(UINT) lpMR->rdSize * sizeof(WORD) + sizeof(WORD))))
|
|
break;
|
|
lpMRtmp = (LPMETARECORD) &((PWORD) lpMRdup)[1];
|
|
RtlCopyMemory((PBYTE) lpMRtmp,
|
|
(PBYTE) lpMR,
|
|
(UINT) lpMR->rdSize * sizeof(WORD));
|
|
|
|
// we know the palette being set is the current palette
|
|
if (magic == META_SETPALENTRIES)
|
|
fStatus = SetPaletteEntries(GetCurrentObject(hdc,OBJ_PAL),
|
|
(UINT) lpMRtmp->rdParm[0],
|
|
(UINT) lpMRtmp->rdParm[1],
|
|
(LPPALETTEENTRY)&lpMRtmp->rdParm[2]
|
|
) != 0;
|
|
else
|
|
fStatus = AnimatePalette(GetCurrentObject(hdc,OBJ_PAL),
|
|
(UINT) lpMR->rdParm[0],
|
|
(UINT) lpMR->rdParm[1],
|
|
(LPPALETTEENTRY)&lpMR->rdParm[2]);
|
|
}
|
|
break;
|
|
|
|
case (META_RESIZEPALETTE & 255):
|
|
fStatus = ResizePalette(GetCurrentObject(hdc,OBJ_PAL),
|
|
(UINT) lpMR->rdParm[0]);
|
|
break;
|
|
|
|
case (META_SETDIBTODEV & 255):
|
|
{
|
|
LPBITMAPINFOHEADER lpBitmapInfo;
|
|
DWORD ColorSize;
|
|
LPMETARECORD lpMRtmp;
|
|
|
|
/* if playing into another metafile, do direct copy */
|
|
if (PlayIntoAMetafile(lpMR, hdc))
|
|
{
|
|
fStatus = TRUE;
|
|
break;
|
|
}
|
|
|
|
// Make the bitmap info and bits dword aligned. To do this,
|
|
// lpMR has to fall on a dword aligned address so that
|
|
// the bitmap info (&lpMR->rdParm[9]) and
|
|
// the bitmap bits will fall on the dword aligned addresses.
|
|
// Note that the size of the bitmap info is always a multiple
|
|
// of 4.
|
|
|
|
if (!(lpMRdup = (LPMETARECORD) LocalAlloc(LMEM_FIXED,
|
|
(UINT) lpMR->rdSize * sizeof(WORD))))
|
|
break;
|
|
lpMRtmp = lpMRdup;
|
|
RtlCopyMemory((PBYTE) lpMRtmp,
|
|
(PBYTE) lpMR,
|
|
(UINT) lpMR->rdSize * sizeof(WORD));
|
|
|
|
lpBitmapInfo = (LPBITMAPINFOHEADER)&(lpMRtmp->rdParm[9]);
|
|
|
|
if (lpBitmapInfo->biBitCount == 16 || lpBitmapInfo->biBitCount == 32)
|
|
ColorSize = 3 * sizeof(DWORD);
|
|
else if (lpBitmapInfo->biClrUsed)
|
|
ColorSize = lpBitmapInfo->biClrUsed *
|
|
(DWORD)(lpMRtmp->rdParm[0] == DIB_RGB_COLORS ?
|
|
sizeof(RGBQUAD) :
|
|
sizeof(WORD));
|
|
else if (lpBitmapInfo->biBitCount == 24)
|
|
ColorSize = 0;
|
|
else
|
|
ColorSize = (DWORD)(1 << lpBitmapInfo->biBitCount) *
|
|
(DWORD)(lpMRtmp->rdParm[0] == DIB_RGB_COLORS ?
|
|
sizeof(RGBQUAD) :
|
|
sizeof(WORD));
|
|
ColorSize = (ColorSize + 3) / 4 * 4; // make sure it is aligned
|
|
|
|
ColorSize += lpBitmapInfo->biSize;
|
|
|
|
fStatus = SetDIBitsToDevice(hdc,
|
|
(int) (SHORT) lpMRtmp->rdParm[8],
|
|
(int) (SHORT) lpMRtmp->rdParm[7],
|
|
(DWORD) (int) (SHORT)lpMRtmp->rdParm[6],
|
|
(DWORD) (int) (SHORT)lpMRtmp->rdParm[5],
|
|
(int) (SHORT) lpMRtmp->rdParm[4],
|
|
(int) (SHORT) lpMRtmp->rdParm[3],
|
|
(UINT) lpMRtmp->rdParm[2],
|
|
(UINT) lpMRtmp->rdParm[1],
|
|
(PBYTE)(((PBYTE)lpBitmapInfo) + ColorSize),
|
|
(LPBITMAPINFO) lpBitmapInfo,
|
|
(DWORD) lpMRtmp->rdParm[0]
|
|
) != 0;
|
|
}
|
|
break;
|
|
|
|
case (META_STRETCHDIB & 255):
|
|
{
|
|
LPBITMAPINFOHEADER lpBitmapInfo;
|
|
DWORD ColorSize;
|
|
LPMETARECORD lpMRtmp;
|
|
|
|
/* if playing into another metafile, do direct copy */
|
|
if (PlayIntoAMetafile(lpMR, hdc))
|
|
{
|
|
fStatus = TRUE;
|
|
break;
|
|
}
|
|
|
|
// Make the bitmap info and bits dword aligned. To do this,
|
|
// lpMR has to fall on a dword aligned address so that
|
|
// the bitmap info (&lpMR->rdParm[11]) and
|
|
// the bitmap bits will fall on the dword aligned addresses.
|
|
// Note that the size of the bitmap info is always a multiple
|
|
// of 4.
|
|
|
|
if (!(lpMRdup = (LPMETARECORD) LocalAlloc(LMEM_FIXED,
|
|
(UINT) lpMR->rdSize * sizeof(WORD))))
|
|
break;
|
|
lpMRtmp = lpMRdup;
|
|
RtlCopyMemory((PBYTE) lpMRtmp,
|
|
(PBYTE) lpMR,
|
|
(UINT) lpMR->rdSize * sizeof(WORD));
|
|
|
|
//
|
|
// rdsize is SIZEOF_METARECORDHEADER/sizeof(WORD) + cw;
|
|
// where cw is from MF16_RecordDIBits (11)
|
|
//
|
|
if (lpMR->rdSize > SIZEOF_METARECORDHEADER/sizeof(WORD) + 11)
|
|
{
|
|
lpBitmapInfo = (LPBITMAPINFOHEADER)&(lpMRtmp->rdParm[11]);
|
|
|
|
if (lpBitmapInfo->biBitCount == 16 || lpBitmapInfo->biBitCount == 32)
|
|
ColorSize = 3 * sizeof(DWORD);
|
|
else if (lpBitmapInfo->biClrUsed)
|
|
ColorSize = lpBitmapInfo->biClrUsed *
|
|
(DWORD)(lpMRtmp->rdParm[2] == DIB_RGB_COLORS ?
|
|
sizeof(RGBQUAD) :
|
|
sizeof(WORD));
|
|
else if (lpBitmapInfo->biBitCount == 24)
|
|
ColorSize = 0;
|
|
else
|
|
ColorSize = (DWORD)(1 << lpBitmapInfo->biBitCount) *
|
|
(DWORD)(lpMRtmp->rdParm[2] == DIB_RGB_COLORS ?
|
|
sizeof(RGBQUAD) :
|
|
sizeof(WORD));
|
|
ColorSize = (ColorSize + 3) / 4 * 4; // make sure it is aligned
|
|
|
|
ColorSize += lpBitmapInfo->biSize;
|
|
|
|
}
|
|
else
|
|
{
|
|
lpBitmapInfo = NULL;
|
|
}
|
|
|
|
fStatus = StretchDIBits(hdc,
|
|
(int) (SHORT) lpMRtmp->rdParm[10],
|
|
(int) (SHORT) lpMRtmp->rdParm[9],
|
|
(int) (SHORT) lpMRtmp->rdParm[8],
|
|
(int) (SHORT) lpMRtmp->rdParm[7],
|
|
(int) (SHORT) lpMRtmp->rdParm[6],
|
|
(int) (SHORT) lpMRtmp->rdParm[5],
|
|
(int) (SHORT) lpMRtmp->rdParm[4],
|
|
(int) (SHORT) lpMRtmp->rdParm[3],
|
|
lpBitmapInfo ? (LPBYTE)(((PBYTE)lpBitmapInfo) + ColorSize) : NULL,
|
|
(LPBITMAPINFO) lpBitmapInfo,
|
|
(DWORD) lpMRtmp->rdParm[2],
|
|
MAKELONG(lpMRtmp->rdParm[0], lpMRtmp->rdParm[1])
|
|
) != ERROR;
|
|
}
|
|
break;
|
|
|
|
// Function that have new parameters on WIN32
|
|
// Or have DWORDs that stayed DWORDs; all other INTs to DWORDs
|
|
|
|
case (META_PATBLT & 255):
|
|
fStatus = PatBlt(hdc,
|
|
(int) (SHORT) lpMR->rdParm[5],
|
|
(int) (SHORT) lpMR->rdParm[4],
|
|
(int) (SHORT) lpMR->rdParm[3],
|
|
(int) (SHORT) lpMR->rdParm[2],
|
|
MAKELONG(lpMR->rdParm[0], lpMR->rdParm[1]));
|
|
break;
|
|
|
|
case (META_MOVETO & 255):
|
|
fStatus = MoveToEx(hdc, (int)(SHORT)lpMR->rdParm[1], (int)(SHORT)lpMR->rdParm[0], NULL);
|
|
break;
|
|
|
|
case (META_RESTOREDC & 255):
|
|
fStatus = RestoreDC(hdc, (int)(SHORT)lpMR->rdParm[0]);
|
|
break;
|
|
|
|
case (META_SETBKCOLOR & 255):
|
|
fStatus = SetBkColor(hdc, *(COLORREF UNALIGNED *)lpMR->rdParm) != CLR_INVALID;
|
|
break;
|
|
|
|
case (META_SETTEXTCOLOR & 255):
|
|
fStatus = SetTextColor(hdc, *(COLORREF UNALIGNED *)lpMR->rdParm) != CLR_INVALID;
|
|
break;
|
|
|
|
case (META_SETPIXEL & 255):
|
|
fStatus = SetPixel(hdc,
|
|
(int) (SHORT) lpMR->rdParm[3],
|
|
(int) (SHORT) lpMR->rdParm[2],
|
|
*(COLORREF UNALIGNED *) lpMR->rdParm
|
|
) != CLR_INVALID;
|
|
break;
|
|
|
|
case (META_SETMAPPERFLAGS & 255):
|
|
fStatus = SetMapperFlags(hdc, *(DWORD UNALIGNED *)lpMR->rdParm) != GDI_ERROR;
|
|
break;
|
|
|
|
case (META_FLOODFILL & 255):
|
|
fStatus = FloodFill(hdc,
|
|
(int) (SHORT) lpMR->rdParm[3],
|
|
(int) (SHORT) lpMR->rdParm[2],
|
|
*(COLORREF UNALIGNED *) lpMR->rdParm);
|
|
break;
|
|
|
|
case (META_EXTFLOODFILL & 255):
|
|
fStatus = ExtFloodFill(hdc,
|
|
(int) (SHORT) lpMR->rdParm[4],
|
|
(int) (SHORT) lpMR->rdParm[3],
|
|
*(COLORREF UNALIGNED *) &lpMR->rdParm[1],
|
|
(UINT) lpMR->rdParm[0]);
|
|
break;
|
|
|
|
case (META_SCALEWINDOWEXT & 255):
|
|
fStatus = ScaleWindowExtEx(hdc,
|
|
(int)(SHORT)lpMR->rdParm[3],
|
|
(int)(SHORT)lpMR->rdParm[2],
|
|
(int)(SHORT)lpMR->rdParm[1],
|
|
(int)(SHORT)lpMR->rdParm[0],
|
|
NULL);
|
|
break;
|
|
|
|
case (META_SCALEVIEWPORTEXT & 255):
|
|
fStatus = ScaleViewportExtEx(hdc,
|
|
(int)(SHORT)lpMR->rdParm[3],
|
|
(int)(SHORT)lpMR->rdParm[2],
|
|
(int)(SHORT)lpMR->rdParm[1],
|
|
(int)(SHORT)lpMR->rdParm[0],
|
|
NULL);
|
|
break;
|
|
|
|
case (META_SETWINDOWORG & 255):
|
|
fStatus = SetWindowOrgEx(hdc,
|
|
(int)(SHORT)lpMR->rdParm[1],
|
|
(int)(SHORT)lpMR->rdParm[0],
|
|
(LPPOINT) NULL);
|
|
break;
|
|
|
|
case (META_SETWINDOWEXT & 255):
|
|
fStatus = SetWindowExtEx(hdc,
|
|
(int)(SHORT)lpMR->rdParm[1],
|
|
(int)(SHORT)lpMR->rdParm[0],
|
|
(LPSIZE) NULL);
|
|
break;
|
|
|
|
case (META_SETVIEWPORTORG & 255):
|
|
fStatus = SetViewportOrgEx(hdc,
|
|
(int)(SHORT)lpMR->rdParm[1],
|
|
(int)(SHORT)lpMR->rdParm[0],
|
|
(LPPOINT) NULL);
|
|
break;
|
|
|
|
case (META_SETVIEWPORTEXT & 255):
|
|
fStatus = SetViewportExtEx(hdc,
|
|
(int)(SHORT)lpMR->rdParm[1],
|
|
(int)(SHORT)lpMR->rdParm[0],
|
|
(LPSIZE) NULL);
|
|
break;
|
|
|
|
case (META_OFFSETWINDOWORG & 255):
|
|
fStatus = OffsetWindowOrgEx(hdc,
|
|
(int)(SHORT)lpMR->rdParm[1],
|
|
(int)(SHORT)lpMR->rdParm[0],
|
|
(LPPOINT) NULL);
|
|
break;
|
|
|
|
case (META_OFFSETVIEWPORTORG & 255):
|
|
fStatus = OffsetViewportOrgEx(hdc,
|
|
(int)(SHORT)lpMR->rdParm[1],
|
|
(int)(SHORT)lpMR->rdParm[0],
|
|
(LPPOINT) NULL);
|
|
break;
|
|
|
|
case (META_SETTEXTCHAREXTRA & 255):
|
|
fStatus = SetTextCharacterExtra(hdc, (int)(SHORT)lpMR->rdParm[0]) != 0x80000000;
|
|
break;
|
|
|
|
case (META_SETTEXTALIGN & 255):
|
|
fStatus = SetTextAlign(hdc, (UINT)lpMR->rdParm[0]) != GDI_ERROR;
|
|
break;
|
|
|
|
case (META_SAVEDC & 255):
|
|
fStatus = (SaveDC(hdc) != 0);
|
|
break;
|
|
|
|
case (META_SELECTCLIPREGION & 255):
|
|
// Win3.1 has never got this right except when the handle is 0.
|
|
hObject = (lpMR->rdParm[0] == 0)
|
|
? 0
|
|
: lpHandleTable->objectHandle[lpMR->rdParm[0]];
|
|
fStatus = (SelectClipRgn(hdc, hObject) != RGN_ERROR);
|
|
break;
|
|
|
|
case (META_SETBKMODE & 255):
|
|
fStatus = (SetBkMode(hdc, (int)(SHORT)lpMR->rdParm[0]) != 0);
|
|
break;
|
|
|
|
case (META_SETMAPMODE & 255):
|
|
fStatus = (SetMapMode(hdc, (int)(SHORT)lpMR->rdParm[0]) != 0);
|
|
break;
|
|
|
|
case (META_SETLAYOUT & 255):
|
|
fStatus = (SetLayout(hdc, (DWORD)lpMR->rdParm[0]) != GDI_ERROR);
|
|
break;
|
|
|
|
case (META_SETPOLYFILLMODE & 255):
|
|
fStatus = (SetPolyFillMode(hdc, (int)(SHORT)lpMR->rdParm[0]) != 0);
|
|
break;
|
|
|
|
case (META_SETROP2 & 255):
|
|
fStatus = (SetROP2(hdc, (int)(SHORT)lpMR->rdParm[0]) != 0);
|
|
break;
|
|
|
|
case (META_SETSTRETCHBLTMODE & 255):
|
|
fStatus = (SetStretchBltMode(hdc, (int)(SHORT)lpMR->rdParm[0]) != 0);
|
|
break;
|
|
|
|
case (META_LINETO & 255):
|
|
fStatus = LineTo(hdc,
|
|
(int)(SHORT)lpMR->rdParm[1],
|
|
(int)(SHORT)lpMR->rdParm[0]);
|
|
break;
|
|
|
|
case (META_OFFSETCLIPRGN & 255):
|
|
fStatus = OffsetClipRgn(hdc,
|
|
(int)(SHORT)lpMR->rdParm[1],
|
|
(int)(SHORT)lpMR->rdParm[0]
|
|
) != RGN_ERROR;
|
|
break;
|
|
|
|
case (META_SETTEXTJUSTIFICATION & 255):
|
|
fStatus = SetTextJustification(hdc,
|
|
(int)(SHORT)lpMR->rdParm[1],
|
|
(int)(SHORT)lpMR->rdParm[0]);
|
|
break;
|
|
|
|
case (META_ELLIPSE & 255):
|
|
fStatus = Ellipse(hdc,
|
|
(int)(SHORT)lpMR->rdParm[3],
|
|
(int)(SHORT)lpMR->rdParm[2],
|
|
(int)(SHORT)lpMR->rdParm[1],
|
|
(int)(SHORT)lpMR->rdParm[0]);
|
|
break;
|
|
|
|
case (META_RECTANGLE & 255):
|
|
fStatus = Rectangle(hdc,
|
|
(int)(SHORT)lpMR->rdParm[3],
|
|
(int)(SHORT)lpMR->rdParm[2],
|
|
(int)(SHORT)lpMR->rdParm[1],
|
|
(int)(SHORT)lpMR->rdParm[0]);
|
|
break;
|
|
|
|
case (META_EXCLUDECLIPRECT & 255):
|
|
fStatus = ExcludeClipRect(hdc,
|
|
(int)(SHORT)lpMR->rdParm[3],
|
|
(int)(SHORT)lpMR->rdParm[2],
|
|
(int)(SHORT)lpMR->rdParm[1],
|
|
(int)(SHORT)lpMR->rdParm[0]
|
|
) != RGN_ERROR;
|
|
break;
|
|
|
|
case (META_INTERSECTCLIPRECT & 255):
|
|
fStatus = IntersectClipRect(hdc,
|
|
(int)(SHORT)lpMR->rdParm[3],
|
|
(int)(SHORT)lpMR->rdParm[2],
|
|
(int)(SHORT)lpMR->rdParm[1],
|
|
(int)(SHORT)lpMR->rdParm[0]
|
|
) != RGN_ERROR;
|
|
break;
|
|
|
|
case (META_ROUNDRECT & 255):
|
|
fStatus = RoundRect(hdc,
|
|
(int)(SHORT)lpMR->rdParm[5],
|
|
(int)(SHORT)lpMR->rdParm[4],
|
|
(int)(SHORT)lpMR->rdParm[3],
|
|
(int)(SHORT)lpMR->rdParm[2],
|
|
(int)(SHORT)lpMR->rdParm[1],
|
|
(int)(SHORT)lpMR->rdParm[0]
|
|
);
|
|
break;
|
|
|
|
case (META_ARC & 255):
|
|
fStatus = Arc(hdc,
|
|
(int)(SHORT)lpMR->rdParm[7],
|
|
(int)(SHORT)lpMR->rdParm[6],
|
|
(int)(SHORT)lpMR->rdParm[5],
|
|
(int)(SHORT)lpMR->rdParm[4],
|
|
(int)(SHORT)lpMR->rdParm[3],
|
|
(int)(SHORT)lpMR->rdParm[2],
|
|
(int)(SHORT)lpMR->rdParm[1],
|
|
(int)(SHORT)lpMR->rdParm[0]
|
|
);
|
|
break;
|
|
|
|
case (META_CHORD & 255):
|
|
fStatus = Chord(hdc,
|
|
(int)(SHORT)lpMR->rdParm[7],
|
|
(int)(SHORT)lpMR->rdParm[6],
|
|
(int)(SHORT)lpMR->rdParm[5],
|
|
(int)(SHORT)lpMR->rdParm[4],
|
|
(int)(SHORT)lpMR->rdParm[3],
|
|
(int)(SHORT)lpMR->rdParm[2],
|
|
(int)(SHORT)lpMR->rdParm[1],
|
|
(int)(SHORT)lpMR->rdParm[0]
|
|
);
|
|
break;
|
|
|
|
case (META_PIE & 255):
|
|
fStatus = Pie(hdc,
|
|
(int)(SHORT)lpMR->rdParm[7],
|
|
(int)(SHORT)lpMR->rdParm[6],
|
|
(int)(SHORT)lpMR->rdParm[5],
|
|
(int)(SHORT)lpMR->rdParm[4],
|
|
(int)(SHORT)lpMR->rdParm[3],
|
|
(int)(SHORT)lpMR->rdParm[2],
|
|
(int)(SHORT)lpMR->rdParm[1],
|
|
(int)(SHORT)lpMR->rdParm[0]
|
|
);
|
|
break;
|
|
|
|
case (META_SETRELABS & 255):
|
|
ERROR_ASSERT(FALSE, "PlayMetaFileRecord: unsupported META_SETRELABS record\n");
|
|
fStatus = TRUE;
|
|
break;
|
|
|
|
#if 0
|
|
case (META_CREATEBITMAP & 255):
|
|
case (META_CREATEBITMAPINDIRECT & 255):
|
|
case (META_CREATEBRUSH & 255):
|
|
case (META_ABORTDOC & 255):
|
|
case (META_ENDPAGE & 255):
|
|
case (META_ENDDOC & 255):
|
|
case (META_RESETDC & 255):
|
|
case (META_STARTDOC & 255):
|
|
case (META_STARTPAGE & 255):
|
|
// not created or playbacked on Win3.1!
|
|
ASSERTGDI(FALSE, "PlayMetaFileRecord: unsupported record\n");
|
|
fStatus = TRUE;
|
|
break;
|
|
#endif // 0
|
|
|
|
case 0: // End of metafile record
|
|
fStatus = TRUE;
|
|
break;
|
|
|
|
default:
|
|
VERIFYGDI(FALSE, "PlayMetaFileRecord: unknown record\n");
|
|
#if DBG
|
|
DbgPrint("Record %lx pMFRecord %p magic %X\n", curRecord, lpMR, magic);
|
|
#endif
|
|
fStatus = TRUE;
|
|
break;
|
|
|
|
} // switch (magic & 255)
|
|
|
|
if (lpMRdup)
|
|
if (LocalFree((HANDLE) lpMRdup))
|
|
ASSERTGDI(FALSE, "LocalFree failed");
|
|
|
|
#if DBG
|
|
if (!fStatus)
|
|
{
|
|
DbgPrint("PlayMetaFileRecord Record %lx pMFRecord %p magic %X\n", curRecord, lpMR, magic);
|
|
ERROR_ASSERT(FALSE, "PlayMetaFileRecord Failing\n");
|
|
}
|
|
#endif
|
|
|
|
return(fStatus);
|
|
}
|
|
|
|
/****************************** Internal Function **************************\
|
|
* AddToHandleTable
|
|
*
|
|
* Adds an object to the metafile table of objects
|
|
*
|
|
*
|
|
\***************************************************************************/
|
|
|
|
BOOL AddToHandleTable(LPHANDLETABLE lpHandleTable, HANDLE hObject, UINT noObjs)
|
|
{
|
|
UINT ii;
|
|
|
|
PUTS("AddToHandleTable\n");
|
|
|
|
if (lpHandleTable == (LPHANDLETABLE) NULL)
|
|
{
|
|
ASSERTGDI(FALSE, "AddToHandleTable: lpHT is NULL\n");
|
|
return(FALSE);
|
|
}
|
|
|
|
/* linear search through table for first open slot */
|
|
for (ii = 0; ((lpHandleTable->objectHandle[ii] != NULL) && (ii < noObjs));
|
|
++ii);
|
|
|
|
if (ii < noObjs) /* ok index */
|
|
{
|
|
lpHandleTable->objectHandle[ii] = hObject;
|
|
return (TRUE);
|
|
}
|
|
else
|
|
{
|
|
ASSERTGDI(FALSE, "AddToHandleTable: Too many objects in table\n");
|
|
return(FALSE);
|
|
}
|
|
}
|
|
|
|
BOOL IsValidMetaHeader16(PMETAHEADER pMetaHeader)
|
|
{
|
|
BOOL status;
|
|
|
|
PUTS("IsValidMetaHeader16\n");
|
|
|
|
status = (
|
|
(pMetaHeader->mtType == MEMORYMETAFILE ||
|
|
pMetaHeader->mtType == DISKMETAFILE) &&
|
|
(pMetaHeader->mtHeaderSize == (sizeof(METAHEADER)/sizeof(WORD))) &&
|
|
((pMetaHeader->mtVersion == METAVERSION300) ||
|
|
(pMetaHeader->mtVersion ==METAVERSION100))
|
|
);
|
|
|
|
ERROR_ASSERT(status, "IsValidMetaHeader16 is failing\n");
|
|
|
|
return status;
|
|
}
|
|
|
|
/****************************** Internal Function **************************\
|
|
* CreateBitmapForDC (HDC hMemDC, LPBITMAPINFOHEADER lpDIBInfo)
|
|
*
|
|
* This routine takes a memory device context and a DIB bitmap, creates a
|
|
* compatible bitmap for the DC and fills it with the bits from the DIB
|
|
* converting to the device dependent format). The pointer to the DIB bits
|
|
* start immediately after the color table in the INFO header.
|
|
*
|
|
* The routine returns the handle to the bitmap with the bits filled in if
|
|
* everything goes well else it returns NULL.
|
|
\***************************************************************************/
|
|
|
|
HANDLE CreateBitmapForDC (HDC hMemDC, LPBITMAPINFOHEADER lpDIBInfo)
|
|
{
|
|
HBITMAP hBitmap ;
|
|
LPBYTE lpDIBits ;
|
|
|
|
PUTS("CreateBitmapForDC\n");
|
|
|
|
ASSERTGDI(!((ULONG_PTR) lpDIBInfo & 0x3), "CreateBitmapForDC: dword alignment error\n");
|
|
|
|
/* preserve monochrome if it started out as monochrome
|
|
** and check for REAL Black&white monochrome as opposed
|
|
** to a 2-color DIB
|
|
*/
|
|
if (IsDIBBlackAndWhite(lpDIBInfo))
|
|
hBitmap = CreateBitmap ((WORD)lpDIBInfo->biWidth,
|
|
(WORD)lpDIBInfo->biHeight,
|
|
1, 1, (LPBYTE) NULL);
|
|
else
|
|
/* otherwise, make a compatible bitmap */
|
|
hBitmap = CreateCompatibleBitmap (hMemDC,
|
|
(WORD)lpDIBInfo->biWidth,
|
|
(WORD)lpDIBInfo->biHeight);
|
|
|
|
if (!hBitmap)
|
|
goto CreateBitmapForDCErr ;
|
|
|
|
/* take a pointer past the header of the DIB, to the start of the color
|
|
table */
|
|
lpDIBits = (LPBYTE) lpDIBInfo + lpDIBInfo->biSize;
|
|
|
|
/* take the pointer past the color table */
|
|
lpDIBits += GetSizeOfColorTable (lpDIBInfo) ;
|
|
|
|
/* get the bits from the DIB into the Bitmap */
|
|
if (!SetDIBits (hMemDC, hBitmap, 0, (WORD)lpDIBInfo->biHeight,
|
|
lpDIBits, (LPBITMAPINFO)lpDIBInfo, DIB_RGB_COLORS))
|
|
{
|
|
if (!DeleteObject(hBitmap))
|
|
ASSERTGDI(FALSE, "CreateBitmapForDC: DeleteObject(hBitmap) Failed\n");
|
|
goto CreateBitmapForDCErr ;
|
|
}
|
|
|
|
/* return success */
|
|
return (hBitmap) ;
|
|
|
|
CreateBitmapForDCErr:
|
|
|
|
/* returm failure for function */
|
|
return (NULL);
|
|
}
|
|
|
|
|
|
/****************************** Internal Function **************************\
|
|
* GetSizeOfColorTable (LPBITMAPINFOHEADER lpDIBInfo)
|
|
*
|
|
* Returns the number of bytes in the color table for the giving info header
|
|
*
|
|
\***************************************************************************/
|
|
|
|
WORD GetSizeOfColorTable (LPBITMAPINFOHEADER lpDIBInfo)
|
|
{
|
|
PUTS("GetSizeOfColorTable\n");
|
|
|
|
ASSERTGDI(!((ULONG_PTR) lpDIBInfo & 0x3), "GetSizeOfColorTable: dword alignment error\n");
|
|
|
|
if (lpDIBInfo->biBitCount == 16 || lpDIBInfo->biBitCount == 32)
|
|
return(3 * sizeof(DWORD));
|
|
|
|
if (lpDIBInfo->biClrUsed)
|
|
return((WORD)lpDIBInfo->biClrUsed * (WORD)sizeof(RGBQUAD));
|
|
|
|
if (lpDIBInfo->biBitCount < 16)
|
|
return((1 << lpDIBInfo->biBitCount) * sizeof(RGBQUAD));
|
|
else
|
|
return(0);
|
|
}
|
|
|
|
/***************************** Public Function ****************************\
|
|
* BOOL APIENTRY DeleteMetaFile(hmf)
|
|
*
|
|
* Frees a metafile handle.
|
|
*
|
|
* Effects:
|
|
*
|
|
\***************************************************************************/
|
|
|
|
BOOL APIENTRY DeleteMetaFile(HMETAFILE hmf)
|
|
{
|
|
PMETAFILE16 pmf16;
|
|
|
|
PUTS("DeleteMetaFile\n");
|
|
|
|
pmf16 = GET_PMF16(hmf);
|
|
if (pmf16 == NULL)
|
|
{
|
|
GdiSetLastError(ERROR_INVALID_HANDLE);
|
|
return(FALSE);
|
|
}
|
|
|
|
// Free the metafile and its handle.
|
|
|
|
vFreeMF16(pmf16);
|
|
bDeleteHmf16(hmf);
|
|
return(TRUE);
|
|
}
|
|
|
|
/***************************** Public Function ****************************\
|
|
* HMETAFILE APIENTRY GetMetaFileW(pszwFilename)
|
|
*
|
|
* Returns a metafile handle for a disk based metafile.
|
|
*
|
|
* Effects:
|
|
*
|
|
* History:
|
|
* Fri May 15 14:11:22 1992 -by- Hock San Lee [hockl]
|
|
* Wrote it.
|
|
\***************************************************************************/
|
|
|
|
HMETAFILE GetMetaFileA(LPCSTR pszFileName)
|
|
{
|
|
UINT cch;
|
|
WCHAR awch[MAX_PATH];
|
|
|
|
cch = strlen(pszFileName)+1;
|
|
|
|
if (cch > MAX_PATH)
|
|
{
|
|
ERROR_ASSERT(FALSE, "GetMetaFileA filename too long");
|
|
GdiSetLastError(ERROR_FILENAME_EXCED_RANGE);
|
|
return ((HMETAFILE)0);
|
|
}
|
|
vToUnicodeN(awch, MAX_PATH, pszFileName, cch);
|
|
|
|
return (GetMetaFileW(awch));
|
|
}
|
|
|
|
HMETAFILE APIENTRY GetMetaFileW(LPCWSTR pwszFileName)
|
|
{
|
|
PMETAFILE16 pmf16;
|
|
HMETAFILE hmf;
|
|
|
|
PUTS("GetMetaFileW\n");
|
|
|
|
// Allocate and initialize a metafile.
|
|
|
|
if (!(pmf16 = pmf16AllocMF16(0, 0, (PDWORD) NULL, (LPWSTR) pwszFileName)))
|
|
return((HMETAFILE) 0);
|
|
|
|
ASSERTGDI(pmf16->metaHeader.mtType == DISKMETAFILE,
|
|
"GetMetaFileW: Bad mtType\n");
|
|
|
|
// Allocate a local handle.
|
|
|
|
hmf = hmf16Create(pmf16);
|
|
if (!hmf)
|
|
{
|
|
vFreeMF16(pmf16);
|
|
}
|
|
|
|
// Return the metafile handle.
|
|
|
|
return(hmf);
|
|
}
|
|
|
|
/***************************** Internal Function **************************\
|
|
* BOOL FAR PASCAL PlayIntoAMetafile
|
|
*
|
|
* if this record is being played into another metafile, simply record
|
|
* it into that metafile, without hassling with a real playing.
|
|
*
|
|
* Returns: TRUE if record was played (copied) into another metafile
|
|
* FALSE if destination DC was a real (non-meta) DC
|
|
*
|
|
* Effects: ?
|
|
*
|
|
* Warnings: ?
|
|
*
|
|
\***************************************************************************/
|
|
|
|
BOOL PlayIntoAMetafile(LPMETARECORD lpMR, HDC hdcDest)
|
|
{
|
|
PUTS("PlayIntoAMetafile\n");
|
|
|
|
if (LO_TYPE(hdcDest) != LO_METADC16_TYPE)
|
|
return(FALSE);
|
|
|
|
// If a metafile is retrieved with GetWinMetaFileBits, it may contain
|
|
// an embedded enhanced metafile. Do not include the enhanced metafile
|
|
// if we are playing the metafile to another metafile.
|
|
|
|
if (IS_META_ESCAPE_ENHANCED_METAFILE((PMETA_ESCAPE_ENHANCED_METAFILE) lpMR))
|
|
return(TRUE);
|
|
|
|
// the size is the same minus 3 words for the record header
|
|
return(RecordParms(hdcDest, (DWORD)lpMR->rdFunction, (DWORD)lpMR->rdSize - 3,
|
|
(LPWORD)&(lpMR->rdParm[0])));
|
|
}
|