867 lines
27 KiB
C
867 lines
27 KiB
C
/*****************************************************************************
|
|
*
|
|
* misc - Entry points for Win32 to Win 16 converter
|
|
*
|
|
* Date: 7/1/91
|
|
* Author: Jeffrey Newman (c-jeffn)
|
|
*
|
|
* Copyright 1991 Microsoft Corp
|
|
*****************************************************************************/
|
|
|
|
#include "precomp.h"
|
|
#pragma hdrstop
|
|
|
|
extern fnGetTransform pfnGetTransform;
|
|
|
|
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;
|
|
|
|
BOOL WINAPI DoGdiCommentMultiFormats
|
|
(
|
|
PLOCALDC pLocalDC,
|
|
PEMRGDICOMMENT_MULTIFORMATS pemr
|
|
);
|
|
|
|
/***************************************************************************
|
|
* ExtFloodFill - Win32 to Win16 Metafile Converter Entry Point
|
|
**************************************************************************/
|
|
BOOL WINAPI DoExtFloodFill
|
|
(
|
|
PLOCALDC pLocalDC,
|
|
int x,
|
|
int y,
|
|
COLORREF crColor,
|
|
DWORD iMode
|
|
)
|
|
{
|
|
POINTL ptl ;
|
|
BOOL b ;
|
|
|
|
ptl.x = (LONG) x ;
|
|
ptl.y = (LONG) y ;
|
|
|
|
b = bXformRWorldToPPage(pLocalDC, &ptl, 1) ;
|
|
if (b == FALSE)
|
|
goto exit1 ;
|
|
|
|
b = bEmitWin16ExtFloodFill(pLocalDC, LOWORD(ptl.x), LOWORD(ptl.y), crColor, LOWORD(iMode)) ;
|
|
exit1:
|
|
return(b) ;
|
|
|
|
}
|
|
|
|
/***************************************************************************
|
|
* MoveToEx - Win32 to Win16 Metafile Converter Entry Point
|
|
*
|
|
* NOTE ON CURRENT POSITION
|
|
* ------------------------
|
|
* There are only three Win16 functions that use and update the
|
|
* current position (CP). They are:
|
|
*
|
|
* MoveTo
|
|
* LineTo
|
|
* (Ext)TextOut with TA_UPDATECP text alignment option
|
|
*
|
|
* In Win32, CP is used in many more functions and has two
|
|
* interpretations based on the state of the current path.
|
|
* As a result, it is easier and more robust to rely on the
|
|
* helper DC to keep track of the CP than doing it in the
|
|
* converter. To do this, we need to do the following:
|
|
*
|
|
* 1. The converter will update the CP in the helper DC in all
|
|
* records that modify the CP.
|
|
*
|
|
* 2. The converter will keep track of the CP in the converted
|
|
* metafile at all time.
|
|
*
|
|
* 3. In LineTo and (Ext)TextOut, the metafile CP is compared to
|
|
* that of the helper DC. If they are different, a MoveTo record
|
|
* is emitted. This is done in bValidateMetaFileCP().
|
|
*
|
|
* 4. The converter should emit a MoveTo record the first time the
|
|
* CP is used in the converted metafile.
|
|
*
|
|
* - HockL July 2, 1992
|
|
**************************************************************************/
|
|
BOOL WINAPI DoMoveTo
|
|
(
|
|
PLOCALDC pLocalDC,
|
|
LONG x,
|
|
LONG y
|
|
)
|
|
{
|
|
BOOL b ;
|
|
POINTL ptl ;
|
|
|
|
// Whether we are recording for a path or acutally emitting
|
|
// a drawing order we must pass the drawing order to the helper DC
|
|
// so the helper can maintain the current positon.
|
|
// If we're recording the drawing orders for a path
|
|
// then just pass the drawing order to the helper DC.
|
|
// Do not emit any Win16 drawing orders.
|
|
POINTL p = {x, y};
|
|
if (pfnSetVirtualResolution == NULL)
|
|
{
|
|
if (!bXformWorkhorse(&p, 1, &pLocalDC->xformRWorldToRDev))
|
|
{
|
|
return FALSE;
|
|
}
|
|
}
|
|
b = MoveToEx(pLocalDC->hdcHelper, (INT) p.x, (INT) p.y, (LPPOINT) &ptl) ;
|
|
if (pLocalDC->flags & RECORDING_PATH)
|
|
return(b) ;
|
|
|
|
// Update the CP in the converted metafile.
|
|
b = bValidateMetaFileCP(pLocalDC, x, y) ;
|
|
|
|
return(b) ;
|
|
}
|
|
|
|
|
|
/***************************************************************************
|
|
* bValidateMetaFiloeCP - Update the current position in the converted
|
|
* metafile.
|
|
*
|
|
* x and y are assumed to be in the record time world coordinates.
|
|
*
|
|
**************************************************************************/
|
|
BOOL bValidateMetaFileCP(PLOCALDC pLocalDC, LONG x, LONG y)
|
|
{
|
|
BOOL b ;
|
|
POINT pt ;
|
|
|
|
// Compute the new current position in the play time page coord.
|
|
|
|
pt.x = x ;
|
|
pt.y = y ;
|
|
if (!bXformRWorldToPPage(pLocalDC, (PPOINTL) &pt, 1L))
|
|
return(FALSE);
|
|
|
|
// No need to emit the record if the converted metafile has
|
|
// the same CP.
|
|
|
|
if (pLocalDC->ptCP.x == pt.x && pLocalDC->ptCP.y == pt.y)
|
|
return(TRUE);
|
|
|
|
// Call the Win16 routine to emit the move to the metafile.
|
|
|
|
b = bEmitWin16MoveTo(pLocalDC, LOWORD(pt.x), LOWORD(pt.y)) ;
|
|
|
|
// Update the mf16 current position.
|
|
|
|
pLocalDC->ptCP = pt ;
|
|
|
|
return(b) ;
|
|
}
|
|
|
|
/***************************************************************************
|
|
* SaveDC - Win32 to Win16 Metafile Converter Entry Point
|
|
**************************************************************************/
|
|
BOOL WINAPI DoSaveDC
|
|
(
|
|
PLOCALDC pLocalDC
|
|
)
|
|
{
|
|
BOOL b;
|
|
PLOCALDC pLocalDCNew;
|
|
|
|
b = FALSE;
|
|
|
|
// Save the helper DC's state first
|
|
|
|
if (!SaveDC(pLocalDC->hdcHelper))
|
|
{
|
|
RIPS("MF3216: DoSaveDC, SaveDC failed\n");
|
|
return(b);
|
|
}
|
|
|
|
// Allocate some memory for the LocalDC.
|
|
|
|
pLocalDCNew = (PLOCALDC) LocalAlloc(LMEM_FIXED, sizeof(LOCALDC));
|
|
if (pLocalDCNew == (PLOCALDC) NULL)
|
|
{
|
|
RIPS("MF3216: DoSaveDC, LocalAlloc failed\n");
|
|
return(b);
|
|
}
|
|
|
|
// Copy the data from the current LocalDC to the new one just allocated.
|
|
|
|
*pLocalDCNew = *pLocalDC;
|
|
|
|
// Link in the new level.
|
|
|
|
pLocalDC->pLocalDCSaved = pLocalDCNew;
|
|
pLocalDC->iLevel++;
|
|
|
|
// We don't want to restore a PS clip path unless we are doing it at the
|
|
// same level
|
|
pLocalDC->iSavePSClipPath = 0;
|
|
|
|
// Emit Win16 drawing order.
|
|
|
|
b = bEmitWin16SaveDC(pLocalDC);
|
|
|
|
return(b);
|
|
}
|
|
|
|
/***************************************************************************
|
|
* RestoreDC - Win32 to Win16 Metafile Converter Entry Point
|
|
**************************************************************************/
|
|
BOOL WINAPI DoRestoreDC
|
|
(
|
|
PLOCALDC pLocalDC,
|
|
int nSavedDC
|
|
)
|
|
{
|
|
BOOL b;
|
|
INT iLevel;
|
|
PLOCALDC pLocalDCNext;
|
|
PLOCALDC pLocalDCTmp;
|
|
BOOL bRet;
|
|
WORD wEscape ;
|
|
|
|
b = FALSE;
|
|
|
|
// First check to make sure this is a relative save level.
|
|
|
|
if (nSavedDC > 0)
|
|
return(b);
|
|
|
|
// Compute an absolute level.
|
|
|
|
iLevel = pLocalDC->iLevel + nSavedDC;
|
|
|
|
// The helper DC should have caught bogus levels.
|
|
|
|
ASSERTGDI((iLevel >= 0) && ((UINT) iLevel < pLocalDC->iLevel),
|
|
"MF3216: DoRestoreDC, Bogus RestoreDC");
|
|
|
|
// Before restoring the DC level.. If we are in an XOR pass and we want to
|
|
// restore the DC level to a level that is less than the Level that we started
|
|
// the pass at, we simply treat this as the end of the pass and to the start over
|
|
if( pLocalDC->iXORPass == DRAWXORPASS && iLevel <= pLocalDC->iXORPassDCLevel )
|
|
{
|
|
|
|
pLocalDC->iXORPass = OBJECTRECREATION ;
|
|
if(!DoRemoveObjects( pLocalDC ))
|
|
return FALSE ;
|
|
|
|
bRet = DoMoveTo(pLocalDC, pLocalDC->pOldPosition.x, pLocalDC->pOldPosition.y) ;
|
|
|
|
wEscape = ENDPSIGNORE;
|
|
if(!bEmitWin16Escape(pLocalDC, POSTSCRIPT_IGNORE, sizeof(wEscape), (LPSTR)&wEscape, NULL))
|
|
return FALSE ;
|
|
|
|
wEscape = CLIP_SAVE ;
|
|
if(!bEmitWin16Escape(pLocalDC, CLIP_TO_PATH, sizeof(wEscape), (LPSTR)&wEscape, NULL))
|
|
return FALSE ;
|
|
return TRUE ;
|
|
|
|
}
|
|
else if(pLocalDC->iXORPass == ERASEXORPASS && iLevel <= pLocalDC->iXORPassDCLevel )
|
|
{
|
|
pLocalDC->iXORPass = NOTXORPASS ;
|
|
pLocalDC->pbChange = NULL ;
|
|
|
|
DoSetRop2(pLocalDC, pLocalDC->iROP);
|
|
|
|
if(!DoRestoreDC(pLocalDC, -1))
|
|
return FALSE ;
|
|
|
|
wEscape = CLIP_RESTORE ;
|
|
if(!bEmitWin16Escape(pLocalDC, CLIP_TO_PATH, sizeof(wEscape), (LPSTR)&wEscape, NULL))
|
|
return FALSE ;
|
|
|
|
if (!bEmitWin16EmitSrcCopyComment(pLocalDC, msocommentEndSrcCopy))
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
pLocalDC->iXORPassDCLevel = -1 ;
|
|
}
|
|
|
|
// We can't restore the DC if we are in an XOR pass
|
|
// Restore the helper DC's state first
|
|
// If we can restore the helper DC, we know that it is a balanced restore.
|
|
// Otherwise, we return an error.
|
|
|
|
if (!RestoreDC(pLocalDC->hdcHelper, nSavedDC))
|
|
return(b);
|
|
|
|
|
|
|
|
// Restore down to the level we want.
|
|
wEscape = CLIP_RESTORE ;
|
|
while(pLocalDC->iSavePSClipPath > 0)
|
|
{
|
|
bEmitWin16Escape(pLocalDC, CLIP_TO_PATH, sizeof(wEscape), (LPSTR)&wEscape, NULL);
|
|
// Ignore failure in this case...
|
|
pLocalDC->iSavePSClipPath--;
|
|
}
|
|
|
|
pLocalDCNext = pLocalDC->pLocalDCSaved;
|
|
while ((UINT) iLevel < pLocalDCNext->iLevel)
|
|
{
|
|
pLocalDCTmp = pLocalDCNext;
|
|
pLocalDCNext = pLocalDCNext->pLocalDCSaved;
|
|
|
|
// For each DC that has the PSClipPath set, we need to restore a PSClipPath
|
|
while(pLocalDCTmp->iSavePSClipPath > 0)
|
|
{
|
|
bEmitWin16Escape(pLocalDC, CLIP_TO_PATH, sizeof(wEscape), (LPSTR)&wEscape, NULL);
|
|
// Ignore failure in this case...
|
|
pLocalDCTmp->iSavePSClipPath--;
|
|
}
|
|
if (LocalFree(pLocalDCTmp))
|
|
ASSERTGDI(FALSE, "MF3216: DoRestoreDC, LocalFree failed");
|
|
}
|
|
|
|
// Restore the state of our local DC to that level.
|
|
|
|
// keep some of the attributes in the current DC
|
|
|
|
pLocalDCNext->ulBytesEmitted = pLocalDC->ulBytesEmitted;
|
|
pLocalDCNext->ulMaxRecord = pLocalDC->ulMaxRecord;
|
|
pLocalDCNext->nObjectHighWaterMark = pLocalDC->nObjectHighWaterMark;
|
|
pLocalDCNext->pbCurrent = pLocalDC->pbCurrent;
|
|
pLocalDCNext->pbRecord = pLocalDC->pbRecord;
|
|
pLocalDCNext->pbChange = pLocalDC->pbChange;
|
|
pLocalDCNext->cW16ObjHndlSlotStatus = pLocalDC->cW16ObjHndlSlotStatus;
|
|
pLocalDCNext->pW16ObjHndlSlotStatus = pLocalDC->pW16ObjHndlSlotStatus;
|
|
pLocalDCNext->iROP = pLocalDC->iROP;
|
|
pLocalDCNext->pOldPosition = pLocalDC->pOldPosition;
|
|
pLocalDCNext->iXORPass = pLocalDC->iXORPass;
|
|
pLocalDCNext->iXORPassDCLevel = pLocalDC->iXORPassDCLevel;
|
|
pLocalDCNext->pW16RecreationSlot = pLocalDC->pW16RecreationSlot;
|
|
|
|
// now restore the other attributes
|
|
|
|
*pLocalDC = *pLocalDCNext;
|
|
|
|
// Free the local copy of the DC.
|
|
|
|
if (LocalFree(pLocalDCNext))
|
|
ASSERTGDI(FALSE, "MF3216: DoRestoreDC, LocalFree failed");
|
|
|
|
// Emit the record to the Win16 metafile.
|
|
|
|
b = bEmitWin16RestoreDC(pLocalDC, LOWORD(nSavedDC)) ;
|
|
|
|
return (b) ;
|
|
}
|
|
|
|
/***************************************************************************
|
|
* SetRop2 - Win32 to Win16 Metafile Converter Entry Point
|
|
**************************************************************************/
|
|
BOOL WINAPI DoSetRop2
|
|
(
|
|
PLOCALDC pLocalDC,
|
|
DWORD rop
|
|
)
|
|
{
|
|
BOOL b ;
|
|
|
|
if (pLocalDC->iXORPass == DRAWXORPASS)
|
|
{
|
|
// If we are drawing during an XOR pass then the only ROP we support is
|
|
// SRCCOPY and then we set it to XOR
|
|
if (rop == R2_COPYPEN)
|
|
{
|
|
rop = R2_XORPEN;
|
|
}
|
|
else
|
|
{
|
|
pLocalDC->flags |= ERR_XORCLIPPATH;
|
|
return FALSE;
|
|
}
|
|
}
|
|
// Do it to the helper DC.
|
|
SetROP2(pLocalDC->hdcHelper, rop);
|
|
|
|
// Emit the Win16 metafile drawing order.
|
|
|
|
b = bEmitWin16SetROP2(pLocalDC, LOWORD(rop)) ;
|
|
|
|
return(b) ;
|
|
}
|
|
|
|
/***************************************************************************
|
|
* SetBkMode - Win32 to Win16 Metafile Converter Entry Point
|
|
**************************************************************************/
|
|
BOOL WINAPI DoSetBkMode
|
|
(
|
|
PLOCALDC pLocalDC,
|
|
DWORD iBkMode
|
|
)
|
|
{
|
|
BOOL b ;
|
|
|
|
// Do it to the helper DC. It needs this in a path bracket
|
|
// if a text string is drawn.
|
|
|
|
SetBkMode(pLocalDC->hdcHelper, (int) iBkMode);
|
|
|
|
// Emit the Win16 metafile drawing order.
|
|
|
|
b = bEmitWin16SetBkMode(pLocalDC, LOWORD(iBkMode)) ;
|
|
|
|
return(b) ;
|
|
}
|
|
|
|
/***************************************************************************
|
|
* SetBkColor - Win32 to Win16 Metafile Converter Entry Point
|
|
**************************************************************************/
|
|
BOOL APIENTRY DoSetBkColor
|
|
(
|
|
PLOCALDC pLocalDC,
|
|
COLORREF crColor
|
|
)
|
|
{
|
|
BOOL b ;
|
|
|
|
pLocalDC->crBkColor = crColor; // used by brushes
|
|
|
|
// Emit the Win16 metafile drawing order.
|
|
|
|
b = bEmitWin16SetBkColor(pLocalDC, crColor) ;
|
|
|
|
return(b) ;
|
|
}
|
|
|
|
/***************************************************************************
|
|
* GdiComment - Win32 to Win16 Metafile Converter Entry Point
|
|
**************************************************************************/
|
|
BOOL WINAPI DoGdiComment
|
|
(
|
|
PLOCALDC pLocalDC,
|
|
PEMR pemr
|
|
)
|
|
{
|
|
BOOL b;
|
|
PEMRGDICOMMENT_PUBLIC pemrComment = (PEMRGDICOMMENT_PUBLIC) pemr;
|
|
|
|
PEMROFFICECOMMENT pemrOffice = (PEMROFFICECOMMENT) pemr;
|
|
|
|
if (pemrOffice->emr.nSize == sizeof(EMROFFICECOMMENT)
|
|
&& pemrOffice->ident == msosignature)
|
|
{
|
|
// This is not necessarily a SrcCopy comment, but an Office Comment
|
|
return (bEmitWin16EmitSrcCopyComment(pLocalDC, LOWORD(pemrOffice->iComment)));
|
|
}
|
|
|
|
// If it's not a public comment, just return TRUE.
|
|
if (pemrComment->emr.nSize < sizeof(EMRGDICOMMENT_PUBLIC)
|
|
|| pemrComment->ident != GDICOMMENT_IDENTIFIER)
|
|
return(TRUE);
|
|
|
|
// Handle public comments.
|
|
// A public comment consists of a public comment identifier,
|
|
// a comment type, plus any accompanying data.
|
|
|
|
switch (pemrComment->iComment)
|
|
{
|
|
case GDICOMMENT_MULTIFORMATS:
|
|
b = DoGdiCommentMultiFormats(pLocalDC, (PEMRGDICOMMENT_MULTIFORMATS) pemr);
|
|
break;
|
|
case GDICOMMENT_BEGINGROUP:
|
|
case GDICOMMENT_ENDGROUP:
|
|
case GDICOMMENT_WINDOWS_METAFILE:
|
|
default:
|
|
b = TRUE;
|
|
break;
|
|
}
|
|
|
|
return(b) ;
|
|
}
|
|
|
|
BOOL WINAPI DoGdiCommentMultiFormats
|
|
(
|
|
PLOCALDC pLocalDC,
|
|
PEMRGDICOMMENT_MULTIFORMATS pemrcmf
|
|
)
|
|
{
|
|
DWORD i;
|
|
DWORD cSizeOld;
|
|
int iBase;
|
|
XFORM xformNew, xformScale;
|
|
POINTL aptlFrame[4];
|
|
RECTL rclFrame;
|
|
UINT cbwmfNew;
|
|
SIZEL szlDeviceNew, szlMillimetersNew;
|
|
BOOL bRet = FALSE;
|
|
PBYTE pbwmfNew = (PBYTE) NULL;
|
|
HDC hdcemfNew = (HDC) 0;
|
|
HENHMETAFILE hemf = (HENHMETAFILE) 0;
|
|
HENHMETAFILE hemfNew = (HENHMETAFILE) 0;
|
|
PENHMETAHEADER pemfh;
|
|
WIN16LOGBRUSH Win16LogBrush;
|
|
PMETARECORD pmr;
|
|
VOID* pvTemp = NULL;
|
|
#if DBG
|
|
int iSWO = 0;
|
|
int iSWE = 0;
|
|
#endif
|
|
|
|
// We will convert the enhanced metafile format only.
|
|
// Find the enhanced metafile data.
|
|
|
|
for (i = 0; i < pemrcmf->nFormats; i++)
|
|
{
|
|
if (pemrcmf->aemrformat[i].dSignature == ENHMETA_SIGNATURE
|
|
&& pemrcmf->aemrformat[i].nVersion <= META_FORMAT_ENHANCED)
|
|
break;
|
|
}
|
|
|
|
// If we cannot find a recognized format, return failure.
|
|
|
|
if (i >= pemrcmf->nFormats)
|
|
{
|
|
PUTS("MF3216: DoGdiCommentMultiFormats - no recognized format found\n");
|
|
goto dgcmf_exit;
|
|
}
|
|
|
|
// Get the embedded enhanced metafile.
|
|
|
|
hemf = SetEnhMetaFileBits((UINT) pemrcmf->aemrformat[i].cbData,
|
|
&((PBYTE) &pemrcmf->ident)[pemrcmf->aemrformat[i].offData]);
|
|
if (!hemf)
|
|
goto dgcmf_exit;
|
|
|
|
// Now the fun begins - we have to convert the enhanced metafile to
|
|
// Windows metafile.
|
|
// Since the multiformats record takes a logical rectangle, we have to
|
|
// set up a proper transform for the enhanced metafile. We do it by
|
|
// creating a new enhanced metafile and playing the embedded metafile
|
|
// into the new metafile with the proper transform setup.
|
|
// In addition, the new metafile may have a different resolution than the
|
|
// metafile. We need to take this into account when setting up
|
|
// the transform.
|
|
|
|
// Get the world to device transform for the logical rectangle.
|
|
|
|
if( pfnGetTransform != NULL )
|
|
{
|
|
if (!(pfnGetTransform)(pLocalDC->hdcHelper, XFORM_WORLD_TO_DEVICE, &xformNew))
|
|
goto dgcmf_exit;
|
|
}
|
|
else
|
|
{
|
|
xformNew = xformIdentity ;
|
|
}
|
|
|
|
// Compute the device scales.
|
|
|
|
szlDeviceNew.cx = GetDeviceCaps(pLocalDC->hdcRef, HORZRES);
|
|
szlDeviceNew.cy = GetDeviceCaps(pLocalDC->hdcRef, VERTRES);
|
|
szlMillimetersNew.cx = GetDeviceCaps(pLocalDC->hdcRef, HORZSIZE);
|
|
szlMillimetersNew.cy = GetDeviceCaps(pLocalDC->hdcRef, VERTSIZE);
|
|
pemfh = (PENHMETAHEADER) pLocalDC->pMf32Bits;
|
|
|
|
xformScale.eM11 = ((FLOAT) szlDeviceNew.cx / (FLOAT) szlMillimetersNew.cx)
|
|
/ ((FLOAT) pemfh->szlDevice.cx / (FLOAT) pemfh->szlMillimeters.cx);
|
|
xformScale.eM12 = 0.0f;
|
|
xformScale.eM21 = 0.0f;
|
|
xformScale.eM22 = ((FLOAT) szlDeviceNew.cy / (FLOAT) szlMillimetersNew.cy)
|
|
/ ((FLOAT) pemfh->szlDevice.cy / (FLOAT) pemfh->szlMillimeters.cy);
|
|
xformScale.eDx = 0.0f;
|
|
xformScale.eDy = 0.0f;
|
|
|
|
// Compute the resulting transform to apply to the new metafile.
|
|
|
|
if (!bCombineTransform(&xformNew, &xformNew, &xformScale))
|
|
goto dgcmf_exit;
|
|
|
|
// Create the new enhanced metafile.
|
|
|
|
// Compute the new metafile frame.
|
|
|
|
aptlFrame[0].x = pemrcmf->rclOutput.left;
|
|
aptlFrame[0].y = pemrcmf->rclOutput.top;
|
|
aptlFrame[1].x = pemrcmf->rclOutput.right;
|
|
aptlFrame[1].y = pemrcmf->rclOutput.top;
|
|
aptlFrame[2].x = pemrcmf->rclOutput.right;
|
|
aptlFrame[2].y = pemrcmf->rclOutput.bottom;
|
|
aptlFrame[3].x = pemrcmf->rclOutput.left;
|
|
aptlFrame[3].y = pemrcmf->rclOutput.bottom;
|
|
if (!bXformWorkhorse(aptlFrame, 4, &xformNew))
|
|
goto dgcmf_exit;
|
|
rclFrame.left = MulDiv(100 * MIN4(aptlFrame[0].x, aptlFrame[1].x,
|
|
aptlFrame[2].x, aptlFrame[3].x),
|
|
szlMillimetersNew.cx,
|
|
szlDeviceNew.cx);
|
|
rclFrame.right = MulDiv(100 * MAX4(aptlFrame[0].x, aptlFrame[1].x,
|
|
aptlFrame[2].x, aptlFrame[3].x),
|
|
szlMillimetersNew.cx,
|
|
szlDeviceNew.cx);
|
|
rclFrame.top = MulDiv(100 * MIN4(aptlFrame[0].y, aptlFrame[1].y,
|
|
aptlFrame[2].y, aptlFrame[3].y),
|
|
szlMillimetersNew.cy,
|
|
szlDeviceNew.cy);
|
|
rclFrame.bottom = MulDiv(100 * MAX4(aptlFrame[0].y, aptlFrame[1].y,
|
|
aptlFrame[2].y, aptlFrame[3].y),
|
|
szlMillimetersNew.cy,
|
|
szlDeviceNew.cy);
|
|
|
|
hdcemfNew = CreateEnhMetaFileA(pLocalDC->hdcRef, (LPCSTR) NULL,
|
|
(CONST RECT *) &rclFrame, (LPCSTR) NULL);
|
|
if (!hdcemfNew)
|
|
goto dgcmf_exit;
|
|
|
|
if (!SetGraphicsMode(hdcemfNew, GM_ADVANCED))
|
|
goto dgcmf_exit;
|
|
|
|
// Set up the transform in the new metafile.
|
|
|
|
if (!SetWorldTransform(hdcemfNew, &xformNew))
|
|
goto dgcmf_exit;
|
|
|
|
// Play the embedded metafile into the new metafile.
|
|
// This call ensures balanced level etc.
|
|
|
|
(void) PlayEnhMetaFile(hdcemfNew, hemf, (LPRECT) &pemrcmf->rclOutput);
|
|
|
|
// Close the new metafile.
|
|
|
|
hemfNew = CloseEnhMetaFile(hdcemfNew);
|
|
hdcemfNew = (HDC) 0; // used by clean up code below
|
|
|
|
// Convert the new enhanced metafile to windows metafile.
|
|
|
|
if (!(cbwmfNew = GetWinMetaFileBits(hemfNew, 0, (LPBYTE) NULL,
|
|
MM_ANISOTROPIC, pLocalDC->hdcRef)))
|
|
goto dgcmf_exit;
|
|
|
|
if (!(pbwmfNew = (PBYTE) LocalAlloc(LMEM_FIXED, cbwmfNew)))
|
|
goto dgcmf_exit;
|
|
|
|
if (cbwmfNew != GetWinMetaFileBits(hemfNew, cbwmfNew, pbwmfNew,
|
|
MM_ANISOTROPIC, pLocalDC->hdcRef))
|
|
goto dgcmf_exit;
|
|
|
|
// We now have the converted windows metafile. We need to include it into
|
|
// our current data stream. There are a few things to be aware of:
|
|
//
|
|
// 1. Expand the object handle slot table. The converted metafile may
|
|
// contain some undeleted objects. These objects are likely
|
|
// the "stock" objects in the converter. As a result, we need to
|
|
// expand the slot table by the number of object handles in the
|
|
// converted metafile.
|
|
// 2. The object index must be changed to the current object index.
|
|
// We are going to do this by the lazy method, i.e. we will elevate
|
|
// the current object index base to one higher than the current max
|
|
// object index in the current data stream. This is because Windows uses
|
|
// some an insane scheme for object index and this is the cheapest
|
|
// method. We elevate the object index base by filling up the empty
|
|
// indexes with dummy objects that are freed when we are done.
|
|
// 3. Remove the now useless comments.
|
|
// 4. Skip header and eof.
|
|
// 5. Set up the transform to place the embedded metafile into the data
|
|
// stream. We know that the metafile bits returned by the converter
|
|
// contains only a SetWindowOrg and a SetWindowExt record.
|
|
// By implementation, we can simply remove both the SetWindowOrg and
|
|
// SetWindowExt records from the data stream. The window origin and
|
|
// extents have been set up when we begin converting this enhanced
|
|
// metafile.
|
|
|
|
// Expand the object handle slot table.
|
|
|
|
if (((PMETAHEADER) pbwmfNew)->mtNoObjects)
|
|
{
|
|
cSizeOld = (DWORD) pLocalDC->cW16ObjHndlSlotStatus;
|
|
if (cSizeOld + ((PMETAHEADER)pbwmfNew)->mtNoObjects > (UINT) (WORD) MAXWORD)
|
|
goto dgcmf_exit; // w16 handle index is only 16-bit
|
|
|
|
pLocalDC->cW16ObjHndlSlotStatus += ((PMETAHEADER)pbwmfNew)->mtNoObjects;
|
|
i = pLocalDC->cW16ObjHndlSlotStatus * sizeof(W16OBJHNDLSLOTSTATUS);
|
|
|
|
// Allocate in a new pointer in case the allocation fails
|
|
pvTemp = LocalReAlloc(pLocalDC->pW16ObjHndlSlotStatus, i, LMEM_MOVEABLE);
|
|
if (pvTemp == NULL)
|
|
{
|
|
// Restore the old size and keep the memory...
|
|
pLocalDC->cW16ObjHndlSlotStatus = cSizeOld;
|
|
goto dgcmf_exit;
|
|
}
|
|
|
|
pLocalDC->pW16ObjHndlSlotStatus = (PW16OBJHNDLSLOTSTATUS) pvTemp;
|
|
|
|
for (i = cSizeOld; i < pLocalDC->cW16ObjHndlSlotStatus; i++)
|
|
{
|
|
pLocalDC->pW16ObjHndlSlotStatus[i].use = OPEN_AVAILABLE_SLOT;
|
|
pLocalDC->pW16ObjHndlSlotStatus[i].w32Handle = 0 ;
|
|
}
|
|
}
|
|
|
|
// Find the new base for the object index.
|
|
|
|
for (iBase = pLocalDC->cW16ObjHndlSlotStatus - 1; iBase >= 0; iBase--)
|
|
{
|
|
if (pLocalDC->pW16ObjHndlSlotStatus[iBase].use != OPEN_AVAILABLE_SLOT)
|
|
break;
|
|
}
|
|
iBase++;
|
|
|
|
// Fill up the object index table with dummy objects.
|
|
|
|
Win16LogBrush.lbStyle = BS_SOLID;
|
|
Win16LogBrush.lbColor = 0;
|
|
Win16LogBrush.lbHatch = 0;
|
|
|
|
for (i = 0; i < (DWORD) iBase; i++)
|
|
{
|
|
if (pLocalDC->pW16ObjHndlSlotStatus[i].use == OPEN_AVAILABLE_SLOT)
|
|
{
|
|
if (!bEmitWin16CreateBrushIndirect(pLocalDC, &Win16LogBrush))
|
|
goto dgcmf_exit;
|
|
pLocalDC->pW16ObjHndlSlotStatus[i].use = REALIZED_DUMMY;
|
|
}
|
|
}
|
|
|
|
// Update the high water mark.
|
|
|
|
if (iBase + ((PMETAHEADER) pbwmfNew)->mtNoObjects - 1 > pLocalDC->nObjectHighWaterMark)
|
|
pLocalDC->nObjectHighWaterMark = iBase + ((PMETAHEADER) pbwmfNew)->mtNoObjects - 1;
|
|
|
|
// Save DC states.
|
|
|
|
if (!bEmitWin16SaveDC(pLocalDC))
|
|
goto dgcmf_exit;
|
|
|
|
// Enumerate the records and fix them up as necessary.
|
|
|
|
for (pmr = (PMETARECORD) (pbwmfNew + sizeof(METAHEADER));
|
|
pmr->rdFunction != 0;
|
|
pmr = (PMETARECORD) ((PWORD) pmr + pmr->rdSize))
|
|
{
|
|
switch (pmr->rdFunction)
|
|
{
|
|
case META_SETWINDOWORG:
|
|
ASSERTGDI(++iSWO <= 1,
|
|
"MF3216: DoGdiCommentMultiFormats - unexpected SWO record\n");
|
|
break;
|
|
case META_SETWINDOWEXT:
|
|
ASSERTGDI(++iSWE <= 1,
|
|
"MF3216: DoGdiCommentMultiFormats - unexpected SWE record\n");
|
|
break;
|
|
|
|
case META_ESCAPE:
|
|
if (!IS_META_ESCAPE_ENHANCED_METAFILE((PMETA_ESCAPE_ENHANCED_METAFILE) pmr))
|
|
goto default_alt;
|
|
break;
|
|
|
|
case META_RESTOREDC:
|
|
ASSERTGDI((int)(SHORT)pmr->rdParm[0] < 0,
|
|
"MF3216: DoGdiCommentMultiFormats - bogus RestoreDC record\n");
|
|
goto default_alt;
|
|
|
|
case META_SELECTCLIPREGION:
|
|
if (pmr->rdParm[0] != 0) // allow for default clipping!
|
|
{
|
|
pmr->rdParm[0] += (WORD)iBase;
|
|
pLocalDC->pW16ObjHndlSlotStatus[pmr->rdParm[0]].use = REALIZED_OBJECT;
|
|
}
|
|
goto default_alt;
|
|
|
|
case META_FRAMEREGION:
|
|
case META_FILLREGION:
|
|
pmr->rdParm[1] += (WORD)iBase;
|
|
pLocalDC->pW16ObjHndlSlotStatus[pmr->rdParm[1]].use = REALIZED_OBJECT;
|
|
// fall through
|
|
case META_PAINTREGION:
|
|
case META_INVERTREGION:
|
|
case META_DELETEOBJECT:
|
|
case META_SELECTPALETTE:
|
|
case META_SELECTOBJECT:
|
|
pmr->rdParm[0] += (WORD)iBase;
|
|
if (pmr->rdFunction != META_DELETEOBJECT)
|
|
pLocalDC->pW16ObjHndlSlotStatus[pmr->rdParm[0]].use = REALIZED_OBJECT;
|
|
else
|
|
pLocalDC->pW16ObjHndlSlotStatus[pmr->rdParm[0]].use = OPEN_AVAILABLE_SLOT;
|
|
// fall through
|
|
default:
|
|
default_alt:
|
|
if (!bEmit(pLocalDC, (PVOID) pmr, pmr->rdSize * sizeof(WORD)))
|
|
goto dgcmf_exit;
|
|
vUpdateMaxRecord(pLocalDC, pmr);
|
|
break;
|
|
}
|
|
}
|
|
|
|
// Restore DC states.
|
|
|
|
if (!bEmitWin16RestoreDC(pLocalDC, (WORD) -1))
|
|
goto dgcmf_exit;
|
|
|
|
// Remove the dummy objects from the handle table.
|
|
|
|
for (i = 0; i < (DWORD) iBase; i++)
|
|
{
|
|
if (pLocalDC->pW16ObjHndlSlotStatus[i].use == REALIZED_DUMMY)
|
|
{
|
|
if (!bEmitWin16DeleteObject(pLocalDC, (WORD) i))
|
|
goto dgcmf_exit;
|
|
pLocalDC->pW16ObjHndlSlotStatus[i].use = OPEN_AVAILABLE_SLOT;
|
|
}
|
|
}
|
|
|
|
// Shrink the object handle slot table.
|
|
|
|
if (((PMETAHEADER) pbwmfNew)->mtNoObjects)
|
|
{
|
|
DWORD cUndel = 0; // number of objects not deleted
|
|
DWORD iUndelMax = iBase - 1; // the max undeleted object index
|
|
|
|
for (i = iBase; i < pLocalDC->cW16ObjHndlSlotStatus; i++)
|
|
{
|
|
if (pLocalDC->pW16ObjHndlSlotStatus[i].use != OPEN_AVAILABLE_SLOT)
|
|
{
|
|
cUndel++;
|
|
iUndelMax = i;
|
|
}
|
|
}
|
|
|
|
pLocalDC->cW16ObjHndlSlotStatus = max(cSizeOld + cUndel, iUndelMax + 1);
|
|
}
|
|
|
|
// Everything is golden.
|
|
|
|
bRet = TRUE;
|
|
|
|
dgcmf_exit:
|
|
|
|
if (pbwmfNew)
|
|
if (LocalFree(pbwmfNew))
|
|
ASSERTGDI(FALSE, "MF3216: DoGdiCommentMultiFormats - LocalFree failed\n");
|
|
|
|
if (hemf)
|
|
DeleteEnhMetaFile(hemf);
|
|
|
|
if (hdcemfNew)
|
|
hemfNew = CloseEnhMetaFile(hdcemfNew); // hemfNew will be deleted next
|
|
|
|
if (hemfNew)
|
|
DeleteEnhMetaFile(hemfNew);
|
|
|
|
return(bRet);
|
|
}
|
|
|
|
/***************************************************************************
|
|
* EOF - Win32 to Win16 Metafile Converter Entry Point
|
|
**************************************************************************/
|
|
BOOL APIENTRY DoEOF
|
|
(
|
|
PLOCALDC pLocalDC
|
|
)
|
|
{
|
|
BOOL b ;
|
|
|
|
b = bEmitWin16EOF(pLocalDC) ;
|
|
|
|
return(b) ;
|
|
}
|