Windows NT 4.0 source code leak
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.
 
 
 
 
 
 

3550 lines
94 KiB

/******************************Module*Header*******************************\
* Module Name: metarec.cxx
*
* Metafile recording functions.
*
* Created: 12-June-1991 13:46:00
* Author: Hock San Lee [hockl]
*
* Copyright (c) 1991 Microsoft Corporation
\**************************************************************************/
#define NO_STRICT
extern "C" {
#include <nt.h>
#include <ntrtl.h>
#include <nturtl.h>
#include <stddef.h>
#include <windows.h> // GDI function declarations.
#include <winerror.h>
#include "firewall.h"
#define __CPLUSPLUS
#include <winspool.h>
#include <wingdip.h>
#include "ntgdistr.h"
#include "winddi.h"
#include "hmgshare.h"
#include "local.h" // Local object support.
#include "metadef.h" // Metafile record type constants.
#include "metarec.h" // Metafile recording functions.
#include "mf16.h"
#include "nlsconv.h"
#include "ntgdi.h"
#include "xfflags.h"
#include "..\inc\mapfile.h"
}
#include "rectl.hxx"
#include "mfdc.hxx" // Metafile DC class declarations.
#include "mfrec.hxx" // Metafile record class declarations.
extern "C" {
#include "mfrec16.h" // 3.x Metafile recording functions
}
extern "C" BOOL bDoFontChange( HDC hdc );
extern "C" void ConvertDxArray(UINT CodePage,
char *pDBCSString,
INT *pDxDBCS,
UINT Count,
INT *pDxUnicode);
XFORM xformIdentity = { 1.00000000f, 0.00000000f, 0.00000000f, 1.00000000f,
0.00000000f, 0.00000000f };
// SaveDC
// BeginPath
// EndPath
// CloseFigure
// FlattenPath
// WidenPath
// AbortPath
// SetMetaRgn
// RealizePalette
extern "C" BOOL MF_Record(HDC hdc,DWORD mrType)
{
PMR pmr;
PLDC pldc;
DC_PLDC(hdc,pldc,FALSE);
PMDC pmdc = (PMDC)pldc->pvPMDC;
ASSERTGDI(pmdc,"no pmdc\n");
PUTS("MF_Record\n");
if (!(pmr = (PMR) pmdc->pvNewRecord(SIZEOF_MR)))
return(FALSE);
pmr->vInit(mrType);
pmr->vCommit(pmdc);
return(TRUE);
}
// FillPath
// StrokeAndFillPath
// StrokePath
extern "C" BOOL MF_BoundRecord(HDC hdc,DWORD mrType)
{
PMRB pmrb;
PLDC pldc;
DC_PLDC(hdc,pldc,FALSE);
PMDC pmdc = (PMDC)pldc->pvPMDC;
ASSERTGDI(pmdc,"no pmdc\n");
PUTS("MF_BoundRecord\n");
if (!(pmrb = (PMRB) pmdc->pvNewRecord(SIZEOF_MRB)))
return(FALSE);
pmrb->vInit(mrType, pmdc);
pmrb->vCommit(pmdc);
return(TRUE);
}
// SetMapperFlags
// SetMapMode
// SetBkMode
// SetPolyFillMode
// SetROP2
// SetStretchBltMode
// SetTextAlign
// SetTextColor
// SetBkColor
// RestoreDC
// SetArcDirection
// SetMiterLimit
// SelectClipPath
extern "C" BOOL MF_SetD(HDC hdc,DWORD d1,DWORD mrType)
{
PMRD pmrd;
PLDC pldc;
DC_PLDC(hdc,pldc,FALSE);
PMDC pmdc = (PMDC)pldc->pvPMDC;
ASSERTGDI(pmdc,"no pmdc\n");
PUTS("MF_SetD\n");
if( ( mrType == EMR_SETMAPMODE ) ||
( mrType == EMR_SETMAPPERFLAGS ) ||
( mrType == EMR_RESTOREDC ) )
{
PLDC pldc = GET_PLDC(hdc);
pldc->fl |= LDC_FONT_CHANGE;
}
if (!(pmrd = (PMRD) pmdc->pvNewRecord(SIZEOF_MRD)))
return(FALSE);
pmrd->vInit(mrType, d1);
pmrd->vCommit(pmdc);
return(TRUE);
}
// OffsetWindowOrgEx
// OffsetViewportOrgEx
// SetWindowExtEx
// SetWindowOrgEx
// SetViewportExtEx
// SetViewportOrgEx
// SetBrushOrgEx
// OffsetClipRgn
// MoveToEx
// LineTo
extern "C" BOOL MF_SetDD(HDC hdc,DWORD d1,DWORD d2,DWORD mrType)
{
PMRDD pmrdd;
PLDC pldc;
DC_PLDC(hdc,pldc,FALSE);
PMDC pmdc = (PMDC)pldc->pvPMDC;
ASSERTGDI(pmdc,"no pmdc\n");
PUTS("MF_SetDD\n");
if( ( mrType == META_SETVIEWPORTEXT ) || ( mrType == META_SETVIEWPORTEXT ) )
{
PLDC pldc = GET_PLDC(hdc);
pldc->fl |= LDC_FONT_CHANGE;
}
if (!(pmrdd = (PMRDD) pmdc->pvNewRecord(SIZEOF_MRDD)))
return(FALSE);
pmrdd->vInit(mrType, d1, d2);
pmrdd->vCommit(pmdc);
return(TRUE);
}
// ExcludeClipRect
// IntersectClipRect
// ScaleViewportExtEx
// ScaleWindowExtEx
extern "C" BOOL MF_SetDDDD(HDC hdc,DWORD d1,DWORD d2,DWORD d3,DWORD d4,DWORD mrType)
{
PMRDDDD pmrdddd;
PLDC pldc;
DC_PLDC(hdc,pldc,FALSE);
PMDC pmdc = (PMDC)pldc->pvPMDC;
ASSERTGDI(pmdc,"no pmdc\n");
PUTS("MF_SetDDDD\n");
if (!(pmrdddd = (PMRDDDD) pmdc->pvNewRecord(SIZEOF_MRDDDD)))
return(FALSE);
pmrdddd->vInit(mrType, d1, d2, d3, d4);
pmrdddd->vCommit(pmdc);
return(TRUE);
}
// SetMetaRgn
extern "C" BOOL MF_SetMetaRgn(HDC hdc)
{
PLDC pldc;
DC_PLDC(hdc,pldc,FALSE);
PMDC pmdc = (PMDC)pldc->pvPMDC;
ASSERTGDI(pmdc,"no pmdc\n");
PUTS("MF_SetMetaRgn\n");
// Record it first.
if (!MF_Record(hdc,EMR_SETMETARGN))
return(FALSE);
// We have to flush the bounds before we change the clipping region
// because the bounds are clipped to the current clipping region bounds.
pmdc->vFlushBounds();
// Now update the clipping bounds to prepare for the next flush.
pmdc->vSetMetaBounds();
return(TRUE);
}
// SelectClipPath
extern "C" BOOL MF_SelectClipPath(HDC hdc,int iMode)
{
PLDC pldc;
DC_PLDC(hdc,pldc,FALSE);
PMDC pmdc = (PMDC)pldc->pvPMDC;
ASSERTGDI(pmdc,"no pmdc\n");
PUTS("MF_SelectClipPath\n");
// Record it first.
if (!MF_SetD(hdc, (DWORD) iMode, EMR_SELECTCLIPPATH))
return(FALSE);
// We have to flush the bounds before we change the clipping region
// because the bounds are clipped to the current clipping region bounds.
pmdc->vFlushBounds();
// Now mark the clipping bounds dirty. The clipping bounds is updated
// when it is needed.
pmdc->vMarkClipBoundsDirty();
return(TRUE);
}
// OffsetClipRgn
extern "C" BOOL MF_OffsetClipRgn(HDC hdc,int x1,int y1)
{
PLDC pldc;
DC_PLDC(hdc,pldc,FALSE);
PMDC pmdc = (PMDC)pldc->pvPMDC;
ASSERTGDI(pmdc,"no pmdc\n");
PUTS("MF_OffsetClipRgn\n");
// Record it first.
if (!MF_SetDD(hdc, (DWORD) x1, (DWORD) y1, EMR_OFFSETCLIPRGN))
return(FALSE);
// We have to flush the bounds before we change the clipping region
// because the bounds are clipped to the current clipping region bounds.
pmdc->vFlushBounds();
// Now mark the clipping bounds dirty. The clipping bounds is updated
// when it is needed.
pmdc->vMarkClipBoundsDirty();
return(TRUE);
}
// ExcludeClipRect
// IntersectClipRect
extern "C" BOOL MF_AnyClipRect(HDC hdc,int x1,int y1,int x2,int y2,DWORD mrType)
{
BOOL bRet = FALSE;
HRGN hrgnTmp;
PLDC pldc;
DC_PLDC(hdc,pldc,FALSE);
PMDC pmdc = (PMDC)pldc->pvPMDC;
ASSERTGDI(pmdc,"no pmdc\n");
PUTS("MF_AnyClipRect\n");
// Record it first.
if (!MF_SetDDDD(hdc, (DWORD) x1, (DWORD) y1, (DWORD) x2, (DWORD) y2, mrType))
return(bRet);
// We have to flush the bounds before we change the clipping region
// because the bounds are clipped to the current clipping region bounds.
pmdc->vFlushBounds();
// Now mark the clipping bounds dirty. The clipping bounds is updated
// when it is needed.
pmdc->vMarkClipBoundsDirty();
// For ExcludeClipRect and InteresectClipRect, this is a little tricky.
// If there is no initial clip region, we have to create a default clipping
// region. Otherwise, GDI will create some random default clipping region
// for us!
// Find out if we have a clip region.
if (!(hrgnTmp = CreateRectRgn(0, 0, 0, 0)))
return(bRet);
switch (GetClipRgn(hdc, hrgnTmp))
{
case -1: // error
ASSERTGDI(FALSE, "GetClipRgn failed");
break;
case 0: // no initial clip region
// We need to select in our default clipping region.
// First, make our default clipping region.
if (!SetRectRgn(hrgnTmp,
#if 0
// Compiler bug!!! It generates 0x00008000.
(int) (SHORT) MINSHORT,
(int) (SHORT) MINSHORT,
#else
(int) 0xffff8000,
(int) 0xffff8000,
#endif
(int) (SHORT) MAXSHORT,
(int) (SHORT) MAXSHORT))
{
ASSERTGDI(FALSE, "SetRectRgn failed");
break;
}
// Now select our default region but don't metafile the call.
{
INT iRet;
iRet = NtGdiExtSelectClipRgn(hdc, hrgnTmp, RGN_COPY);
bRet = (iRet != RGN_ERROR);
}
break;
case 1: // has initial clip region
bRet = TRUE;
break;
}
if (!DeleteObject(hrgnTmp))
ASSERTGDI(FALSE, "DeleteObject failed");
return(bRet);
}
// Always store the relative level.
extern "C" BOOL MF_RestoreDC(HDC hdc,int iLevel)
{
int cLevel = (int) GetDCDWord(hdc,DDW_SAVEDEPTH,0);
PLDC pldc;
DC_PLDC(hdc,pldc,FALSE);
PMDC pmdc = (PMDC)pldc->pvPMDC;
ASSERTGDI(pmdc,"no pmdc\n");
// Compute the relative level.
if (iLevel > 0)
{
iLevel = iLevel - cLevel;
}
// Check bad levels.
if ((iLevel >= 0) || (iLevel + cLevel <= 0))
return(FALSE);
if (!MF_SetD(hdc,(DWORD)iLevel,EMR_RESTOREDC))
return(FALSE);
// We have to flush the bounds before we change the clipping region
// because the bounds are clipped to the current clipping region bounds.
pmdc->vFlushBounds();
// Now mark the clipping bounds dirty. The clipping bounds is updated
// when it is needed.
pmdc->vMarkClipBoundsDirty();
pmdc->vMarkMetaBoundsDirty();
return(TRUE);
}
extern "C" BOOL MF_SetViewportExtEx(HDC hdc,int x,int y)
{
return(MF_SetDD(hdc,(DWORD)x,(DWORD)y,EMR_SETVIEWPORTEXTEX));
}
extern "C" BOOL MF_SetViewportOrgEx(HDC hdc,int x,int y)
{
return(MF_SetDD(hdc,(DWORD)x,(DWORD)y,EMR_SETVIEWPORTORGEX));
}
extern "C" BOOL MF_SetWindowExtEx(HDC hdc,int x,int y)
{
return(MF_SetDD(hdc,(DWORD)x,(DWORD)y,EMR_SETWINDOWEXTEX));
}
extern "C" BOOL MF_SetWindowOrgEx(HDC hdc,int x,int y)
{
return(MF_SetDD(hdc,(DWORD)x,(DWORD)y,EMR_SETWINDOWORGEX));
}
// Map it to SetViewportOrgEx record.
extern "C" BOOL MF_OffsetViewportOrgEx(HDC hdc,int x,int y)
{
POINTL ptl;
if (!GetViewportOrgEx(hdc, (LPPOINT) &ptl))
return(FALSE);
return
(
MF_SetDD
(
hdc,
(DWORD)(ptl.x + (LONG) x),
(DWORD)(ptl.y + (LONG) y),
EMR_SETVIEWPORTORGEX
)
);
}
// Map it to SetWindowOrgEx record.
extern "C" BOOL MF_OffsetWindowOrgEx(HDC hdc,int x,int y)
{
POINTL ptl;
if (!GetWindowOrgEx(hdc, (LPPOINT) &ptl))
return(FALSE);
return
(
MF_SetDD
(
hdc,
(DWORD) (ptl.x + (LONG) x),
(DWORD) (ptl.y + (LONG) y),
EMR_SETWINDOWORGEX
)
);
}
extern "C" BOOL MF_SetBrushOrgEx(HDC hdc,int x,int y)
{
return(MF_SetDD(hdc,(DWORD)x,(DWORD)y,EMR_SETBRUSHORGEX));
}
// PolyBezier
// Polygon
// Polyline
// PolyBezierTo
// PolylineTo
extern "C" BOOL MF_Poly(HDC hdc, CONST POINT *pptl,DWORD cptl,DWORD mrType)
{
PLDC pldc;
DC_PLDC(hdc,pldc,FALSE);
PMDC pmdc = (PMDC)pldc->pvPMDC;
ASSERTGDI(pmdc,"no pmdc\n");
PUTS("MF_Poly\n");
// Check input assumptions.
ASSERTGDI
(
mrType == EMR_POLYBEZIER
|| mrType == EMR_POLYGON
|| mrType == EMR_POLYLINE
|| mrType == EMR_POLYBEZIERTO
|| mrType == EMR_POLYLINETO,
"MF_Poly: Bad record type"
);
ASSERTGDI
(
EMR_POLYGON - EMR_POLYBEZIER == EMR_POLYGON16 - EMR_POLYBEZIER16
&& EMR_POLYLINE - EMR_POLYBEZIER == EMR_POLYLINE16 - EMR_POLYBEZIER16
&& EMR_POLYBEZIERTO - EMR_POLYBEZIER == EMR_POLYBEZIERTO16 - EMR_POLYBEZIER16
&& EMR_POLYLINETO - EMR_POLYBEZIER == EMR_POLYLINETO16 - EMR_POLYBEZIER16,
"MF_Poly: Bad record type"
);
// Store 16-bit record if possible.
if (bIsPoly16((PPOINTL) pptl, cptl))
{
PMRBP16 pmrbp16;
if (!(pmrbp16 = (PMRBP16) pmdc->pvNewRecord(SIZEOF_MRBP16(cptl))))
return(FALSE);
pmrbp16->vInit
(
mrType - EMR_POLYBEZIER + EMR_POLYBEZIER16,
cptl,
(PPOINTL) pptl,
pmdc
);
pmrbp16->vCommit(pmdc);
}
else
{
PMRBP pmrbp;
if (!(pmrbp = (PMRBP) pmdc->pvNewRecord(SIZEOF_MRBP(cptl))))
return(FALSE);
pmrbp->vInit(mrType, cptl, (PPOINTL) pptl, pmdc);
pmrbp->vCommit(pmdc);
}
return(TRUE);
}
// PolyPolygon
// PolyPolyline
extern "C" BOOL MF_PolyPoly(HDC hdc, CONST POINT *pptl, CONST DWORD *pc,DWORD cPoly,DWORD mrType)
{
PLDC pldc;
DC_PLDC(hdc,pldc,FALSE);
PMDC pmdc = (PMDC)pldc->pvPMDC;
ASSERTGDI(pmdc,"no pmdc\n");
PUTS("MF_PolyPoly\n");
// Check input assumptions.
ASSERTGDI
(
mrType == EMR_POLYPOLYGON
|| mrType == EMR_POLYPOLYLINE,
"MF_PolyPoly: Bad record type"
);
ASSERTGDI
(
EMR_POLYPOLYLINE - EMR_POLYPOLYGON == EMR_POLYPOLYLINE16 - EMR_POLYPOLYGON16,
"MF_Poly: Bad record type"
);
// Compute the size of the PolyPoly record.
DWORD cptl = 0;
for (DWORD i = 0; i < cPoly; i++)
cptl += pc[i];
// Store 16-bit record if possible.
if (bIsPoly16((PPOINTL) pptl, cptl))
{
PMRBPP16 pmrbpp16;
if (!(pmrbpp16 = (PMRBPP16) pmdc->pvNewRecord(SIZEOF_MRBPP16(cptl,cPoly))))
return(FALSE);
pmrbpp16->vInit
(
mrType - EMR_POLYPOLYGON + EMR_POLYPOLYGON16,
cPoly,
cptl,
(LPDWORD) pc,
(PPOINTL) pptl,
pmdc
);
pmrbpp16->vCommit(pmdc);
}
else
{
PMRBPP pmrbpp;
if (!(pmrbpp = (PMRBPP) pmdc->pvNewRecord(SIZEOF_MRBPP(cptl,cPoly))))
return(FALSE);
pmrbpp->vInit(mrType, cPoly, cptl, (LPDWORD) pc, (PPOINTL) pptl, pmdc);
pmrbpp->vCommit(pmdc);
}
return(TRUE);
}
// PolyDraw
extern "C" BOOL MF_PolyDraw(HDC hdc, CONST POINT *pptl, CONST BYTE *pb, DWORD cptl)
{
PLDC pldc;
DC_PLDC(hdc,pldc,FALSE);
PMDC pmdc = (PMDC)pldc->pvPMDC;
ASSERTGDI(pmdc,"no pmdc\n");
PUTS("MF_PolyDraw\n");
// Store 16-bit record if possible.
if (bIsPoly16((PPOINTL) pptl, cptl))
{
PMRPOLYDRAW16 pmrpd16;
if (!(pmrpd16 = (PMRPOLYDRAW16) pmdc->pvNewRecord(SIZEOF_MRPOLYDRAW16(cptl))))
return(FALSE);
pmrpd16->vInit(pmdc, (PPOINTL) pptl, pb, cptl);
pmrpd16->vCommit(pmdc);
}
else
{
PMRPOLYDRAW pmrpd;
if (!(pmrpd = (PMRPOLYDRAW) pmdc->pvNewRecord(SIZEOF_MRPOLYDRAW(cptl))))
return(FALSE);
pmrpd->vInit(pmdc, (PPOINTL) pptl, pb, cptl);
pmrpd->vCommit(pmdc);
}
return(TRUE);
}
// InvertRgn
// PaintRgn
extern "C" BOOL MF_InvertPaintRgn(HDC hdc,HRGN hrgn,DWORD mrType)
{
PMRBR pmrbr;
DWORD cRgnData;
PLDC pldc;
DC_PLDC(hdc,pldc,FALSE);
PMDC pmdc = (PMDC)pldc->pvPMDC;
ASSERTGDI(pmdc,"no pmdc\n");
PUTS("MF_InvertPaintRgn\n");
// Get the size of the region data.
if (!(cRgnData = GetRegionData(hrgn, 0, (LPRGNDATA) NULL)))
return(FALSE);
// Allocate dword aligned structure.
if (!(pmrbr = (PMRBR) pmdc->pvNewRecord(SIZEOF_MRBR(cRgnData))))
return(FALSE);
if (!pmrbr->bInit(mrType, pmdc, hrgn, cRgnData, sizeof(MRBR)))
return(FALSE);
pmrbr->vCommit(pmdc);
return(TRUE);
}
// FillRgn
extern "C" BOOL MF_FillRgn(HDC hdc,HRGN hrgn,HBRUSH hbrush)
{
PMRFILLRGN pmrfr;
DWORD cRgnData;
DWORD imheBrush;
PLDC pldc;
DC_PLDC(hdc,pldc,FALSE);
PMDC pmdc = (PMDC)pldc->pvPMDC;
ASSERTGDI(pmdc,"no pmdc\n");
PUTS("MF_FillRgn\n");
// Create the brush first.
if (!(imheBrush = MF_InternalCreateObject(hdc, hbrush)))
return(FALSE);
// Get the size of the region data.
if (!(cRgnData = GetRegionData(hrgn, 0, (LPRGNDATA) NULL)))
return(FALSE);
// Allocate dword aligned structure.
if (!(pmrfr = (PMRFILLRGN) pmdc->pvNewRecord(SIZEOF_MRFILLRGN(cRgnData))))
return(FALSE);
if (!pmrfr->bInit(pmdc, hrgn, cRgnData, imheBrush))
return(FALSE);
pmrfr->vCommit(pmdc);
return(TRUE);
}
// FrameRgn
extern "C" BOOL MF_FrameRgn(HDC hdc,HRGN hrgn,HBRUSH hbrush,int cx,int cy)
{
PMRFRAMERGN pmrfr;
DWORD cRgnData;
DWORD imheBrush;
PLDC pldc;
DC_PLDC(hdc,pldc,FALSE);
PMDC pmdc = (PMDC)pldc->pvPMDC;
ASSERTGDI(pmdc,"no pmdc\n");
PUTS("MF_FrameRgn\n");
// Create the brush first.
if (!(imheBrush = MF_InternalCreateObject(hdc, hbrush)))
return(FALSE);
// Get the size of the region data.
if (!(cRgnData = GetRegionData(hrgn, 0, (LPRGNDATA) NULL)))
return(FALSE);
// Allocate dword aligned structure.
if (!(pmrfr = (PMRFRAMERGN) pmdc->pvNewRecord(SIZEOF_MRFRAMERGN(cRgnData))))
return(FALSE);
if (!pmrfr->bInit(pmdc, hrgn, cRgnData, imheBrush, (LONG) cx, (LONG) cy))
return(FALSE);
pmrfr->vCommit(pmdc);
return(TRUE);
}
// SelectClipRgn
// ExtSelectClipRgn
// SelectObject(hdc,hrgn)
extern "C" BOOL MF_ExtSelectClipRgn(HDC hdc,HRGN hrgn,int iMode)
{
PMREXTSELECTCLIPRGN pmrescr;
DWORD cRgnData;
PLDC pldc;
DC_PLDC(hdc,pldc,FALSE);
PMDC pmdc = (PMDC)pldc->pvPMDC;
ASSERTGDI(pmdc,"no pmdc\n");
PUTS("MF_ExtSelectClipRgn\n");
// Get the size of the region data.
if (iMode == RGN_COPY && hrgn == (HRGN) 0)
cRgnData = 0;
else if (!(cRgnData = GetRegionData(hrgn, 0, (LPRGNDATA) NULL)))
return(FALSE);
// Allocate dword aligned structure.
if (!(pmrescr = (PMREXTSELECTCLIPRGN) pmdc->pvNewRecord
(SIZEOF_MREXTSELECTCLIPRGN(cRgnData))))
return(FALSE);
if (!pmrescr->bInit(hrgn, cRgnData, (DWORD) iMode))
return(FALSE);
pmrescr->vCommit(pmdc);
// We have to flush the bounds before we change the clipping region
// because the bounds are clipped to the current clipping region bounds.
pmdc->vFlushBounds();
// Now mark the clipping bounds dirty. The clipping bounds is updated
// when it is needed.
pmdc->vMarkClipBoundsDirty();
return(TRUE);
}
// SetPixel
// SetPixelV
extern "C" BOOL MF_SetPixelV(HDC hdc,int x,int y,COLORREF color)
{
PMRSETPIXELV pmrspv;
PLDC pldc;
DC_PLDC(hdc,pldc,FALSE);
PMDC pmdc = (PMDC)pldc->pvPMDC;
ASSERTGDI(pmdc,"no pmdc\n");
PUTS("MF_SetPixelV\n");
if (!(pmrspv = (PMRSETPIXELV) pmdc->pvNewRecord(SIZEOF_MRSETPIXELV)))
return(FALSE);
pmrspv->vInit(x, y, color);
pmrspv->vCommit(pmdc);
return(TRUE);
}
// AngleArc
extern "C" BOOL MF_AngleArc(HDC hdc,int x,int y,DWORD r,FLOAT eA,FLOAT eB)
{
PMRANGLEARC pmraa;
PLDC pldc;
DC_PLDC(hdc,pldc,FALSE);
PMDC pmdc = (PMDC)pldc->pvPMDC;
ASSERTGDI(pmdc,"no pmdc\n");
PUTS("MF_AngleArc\n");
if (!(pmraa = (PMRANGLEARC) pmdc->pvNewRecord(SIZEOF_MRANGLEARC)))
return(FALSE);
pmraa->vInit(x, y, r, eA, eB);
pmraa->vCommit(pmdc);
return(TRUE);
}
// SetArcDirection - This is recorded only when used.
extern "C" BOOL MF_ValidateArcDirection(HDC hdc)
{
PLDC pldc;
BOOL bClockwiseMeta, bClockwiseAdvanced;
PDC_ATTR pDcAttr;
PVOID pvUser;
DC_PLDC(hdc,pldc,FALSE);
PUTS("MF_ValidateArcDirection\n");
// Get the current arc direction recorded in the metafile.
// The metafile is recorded in the advanced graphics mode only.
bClockwiseMeta = (pldc->fl & LDC_META_ARCDIR_CLOCKWISE) ? TRUE : FALSE;
// Get the current arc direction in the advanced graphics mode.
bClockwiseAdvanced = (GetArcDirection(hdc) == AD_CLOCKWISE);
if (GetGraphicsMode(hdc) == GM_COMPATIBLE)
{
switch (GetMapMode(hdc))
{
case MM_LOMETRIC:
case MM_HIMETRIC:
case MM_LOENGLISH:
case MM_HIENGLISH:
case MM_TWIPS:
bClockwiseAdvanced = !bClockwiseAdvanced;
break;
}
}
PSHARED_GET_VALIDATE(pvUser,hdc,DC_TYPE);
if (pvUser)
{
pDcAttr = (PDC_ATTR)pvUser;
if (pDcAttr->flXform & PTOD_EFM22_NEGATIVE)
bClockwiseAdvanced = !bClockwiseAdvanced;
}
// Record it only if the new arc direction differs from the recorded one.
if (bClockwiseMeta == bClockwiseAdvanced)
return(TRUE);
pldc->fl ^= LDC_META_ARCDIR_CLOCKWISE;
return
(
MF_SetD
(
hdc,
(DWORD) (bClockwiseAdvanced ? AD_CLOCKWISE : AD_COUNTERCLOCKWISE),
EMR_SETARCDIRECTION
)
);
}
// Ellipse
// Rectangle
extern "C" BOOL MF_EllipseRect(HDC hdc,int x1,int y1,int x2,int y2,DWORD mrType)
{
PMRE pmre;
PLDC pldc;
DC_PLDC(hdc,pldc,FALSE);
PMDC pmdc = (PMDC)pldc->pvPMDC;
ASSERTGDI(pmdc,"no pmdc\n");
PUTS("MF_EllipseRect\n");
// Validate the arc direction in the metafile first.
if (!MF_ValidateArcDirection(hdc))
return(FALSE);
if (!(pmre = (PMRE) pmdc->pvNewRecord(SIZEOF_MRE)))
return(FALSE);
// If the box is empty, don't record it and return success.
switch (pmre->iInit(mrType, hdc, x1, y1, x2, y2))
{
case MRI_ERROR: return(FALSE);
case MRI_NULLBOX: return(TRUE);
case MRI_OK: break;
default: ASSERTGDI(FALSE, "MRE::iInit returned bad value");
break;
}
pmre->vCommit(pmdc);
return(TRUE);
}
// RoundRect
extern "C" BOOL MF_RoundRect(HDC hdc,int x1,int y1,int x2,int y2,int x3,int y3)
{
PMRROUNDRECT pmrrr;
PUTS("MF_RoundRect\n");
PLDC pldc;
DC_PLDC(hdc,pldc,FALSE);
PMDC pmdc = (PMDC)pldc->pvPMDC;
ASSERTGDI(pmdc,"no pmdc\n");
// Validate the arc direction in the metafile first.
if (!MF_ValidateArcDirection(hdc))
return(FALSE);
if (!(pmrrr = (PMRROUNDRECT) pmdc->pvNewRecord(SIZEOF_MRROUNDRECT)))
return(FALSE);
// If the box is empty, don't record it and return success.
switch (pmrrr->iInit(hdc, x1, y1, x2, y2, x3, y3))
{
case MRI_ERROR: return(FALSE);
case MRI_NULLBOX: return(TRUE);
case MRI_OK: break;
default: ASSERTGDI(FALSE, "MRROUNDRECT::iInit returned bad value");
break;
}
pmrrr->vCommit(pmdc);
return(TRUE);
}
// Arc
// ArcTo
// Chord
// Pie
extern "C" BOOL MF_ArcChordPie(HDC hdc,int x1,int y1,int x2,int y2,int x3,int y3,int x4,int y4,DWORD mrType)
{
PMREPP pmrepp;
PLDC pldc;
DC_PLDC(hdc,pldc,FALSE);
PMDC pmdc = (PMDC)pldc->pvPMDC;
ASSERTGDI(pmdc,"no pmdc\n");
PUTS("MF_ArcChordPie\n");
// Validate the arc direction in the metafile first.
if (!MF_ValidateArcDirection(hdc))
return(FALSE);
if (!(pmrepp = (PMREPP) pmdc->pvNewRecord(SIZEOF_MREPP)))
return(FALSE);
// If the box is empty, don't record it and return success.
switch (pmrepp->iInit(mrType, hdc, x1, y1, x2, y2, x3, y3, x4, y4))
{
case MRI_ERROR: return(FALSE);
case MRI_NULLBOX: return(TRUE);
case MRI_OK: break;
default: ASSERTGDI(FALSE, "MREPP::iInit returned bad value");
break;
}
pmrepp->vCommit(pmdc);
return(TRUE);
}
// SetWorldTransform
extern "C" BOOL MF_SetWorldTransform(HDC hdc, CONST XFORM *pxform)
{
PMRX pmrx;
PLDC pldc;
DC_PLDC(hdc,pldc,FALSE);
PMDC pmdc = (PMDC)pldc->pvPMDC;
ASSERTGDI(pmdc,"no pmdc\n");
PUTS("MF_SetWorldTransform\n");
if (!(pmrx = (PMRX) pmdc->pvNewRecord(SIZEOF_MRX)))
return(FALSE);
pmrx->vInit(EMR_SETWORLDTRANSFORM, *pxform);
pmrx->vCommit(pmdc);
return(TRUE);
}
// ModifyWorldTransform
extern "C" BOOL MF_ModifyWorldTransform(HDC hdc, CONST XFORM *pxform, DWORD iMode)
{
PMRXD pmrxd;
PLDC pldc;
DC_PLDC(hdc,pldc,FALSE);
PMDC pmdc = (PMDC)pldc->pvPMDC;
ASSERTGDI(pmdc,"no pmdc\n");
PUTS("MF_ModifyWorldTransform\n");
if (!(pmrxd = (PMRXD) pmdc->pvNewRecord(SIZEOF_MRXD)))
return(FALSE);
// If the mode is set to identity transform, use our identity transform
// since there may not be an input transform.
pmrxd->vInit
(
EMR_MODIFYWORLDTRANSFORM,
(iMode == MWT_IDENTITY) ? xformIdentity : *pxform,
iMode
);
pmrxd->vCommit(pmdc);
return(TRUE);
}
// SelectObject
// SelectPalette
extern "C" BOOL MF_SelectAnyObject(HDC hdc,HANDLE h,DWORD mrType)
{
DWORD imhe;
// Do not do regions. Region call goes to ExtSelectClipRgn.
// Do not do bitmap. Metafile DC is not a memory device.
// MF_InternalCreateObject will return an error if given a bitmap handle.
PUTS("MF_SelectAnyObject\n");
if (!(imhe = MF_InternalCreateObject(hdc, h)))
return(FALSE);
return(MF_SetD(hdc, imhe, mrType));
}
// CreatePen
// CreatePenIndirect
// ExtCreatePen
// CreateBrushIndirect
// CreateDIBPatternBrush
// CreateDIBPatternBrushPt
// CreateHatchBrush
// CreatePatternBrush
// CreateSolidBrush
// CreatePalette
// CreateFont
// CreateFontIndirect
// Create an object if it does not exist. The object must not be a region.
// It also does not create bitmap objects since we keep them in the drawing
// records.
// Return the metafile handle index of the object. For stock objects,
// return the special object index.
// Return 0 on error.
DWORD MF_InternalCreateObject(HDC hdc,HANDLE hobj)
{
DWORD imhe;
UINT ii;
int iType;
int iRet;
LOGBRUSH lb;
PLDC pldc;
DC_PLDC(hdc,pldc,FALSE);
PMDC pmdc = (PMDC)pldc->pvPMDC;
ASSERTGDI(pmdc,"no pmdc\n");
PUTS("MF_InternalCreateObject\n");
if (hobj == NULL)
{
return(0);
}
// Do not do bitmaps. We don't keep bitmap handles in metafiles.
iType = LO_TYPE(hobj);
if ((iType == LO_BITMAP_TYPE) || (iType == LO_DIBSECTION_TYPE))
{
ERROR_ASSERT(FALSE,
"MF_InternalCreateObject: Cannot select bitmap into an enhanced metafile DC");
return(0);
}
// Do not do regions. Regions are stored in the drawing records.
ASSERTGDI(iType != LO_REGION_TYPE,
"MF_InternalCreateObject: Bad object type");
// If this is a stock object, just return a special object index.
if (IS_STOCKOBJ(hobj))
{
for (ii = 0; ii <= STOCK_LAST; ii++)
{
if (GetStockObject(ii) == hobj)
{
break;
}
}
return((DWORD) ENHMETA_STOCK_OBJECT + ii);
}
// Check if the metafile DC knows this object.
METALINK metalink(pmetalink16Get(hobj));
while (metalink.bValid() && (metalink.ihdc != H_INDEX(hdc)))
metalink.vNext();
// If the metafile DC knows this object, just return the metafile handle index.
if (metalink.bValid())
{
if( iType == LO_FONT_TYPE )
{
pldc->fl |= LDC_FONT_CHANGE;
}
return((DWORD) metalink.imhe);
}
// Create the object.
DWORD ulRet = 0; // Assume failure
// Allocate a metafile handle entry and update the metalink.
if ((imhe = imheAllocMHE(hdc, hobj)) == INVALID_INDEX)
return(ulRet);
switch (iType)
{
// Do brush.
case LO_BRUSH_TYPE:
iRet = GetObject(hobj,sizeof(lb),&lb);
// Stock objects is handled above.
ASSERTGDI(iRet,"MF_InternalCreateObject: Brush error");
switch (lb.lbStyle)
{
case BS_HATCHED:
case BS_HOLLOW:
case BS_SOLID:
PMRCREATEBRUSHINDIRECT pmrcbi;
if (!(pmrcbi = (PMRCREATEBRUSHINDIRECT) pmdc->pvNewRecord
(SIZEOF_MRCREATEBRUSHINDIRECT)))
break;
pmrcbi->vInit(imhe, lb);
pmrcbi->vCommit(pmdc);
ulRet = imhe;
break;
case BS_PATTERN:
case BS_DIBPATTERN:
case BS_DIBPATTERNPT:
{
UINT iUsage;
HBITMAP hbmRemote;
BMIH bmih;
DWORD cbBitsInfo;
DWORD cbBits;
BOOL bMonoBrush = FALSE;
if (!(hbmRemote = GetObjectBitmapHandle((HBRUSH)hobj, &iUsage)))
{
ASSERTGDI(FALSE,
"MF_InternalCreateObject: GetObjectBitmapHandle failed");
break;
}
// For a pattern brush, the usage should be set to DIB_PAL_INDICES
// if it is monochrome. If it is color, it becomes a dib pattern
// brush with DIB_RGB_COLORS usage.
if (lb.lbStyle == BS_PATTERN)
{
bMonoBrush = MonoBitmap(hbmRemote);
if (bMonoBrush)
iUsage = DIB_PAL_INDICES;
else
iUsage = DIB_RGB_COLORS;
}
// Get the bitmap info header and sizes.
if (!bMetaGetDIBInfo(hdc, hbmRemote, &bmih,
&cbBitsInfo, &cbBits, iUsage, 0, FALSE))
break;
// Finally create the record and get the bits.
PMRBRUSH pmrbr;
if (!(pmrbr = (PMRBRUSH) pmdc->pvNewRecord
(SIZEOF_MRBRUSH(cbBitsInfo,cbBits))))
break;
if (!pmrbr->bInit
(
bMonoBrush
? EMR_CREATEMONOBRUSH
: EMR_CREATEDIBPATTERNBRUSHPT,
hdc,
imhe,
hbmRemote,
bmih,
iUsage,
cbBitsInfo, // size of bitmap info
cbBits // size of bits buffer
)
)
break;
pmrbr->vCommit(pmdc);
ulRet = imhe;
}
break;
default:
ASSERTGDI(FALSE, "MF_InternalCreateObject: Brush error");
}
break;
// Do pen.
case LO_PEN_TYPE:
PMRCREATEPEN pmrcpn;
// Allocate dword aligned structure.
if (!(pmrcpn = (PMRCREATEPEN) pmdc->pvNewRecord(SIZEOF_MRCREATEPEN)))
break;
if (!pmrcpn->bInit(hobj, imhe))
break;
pmrcpn->vCommit(pmdc);
ulRet = imhe;
break;
// Do extended pen.
case LO_EXTPEN_TYPE:
EXTLOGPEN elp;
PEXTLOGPEN pelp;
int cbelp;
// Get the size of the ExtPen.
if (!(cbelp = GetObjectA(hobj, 0, (LPVOID) NULL)))
break;
ASSERTGDI(cbelp % 4 == 0, "MF_InternalCreateObject: Bad ext pen size");
if (cbelp <= sizeof(EXTLOGPEN))
pelp = &elp;
else if (!(pelp = (PEXTLOGPEN) LocalAlloc(LMEM_FIXED, (UINT) cbelp)))
break;
// Get the ExtPen.
if (GetObjectA(hobj, cbelp, (LPVOID) pelp) == cbelp)
{
UINT iUsage;
HBITMAP hbmRemote = (HBITMAP) 0;
BMIH bmih;
DWORD cbBitsInfo = 0;
DWORD cbBits = 0;
BOOL bMonoBrush = FALSE;
// Use switch statement so we can use the break statement on error.
// The following code is similiar to the brush creation code.
switch (pelp->elpBrushStyle)
{
case BS_DIBPATTERN:
pelp->elpBrushStyle = BS_DIBPATTERNPT; // fall through
case BS_PATTERN:
case BS_DIBPATTERNPT:
if (!(hbmRemote = GetObjectBitmapHandle((HBRUSH)hobj, &iUsage)))
{
ASSERTGDI(FALSE,
"MF_InternalCreateObject: GetObjectBitmapHandle failed");
break;
}
// For a pattern brush, the usage should be set to
// DIB_PAL_INDICES if it is monochrome. If it is color,
// it becomes a dib pattern brush with DIB_RGB_COLORS usage.
if (pelp->elpBrushStyle == BS_PATTERN)
{
bMonoBrush = MonoBitmap(hbmRemote);
if (bMonoBrush)
iUsage = DIB_PAL_INDICES;
else
iUsage = DIB_RGB_COLORS;
}
// Get the bitmap info header and sizes.
if (!bMetaGetDIBInfo(hdc, hbmRemote, &bmih,
&cbBitsInfo, &cbBits, (DWORD) iUsage, 0, FALSE))
break;
// Record DIB bitmap if possible.
pelp->elpBrushStyle = bMonoBrush
? BS_PATTERN
: BS_DIBPATTERNPT;
*(PDWORD) &pelp->elpColor = (DWORD) iUsage;
pelp->elpHatch = 0;
// fall through
default:
// Finally create the record (and get the bits).
PMREXTCREATEPEN pmrecp;
// Allocate dword aligned structure.
if (!(pmrecp = (PMREXTCREATEPEN) pmdc->pvNewRecord
(SIZEOF_MREXTCREATEPEN(cbelp,cbBitsInfo,cbBits))))
break;
if (!pmrecp->bInit
(
hdc,
imhe,
cbelp,
pelp,
hbmRemote,
bmih,
cbBitsInfo, // size of bitmap info
cbBits // size of bits buffer
)
)
break;
pmrecp->vCommit(pmdc);
ulRet = imhe;
break;
}
}
if (cbelp > sizeof(EXTLOGPEN))
if (LocalFree(pelp))
ASSERTGDI(FALSE, "MF_InternalCreateObject: LocalFree failed");
break;
// Do palette.
case LO_PALETTE_TYPE:
PMRCREATEPALETTE pmrcp;
USHORT cEntries;
if (GetObjectA(hobj, sizeof(USHORT), (LPVOID) &cEntries) != 2)
{
ASSERTGDI(FALSE, "MF_InternalCreateObject: GetObjectA failed");
break;
}
if (!(pmrcp = (PMRCREATEPALETTE) pmdc->pvNewRecord
(SIZEOF_MRCREATEPALETTE(cEntries))))
break;
// Also clear peFlags.
if (!pmrcp->bInit((HPALETTE) hobj, imhe, cEntries))
break;
// Also update the metafile palette.
if (!pmrcp->bCommit(pmdc))
break;
ulRet = imhe;
break;
// Do font.
case LO_FONT_TYPE:
PMREXTCREATEFONTINDIRECTW pmecfiw;
PLDC pldc;
pldc = GET_PLDC(hdc);
pldc->fl |= LDC_FONT_CHANGE;
if (!(pmecfiw = (PMREXTCREATEFONTINDIRECTW) pmdc->pvNewRecord
(SIZEOF_MREXTCREATEFONTINDIRECTW)))
break;
if (!pmecfiw->bInit((HFONT) hobj, imhe))
break;
pmecfiw->vCommit(pmdc);
ulRet = imhe;
break;
case LO_BITMAP_TYPE:
case LO_DIBSECTION_TYPE:
default:
ASSERTGDI(FALSE, "MF_InternalCreateObject: Bad object type\n");
break;
}
// Check for error.
if (ulRet == 0)
{
ERROR_ASSERT(FALSE,
"MF_InternalCreateObject: unable to record the object");
vFreeMHE(hdc, imhe);
return(ulRet);
}
ASSERTGDI(ulRet == imhe, "MF_InternalCreateObject: Bad return value");
// Update number of handles in the metafile header record.
pmdc->vUpdateNHandles(imhe);
// Return the metafile handle index of the object.
return(imhe);
}
// DeleteObject
extern "C" BOOL MF_DeleteObject(HANDLE h)
{
// We don't get called if it is a stock object.
HDC hdc;
METALINK metalink;
PUTS("MF_DeleteObject\n");
ASSERTGDI(pmetalink16Get(h) != NULL,
"MF_DeleteObject: No object to delete");
// Delete the object from each metafile DC which references it.
while (TRUE)
{
metalink.vInit(pmetalink16Get(h));
if (!metalink.bValid())
break;
hdc = hdcFromIhdc(metalink.ihdc);
#if DBG
ASSERTGDI(GET_PMDC(hdc)->pmhe[metalink.imhe].lhObject == h,
"MF_DeleteObject: Bad metalink");
ASSERTGDI(metalink.imhe != 0, // Index zero is reserved.
"MF_DeleteObject: Bad metalink");
#endif
// Send a delete object record.
(VOID) MF_SetD(hdc, (DWORD) metalink.imhe, EMR_DELETEOBJECT);
vFreeMHE(hdc, (ULONG) metalink.imhe);
}
return(TRUE);
}
// SetPaletteEntries
extern "C" BOOL MF_SetPaletteEntries
(
HPALETTE hpal,
UINT iStart,
UINT cEntries,
CONST PALETTEENTRY *pPalEntries
)
{
// We don't get called if it is a stock object.
PUTS("MF_SetPaletteEntries\n");
// Create a record in each metafile DC which references it.
// Note that if an object has been previously selected in a metafile DC
// and currently deselected, it is still referenced by the metafile DC.
for
(
METALINK metalink(pmetalink16Get(hpal));
metalink.bValid();
metalink.vNext()
)
{
// Get a metafile DC.
PMDC pmdc = GET_PMDC(hdcFromIhdc(metalink.ihdc));
PMRSETPALETTEENTRIES pmrspe;
ASSERTGDI(pmdc->pmhe[metalink.imhe].lhObject == hpal,
"MF_SetPaletteEntries: Bad metalink");
ASSERTGDI(metalink.imhe != 0, // Index zero is reserved.
"MF_SetPaletteEntries: Bad metalink");
// Send a SetPaletteEntries record.
if (!(pmrspe = (PMRSETPALETTEENTRIES) pmdc->pvNewRecord
(SIZEOF_MRSETPALETTEENTRIES(cEntries))))
return(FALSE);
// Also clear peFlags.
pmrspe->vInit(metalink.imhe, iStart, cEntries, pPalEntries);
// Also update the metafile palette.
if (!pmrspe->bCommit(pmdc))
return(FALSE);
}
return(TRUE);
}
// ResizePalette
extern "C" BOOL MF_ResizePalette(HPALETTE hpal,UINT c)
{
// We don't get called if it is a stock object.
PUTS("MF_ResizePalette\n");
// Create a record in each metafile DC which references it.
// Note that if an object has been previously selected in a metafile DC
// and currently deselected, it is still referenced by the metafile DC.
for
(
METALINK metalink(pmetalink16Get(hpal));
metalink.bValid();
metalink.vNext()
)
{
HDC hdc = hdcFromIhdc(metalink.ihdc);
ASSERTGDI(GET_PMDC(hdc)->pmhe[metalink.imhe].lhObject == hpal,
"MF_ResizePalette: Bad metalink");
ASSERTGDI(metalink.imhe != 0, // Index zero is reserved.
"MF_ResizePalette: Bad metalink");
// Send a ResizePalette record.
if
(
!MF_SetDD
(
hdc,
(DWORD)metalink.imhe,
(DWORD)c,
EMR_RESIZEPALETTE
)
)
return(FALSE);
}
return(TRUE);
}
// RealizePalette
//
// This function takes a hpal, not a hdc! We want to metafile RealizePalette
// calls in other DC which affect the metafile DCs as well. For example,
// if a palette is selected into a display DC and a metafile DC, a
// RealizePalette on the display DC will cause a record to be generated in
// the metafile DC. The reason is applications may expect this behavior
// in Windows although we do not completely agree with this. In any case,
// we do the right thing when they realize a palette on metafile DCs.
//
// Note that no record is generated if the stock palette is realized. This
// is compatible with the current design for palette management in metafiles.
extern "C" BOOL MF_RealizePalette(HPALETTE hpal)
{
// We don't get called if it is a stock object.
PUTS("MF_RealizePalette\n");
// Create a record in each metafile DC which selects it (NOT references it!).
// Note that if an object has been previously selected in a metafile DC
// and currently deselected, it is still referenced by the metafile DC.
for
(
METALINK metalink(pmetalink16Get(hpal));
metalink.bValid();
metalink.vNext()
)
{
HDC hdc = hdcFromIhdc(metalink.ihdc);
ASSERTGDI(GET_PMDC(hdc)->pmhe[metalink.imhe].lhObject == hpal,
"MF_RealizePalette: Bad metalink");
ASSERTGDI(metalink.imhe != 0, // Index zero is reserved.
"MF_RealizePalette: Bad metalink");
// Send a RealizePalette record.
if (GetDCObject(hdc,LO_PALETTE_TYPE) == (int) hpal)
if (!MF_Record(hdc,EMR_REALIZEPALETTE))
return(FALSE);
}
return(TRUE);
}
// EOF - emit an EOF metafile record.
// This function is called by CloseEnhMetaFile to emit the last metafile record.
// The EOF record includes the metafile palette if any logical palette is
// used in the metafile.
extern "C" BOOL MF_EOF(HDC hdc, ULONG cEntries, PPALETTEENTRY pPalEntries)
{
PMREOF pmreof;
DWORD cbEOF;
PLDC pldc;
DC_PLDC(hdc,pldc,FALSE);
PMDC pmdc = (PMDC)pldc->pvPMDC;
ASSERTGDI(pmdc,"no pmdc\n");
PUTS("MF_EOF\n");
cbEOF = SIZEOF_MREOF(cEntries);
if (!(pmreof = (PMREOF) pmdc->pvNewRecord(cbEOF)))
return(FALSE);
pmreof->vInit(cEntries, pPalEntries, cbEOF);
pmreof->vCommit(pmdc);
return(TRUE);
}
// GdiComment - emit a metafile comment record.
extern "C" BOOL MF_GdiComment(HDC hdc, UINT nSize, CONST BYTE *lpData)
{
PMRGDICOMMENT pmrc;
PLDC pldc;
DC_PLDC(hdc,pldc,FALSE);
PMDC pmdc = (PMDC)pldc->pvPMDC;
ASSERTGDI(pmdc,"no pmdc\n");
PUTS("MF_GdiComment\n");
// Ignore GDICOMMENT_WINDOWS_METAFILE and other non-embeddable public comments.
// These comments are now extra baggage.
if (nSize >= 2 * sizeof(DWORD)
&& ((UNALIGNED PDWORD) lpData)[0] == GDICOMMENT_IDENTIFIER
&& ((UNALIGNED PDWORD) lpData)[1] & GDICOMMENT_NOEMBED)
return(TRUE);
if (!(pmrc = (PMRGDICOMMENT) pmdc->pvNewRecord(SIZEOF_MRGDICOMMENT(nSize))))
return(FALSE);
// If it is a GDICOMMENT_MULTIFORMATS or other public comments containing
// logical bounds, we need to accumulate the bounds.
// We assume that applications set up metafile palette properly before
// embedding so we do not have to accumulate the metafile palette here.
// We do the bounds after pvNewRecord so that the previous bounds is
// accounted for properly.
if (nSize >= 2 * sizeof(DWORD)
&& ((UNALIGNED PDWORD) lpData)[0] == GDICOMMENT_IDENTIFIER
&& ((UNALIGNED PDWORD) lpData)[1] & GDICOMMENT_ACCUMBOUNDS)
{
POINT aptBounds[4];
RECT rcBounds;
// The logical output rectangle follows the ident and iComment fields.
CONST RECTL *prclOutput = (UNALIGNED PRECTL) &lpData[2 * sizeof(DWORD)];
aptBounds[0].x = prclOutput->left;
aptBounds[0].y = prclOutput->top;
aptBounds[1].x = prclOutput->right;
aptBounds[1].y = prclOutput->top;
aptBounds[2].x = prclOutput->right;
aptBounds[2].y = prclOutput->bottom;
aptBounds[3].x = prclOutput->left;
aptBounds[3].y = prclOutput->bottom;
if (!LPtoDP(hdc, aptBounds, 4))
return(FALSE);
rcBounds.left = MIN4(aptBounds[0].x,aptBounds[1].x,aptBounds[2].x,aptBounds[3].x);
rcBounds.right = MAX4(aptBounds[0].x,aptBounds[1].x,aptBounds[2].x,aptBounds[3].x);
rcBounds.top = MIN4(aptBounds[0].y,aptBounds[1].y,aptBounds[2].y,aptBounds[3].y);
rcBounds.bottom = MAX4(aptBounds[0].y,aptBounds[1].y,aptBounds[2].y,aptBounds[3].y);
(void) SetBoundsRectAlt(hdc, &rcBounds, (UINT) (DCB_WINDOWMGR | DCB_ACCUMULATE));
}
pmrc->vInit(nSize, lpData);
pmrc->vCommit(pmdc);
return(TRUE);
}
// Emit a metafile comment record for embedded windows metafile.
extern "C" BOOL MF_GdiCommentWindowsMetaFile(HDC hdc, UINT nSize, CONST BYTE *lpData)
{
PMRGDICOMMENT pmrc;
PLDC pldc;
DC_PLDC(hdc,pldc,FALSE);
PMDC pmdc = (PMDC)pldc->pvPMDC;
ASSERTGDI(pmdc,"no pmdc\n");
PUTS("MF_GdiCommentWindowsMetaFile\n");
if (!(pmrc = (PMRGDICOMMENT) pmdc->pvNewRecord(SIZEOF_MRGDICOMMENT_WINDOWS_METAFILE(nSize))))
return(FALSE);
pmrc->vInitWindowsMetaFile(nSize, lpData);
pmrc->vCommit(pmdc);
return(TRUE);
}
// Emit a metafile comment record for begin group. This is used to identify
// the beginning of an embedded enhanced metafile.
extern "C" BOOL MF_GdiCommentBeginGroupEMF(HDC hdc, PENHMETAHEADER pemfHeader)
{
PMRGDICOMMENT pmrc;
PLDC pldc;
DC_PLDC(hdc,pldc,FALSE);
PMDC pmdc = (PMDC)pldc->pvPMDC;
ASSERTGDI(pmdc,"no pmdc\n");
PUTS("MF_GdiCommentBeginGroupEMF\n");
if (!(pmrc = (PMRGDICOMMENT) pmdc->pvNewRecord(SIZEOF_MRGDICOMMENT_BEGINGROUP(pemfHeader->nDescription))))
return(FALSE);
pmrc->vInitBeginGroupEMF(pemfHeader);
pmrc->vCommit(pmdc);
return(TRUE);
}
// Emit a metafile comment record for end group. This is used to identify
// the end of an embedded enhanced metafile.
extern "C" BOOL MF_GdiCommentEndGroupEMF(HDC hdc)
{
DWORD ad[2];
PUTS("MF_GdiCommentEndGroupEMF\n");
ad[0] = GDICOMMENT_IDENTIFIER; // ident
ad[1] = GDICOMMENT_ENDGROUP; // iComment
return(MF_GdiComment(hdc, (UINT) sizeof(ad), (LPBYTE) &ad));
}
// MF_AnyBitBlt helper.
extern "C" BOOL MF_DoBitBlt
(
PMDC pmdcDst,
int xDst,
int yDst,
int cxDst,
int cyDst,
DWORD rop,
int xSrc = 0,
int ySrc = 0,
PXFORM pxformSrc = &xformIdentity,
COLORREF clrBkSrc = 0,
PBMIH pbmihSrc = (PBMIH) NULL,
HBITMAP hbmSrc = (HBITMAP) 0,
DWORD cbBitsInfoSrc = 0,
DWORD cbBitsSrc = 0
)
{
PMRBB pmrbb;
if (!(pmrbb = (PMRBB) pmdcDst->pvNewRecord
(SIZEOF_MRBB(cbBitsInfoSrc,cbBitsSrc))))
return(FALSE);
// Use compression option?!!!
if (!pmrbb->bInit
(
EMR_BITBLT,
pmdcDst, // pmdcDst
xDst, // xDst
yDst, // yDst
cxDst, // cxDst
cyDst, // cyDst
rop, // rop
xSrc, // xSrc
ySrc, // ySrc
pxformSrc, // source DC transform
clrBkSrc, // source DC BkColor
pbmihSrc, // source bitmap info header
hbmSrc, // source bitmap to save
hbmSrc ? sizeof(MRBB) : 0, // offset to bitmap info
cbBitsInfoSrc, // size of bitmap info
hbmSrc ? sizeof(MRBB) + cbBitsInfoSrc : 0,// offset to bits
cbBitsSrc // size of bits buffer
)
)
return(FALSE);
pmrbb->vCommit(pmdcDst);
return(TRUE);
}
// MF_AnyBitBlt helper.
extern "C" BOOL MF_DoStretchBlt
(
PMDC pmdcDst,
int xDst,
int yDst,
int cxDst,
int cyDst,
DWORD rop,
int xSrc,
int ySrc,
int cxSrc,
int cySrc,
PXFORM pxformSrc,
COLORREF clrBkSrc,
PBMIH pbmihSrc,
HBITMAP hbmSrc,
DWORD cbBitsInfoSrc,
DWORD cbBitsSrc
)
{
PMRSTRETCHBLT pmrsb;
// We always have a source bitmap here. StretchBlt without a source is
// recorded as BitBlt.
ASSERTGDI(hbmSrc != (HBITMAP) 0, "MF_DoStretchBlt: Bad hbmSrc");
if (!(pmrsb = (PMRSTRETCHBLT) pmdcDst->pvNewRecord
(SIZEOF_MRSTRETCHBLT(cbBitsInfoSrc,cbBitsSrc))))
return(FALSE);
// Use compression option?!!!
if (!pmrsb->bInit
(
pmdcDst, // pmdcDst
xDst, // xDst
yDst, // yDst
cxDst, // cxDst
cyDst, // cyDst
rop, // rop
xSrc, // xSrc
ySrc, // ySrc
cxSrc, // cxSrc
cySrc, // cySrc
pxformSrc, // source DC transform
clrBkSrc, // source DC BkColor
pbmihSrc, // source bitmap info header
hbmSrc, // source bitmap to save
sizeof(MRSTRETCHBLT),// offset to bitmap info
cbBitsInfoSrc, // size of bitmap info
sizeof(MRSTRETCHBLT) + cbBitsInfoSrc,// offset to bits
cbBitsSrc // size of bits buffer
)
)
return(FALSE);
pmrsb->vCommit(pmdcDst);
return(TRUE);
}
// MF_AnyBitBlt helper.
extern "C" BOOL MF_DoMaskBlt
(
PMDC pmdcDst,
int xDst,
int yDst,
int cxDst,
int cyDst,
DWORD rop3,
PBMIH pbmihMask,
HBITMAP hbmMask,
DWORD cbBitsInfoMask,
DWORD cbBitsMask,
int xMask,
int yMask,
int xSrc,
int ySrc,
PXFORM pxformSrc,
COLORREF clrBkSrc = 0,
PBMIH pbmihSrc = (PBMIH) NULL,
HBITMAP hbmSrc = (HBITMAP) 0,
DWORD cbBitsInfoSrc = 0,
DWORD cbBitsSrc = 0
)
{
PMRMASKBLT pmrmb;
DWORD offBase = sizeof(MRMASKBLT);
DWORD offBitsInfoSrc = 0;
DWORD offBitsSrc = 0;
DWORD offBitsInfoMask = 0;
DWORD offBitsMask = 0;
if (hbmSrc)
{
offBitsInfoSrc = offBase;
offBitsSrc = offBitsInfoSrc + cbBitsInfoSrc;
offBase = offBitsSrc + cbBitsSrc;
}
if (hbmMask)
{
offBitsInfoMask = offBase;
offBitsMask = offBitsInfoMask + cbBitsInfoMask;
}
// Now create the record.
if (!(pmrmb = (PMRMASKBLT) pmdcDst->pvNewRecord
(SIZEOF_MRMASKBLT(cbBitsInfoSrc,cbBitsSrc,cbBitsInfoMask,cbBitsMask))))
return(FALSE);
// Use compression option?!!!
if (!pmrmb->bInit
(
pmdcDst, // pmdcDst
xDst, // xDst
yDst, // yDst
cxDst, // cxDst
cyDst, // cyDst
rop3, // rop3
xSrc, // xSrc
ySrc, // ySrc
pxformSrc, // source DC transform
clrBkSrc, // source DC BkColor
pbmihSrc, // source bitmap info header
hbmSrc, // source bitmap to save
offBitsInfoSrc, // offset to bitmap info
cbBitsInfoSrc, // size of bitmap info
offBitsSrc, // offset to bits
cbBitsSrc, // size of bits buffer
xMask, // xMask
yMask, // yMask
pbmihMask, // mask bitmap info header
hbmMask, // mask bitmap
offBitsInfoMask, // offset to mask bitmap info
cbBitsInfoMask, // size of mask bitmap info
offBitsMask, // offset to mask bits
cbBitsMask // size of mask bits buffer
)
)
return(FALSE);
pmrmb->vCommit(pmdcDst);
return(TRUE);
}
// MF_AnyBitBlt helper.
extern "C" BOOL MF_DoPlgBlt
(
PMDC pmdcDst,
CONST POINT *pptDst,
PBMIH pbmihMask,
HBITMAP hbmMask,
DWORD cbBitsInfoMask,
DWORD cbBitsMask,
int xMask,
int yMask,
int xSrc,
int ySrc,
int cxSrc,
int cySrc,
PXFORM pxformSrc,
COLORREF clrBkSrc,
PBMIH pbmihSrc,
HBITMAP hbmSrc,
DWORD cbBitsInfoSrc,
DWORD cbBitsSrc
)
{
PMRPLGBLT pmrpb;
// We always have a source bitmap here. Destination to destination PlgBlt
// is not allowed.
ASSERTGDI(hbmSrc != (HBITMAP) 0, "MF_DoPlgBlt: Bad hbmSrc");
// Now create the record.
if (!(pmrpb = (PMRPLGBLT) pmdcDst->pvNewRecord
(SIZEOF_MRPLGBLT(cbBitsInfoSrc,cbBitsSrc,cbBitsInfoMask,cbBitsMask))))
return(FALSE);
// Use compression option?!!!
if (!pmrpb->bInit
(
pmdcDst, // pmdcDst
pptDst, // pptDst
xSrc, // xSrc
ySrc, // ySrc
cxSrc, // cxSrc
cySrc, // cySrc
pxformSrc, // source DC transform
clrBkSrc, // source DC BkColor
pbmihSrc, // source bitmap info header
hbmSrc, // source bitmap to save
sizeof(MRPLGBLT), // offset to bitmap info
cbBitsInfoSrc, // size of bitmap info
sizeof(MRPLGBLT) + cbBitsInfoSrc,// offset to bits
cbBitsSrc, // size of bits buffer
xMask, // xMask
yMask, // yMask
pbmihMask, // mask bitmap info header
hbmMask, // mask bitmap
hbmMask // offset to mask bitmap info
? sizeof(MRPLGBLT) + cbBitsInfoSrc + cbBitsSrc
: 0,
cbBitsInfoMask, // size of mask bitmap info
hbmMask // offset to mask bits
? sizeof(MRPLGBLT) + cbBitsInfoSrc + cbBitsSrc + cbBitsInfoMask
: 0,
cbBitsMask // size of mask bits buffer
)
)
return(FALSE);
pmrpb->vCommit(pmdcDst);
return(TRUE);
}
// bMetaGetDIBInfo
//
// Gets the bitmap info header and sizes.
//
// If hbm or hbmRemote is given, it queries the bitmap info header and
// fills in the BITMAPINFOHERADER structure at pBmih. A hdc is required
// if iUsage is DIB_PAL_COLORS.
//
// If no hbm or hbmRemote is given, it assumes that it is called by
// SetDIBitsToDevice or StretchDIBits and pBmih already points to a
// bitmap info header (BITMAPINFOHEADER) or core header (BITMAPCOREHEADER).
//
// In any case, the size for bitmap info (BITMAPINFO) with color table
// and the size for the bitmap bits is returned in pcbBmi and pcbBits
// respectively. We do not store BITMAPCOREINFO structure in the metafiles.
//
// If cScans is non zero, only the size for the bitmap bits of this many
// scans is given. The callers in this case are SetDIBitsToDevice or
// StretchDIBits.
//
// This function is called in many places and any modifications have to
// be verified carefully! It should be kept current with the
// cjBitmapSize and cjBitmapBitsSize functions.
//
// Returns TRUE if successful, FALSE otherwise.
BOOL bMetaGetDIBInfo
(
HDC hdc,
HBITMAP hbm,
PBMIH pBmih,
PDWORD pcbBmi,
PDWORD pcbBits,
DWORD iUsage,
LONG cScans,
BOOL bMeta16
)
{
DWORD cjClr;
DWORD cbBmi;
DWORD cbBits;
PUTS("bMetaGetDIBInfo\n");
// If hbm is given, we need to get the bitmap info header.
// Otherwise, pBmih already has the bitmap info header.
if (hbm)
{
pBmih->biSize = sizeof(BMIH);
pBmih->biBitCount = 0; // don't fill in color table
pBmih->biCompression = BI_RGB;
if (!GetDIBits(hdc, hbm, 0, 0, (LPBYTE) NULL,
(LPBITMAPINFO) pBmih, (UINT) iUsage))
{
ASSERTGDI(FALSE, "bMetaGetDIBInfo: InternalGetDIBits failed");
return(FALSE);
}
// Windows always zeros the clrUsed and clrImportant fields.
// 16-bit metafiles also do not support 16/32bpp bitmaps.
if (bMeta16)
{
pBmih->biClrUsed = 0;
pBmih->biClrImportant = 0;
if (pBmih->biPlanes != 1
|| pBmih->biBitCount == 16 || pBmih->biBitCount == 32)
{
pBmih->biPlanes = 1;
pBmih->biBitCount = 24;
pBmih->biCompression = BI_RGB;
pBmih->biSizeImage = 0;
iUsage = DIB_RGB_COLORS;
}
}
}
// Compute size of a color entry.
switch (iUsage)
{
case DIB_RGB_COLORS:
cjClr = sizeof(RGBQUAD);
break;
case DIB_PAL_COLORS:
cjClr = sizeof(WORD);
ASSERTGDI(sizeof(WORD) == 2, "bMetaGetDIBInfo: Bad size");
break;
case DIB_PAL_INDICES:
cjClr = 0;
break;
default:
ASSERTGDI(FALSE, "bMetaGetDIBInfo: Bad iUsage");
return(FALSE);
}
// Compute size of the bitmap info (with color table) and bitmap bits buffer.
// We will store only BITMAPINFO in the record only. The BITMAPCOREINFO
// structure will be stored as BITMAPINFO in the metafile.
if (pBmih->biSize > sizeof(BMIH))
{
cbBmi = pBmih->biSize;
}
else
{
cbBmi = sizeof(BMIH);
}
if (pBmih->biSize == sizeof(BMCH))
{
if (((LPBMCH) pBmih)->bcBitCount == 16 || ((LPBMCH) pBmih)->bcBitCount == 32)
{
ASSERTGDI(FALSE, "bMetaGetDIBInfo: 16/32bpp bitmap not allowed in core bitmap info");
return(FALSE);
}
if (((LPBMCH) pBmih)->bcBitCount < 16)
cbBmi += (1 << ((LPBMCH) pBmih)->bcBitCount) * cjClr;
cbBits = CJSCAN(((LPBMCH) pBmih)->bcWidth,
((LPBMCH) pBmih)->bcPlanes,
((LPBMCH) pBmih)->bcBitCount)
* (cScans ? cScans : (DWORD) ((LPBMCH) pBmih)->bcHeight);
}
else
{
if (pBmih->biBitCount == 16 || pBmih->biBitCount == 32)
{
if (pBmih->biCompression == BI_BITFIELDS)
cbBmi += 3 * sizeof(DWORD);
}
else if (pBmih->biBitCount == 24)
{
// BI_BITFIELDS not allowed
}
else if (pBmih->biClrUsed)
cbBmi += pBmih->biClrUsed * cjClr;
else if (pBmih->biBitCount < 16)
cbBmi += (1 << pBmih->biBitCount) * cjClr;
// compute cbBits. We first do the computation and then use biSizeImage
// if it is smaller than cbBits.
cbBits = CJSCAN(pBmih->biWidth, pBmih->biPlanes, pBmih->biBitCount)
* (cScans ? cScans : ABS(pBmih->biHeight));
if (pBmih->biSizeImage && (pBmih->biSizeImage < cbBits))
cbBits = pBmih->biSizeImage;
}
*pcbBmi = cbBmi;
*pcbBits = cbBits;
return(TRUE);
}
// BitBlt
// PatBlt
// StretchBlt
// MaskBlt
// PlgBlt
extern "C" BOOL MF_AnyBitBlt
(
HDC hdcDst,
int xDst,
int yDst,
int cxDst,
int cyDst,
CONST POINT *pptDst,
HDC hdcSrc,
int xSrc,
int ySrc,
int cxSrc,
int cySrc,
HBITMAP hbmMask,
int xMask,
int yMask,
DWORD rop, // For MaskBlt, this is rop3!
// For PlgBlt, this must be 0xCCAA0000!
DWORD mrType
)
{
DWORD cbBitsInfoMask = 0;
DWORD cbBitsMask = 0;
BMIH bmihMask;
PBMIH pbmihMask = (PBMIH) NULL;
XFORM xformSrc;
PLDC pldc;
DC_PLDC(hdcDst,pldc,FALSE);
PMDC pmdcDst = (PMDC)pldc->pvPMDC;
ASSERTGDI(pmdcDst,"no pmdc\n");
PUTS("MF_AnyBitBlt\n");
ASSERTGDI(mrType == EMR_BITBLT
|| mrType == EMR_STRETCHBLT
|| mrType == EMR_MASKBLT
|| mrType == EMR_PLGBLT,
"MF_AnyBitBlt: Bad mrType");
// Do mask first.
if (hbmMask)
{
// Get the mask's bitmap info header and sizes.
pbmihMask = &bmihMask;
if (!bMetaGetDIBInfo(hdcDst, hbmMask, &bmihMask,
&cbBitsInfoMask, &cbBitsMask, DIB_PAL_INDICES, 0, FALSE))
return(FALSE);
// Make sure that it is monochrome.
if (bmihMask.biPlanes != 1 && bmihMask.biBitCount != 1)
return(FALSE);
}
// These two checks are needed to make sure that the following rop test works.
if ((mrType == EMR_BITBLT || mrType == EMR_STRETCHBLT)
&& (rop & 0xff000000) != 0)
{
WARNING("MF_AnyBitBlt: Bad BitBlt/StretchBlt rop");
return(FALSE);
}
ASSERTGDI(mrType != EMR_PLGBLT || rop == 0xCCAA0000,
"MF_AnyBitBlt: Bad PlgBlt rop");
// Get the source transform if a source is required by the rop.
// For MaskBlt, we always need the source transform.
if (ISSOURCEINROP3(rop) || mrType == EMR_MASKBLT)
{
// Get source transform.
if (!GetTransform(hdcSrc, XFORM_WORLD_TO_DEVICE, &xformSrc))
return(FALSE);
// Make sure that it is a scale.
if (xformSrc.eM12 != 0.0f || xformSrc.eM21 != 0.0f)
return(FALSE);
}
// Do blts with a source. The source must allow bit query operation.
if (ISSOURCEINROP3(rop))
{
COLORREF clrBkSrc;
BOOL bRet = FALSE; // assume failure
// We need to record the source bitmap. The source DC must be a memory
// DC or a direct DC that allows bits to be retrieved. As a result, the
// source DC cannot be an enhanced metafile DC. That is, destination
// to destination blts are not allowed in an enhanced metafile!
if (IS_ALTDC_TYPE(hdcSrc))
{
PLDC pldcSrc;
DC_PLDC(hdcSrc,pldcSrc,FALSE);
if (pldcSrc->iType == LO_METADC)
return(FALSE);
}
// Get source bk color.
if ((clrBkSrc = GetNearestColor(hdcSrc, GetBkColor(hdcSrc)))
== CLR_INVALID)
{
return(FALSE);
}
// Compute the area of the source bitmap to save in the metafile.
// First we find the coordinates of the source rectange in the
// device/bitmap units. Then we expand the rectangle by one pixel
// unit to account for possible rounding errors. Finally we map
// the rectangle to the playback bitmap origin by modifying the
// translation elements in the source transform.
// Verify pdev?!!!
LONG lWidthSrc, lHeightSrc;
RECTL rclSrc;
RECTL rclBitmap;
DWORD cbBitsInfoCompat;
DWORD cbBitsCompat;
HBITMAP hbmTmp = 0;
HBITMAP hbmCompat = 0;
HDC hdcCompat = 0;
int iSaveState = 0;
BMIH bmihCompat;
// Get source rectangle in device/bitmap coordinates. Since the
// source transform is a scale, we can simply convert the endpoints
// of the source rectangle.
ASSERTGDI((mrType != EMR_BITBLT && mrType != EMR_MASKBLT)
|| (cxDst == cxSrc && cyDst == cySrc),
"MF_AnyBitBlt: Bad width and height in BitBlt/MaskBlt");
ASSERTGDI(sizeof(RECTL) == sizeof(POINT)*2, "MF_AnyBitBlt: Bad size");
((PERECTL) &rclSrc)->vInit(xSrc, ySrc, xSrc + cxSrc, ySrc + cySrc);
if (!LPtoDP(hdcSrc, (LPPOINT) &rclSrc, 2))
return(FALSE);
// Order the result. We assume it to be inclusive-inclusive.
((PERECTL) &rclSrc)->vOrder();
// Expand it by one pixel.
rclSrc.left--;
rclSrc.top--;
rclSrc.right++;
rclSrc.bottom++;
// Map it to the playback bitmap origin.
xformSrc.eDx -= (FLOAT) rclSrc.left;
xformSrc.eDy -= (FLOAT) rclSrc.top;
// We now have the rectangle which defines the size of the playback
// bitmap. But we still need to clip it to the source device/bitmap
// limits. This is done by reducing the size of the rectangle and
// translating its origin.
((PERECTL) &rclBitmap)->vInit
(0, 0, rclSrc.right - rclSrc.left, rclSrc.bottom - rclSrc.top);
// Get source width and height
// BUGBUG - if it is a direct DC, we really want to fall through to the
// second case. Will either the GetDCObject or GetObject fail?
HBITMAP hbm = (HBITMAP)GetDCObject(hdcSrc, LO_BITMAP_TYPE);
BITMAP bmSrc;
if (hbm && GetObjectA((HANDLE)hbm,sizeof(BITMAP),(LPVOID) &bmSrc))
{
lWidthSrc = bmSrc.bmWidth;
lHeightSrc = bmSrc.bmHeight;
}
else
{
lWidthSrc = GetDeviceCaps(hdcDst, DESKTOPHORZRES);
lHeightSrc = GetDeviceCaps(hdcDst, DESKTOPVERTRES);
}
// Clip the source rectangle to the source device/bitmap limits.
// Adjust the playback bitmap size and source transform at the
// same time.
if (rclSrc.left < 0) // Shift and clip the left edge.
{
rclBitmap.right += rclSrc.left;
xformSrc.eDx += (FLOAT) rclSrc.left;
rclSrc.left = 0;
}
if (rclSrc.right >= lWidthSrc) // Clip the right edge.
{
rclBitmap.right -= (rclSrc.right - lWidthSrc + 1);
rclSrc.right -= (rclSrc.right - lWidthSrc + 1);
}
if (rclSrc.top < 0) // Shift and clip the top edge.
{
rclBitmap.bottom += rclSrc.top;
xformSrc.eDy += (FLOAT) rclSrc.top;
rclSrc.top = 0;
}
if (rclSrc.bottom >= lHeightSrc) // Clip the bottom edge.
{
rclBitmap.bottom -= (rclSrc.bottom - lHeightSrc + 1);
rclSrc.bottom -= (rclSrc.bottom - lHeightSrc + 1);
}
// If the rectangle is completely clipped, there is no playback
// bitmap and nothing to blt.
if (rclBitmap.right < 0 || rclBitmap.bottom < 0)
return(TRUE);
// We now have the size of the playback bitmap. We will create a bitmap
// compatible to the source, copy the bits to the compatible bitmap
// and finally retrieve and store the bits in the metafile record.
// Create a compatible DC.
if (!(hdcCompat = CreateCompatibleDC(hdcSrc)))
goto mfbb_src_exit;
// Create a compatible bitmap.
if (!(hbmCompat = CreateCompatibleBitmap
(
hdcSrc,
(int) rclBitmap.right + 1,
(int) rclBitmap.bottom + 1
)
)
)
goto mfbb_src_exit;
// Select the bitmap.
if (!(hbmTmp = (HBITMAP)SelectObject(hdcCompat, (HANDLE)hbmCompat)))
goto mfbb_src_exit;
// Set up the source DC to have the same identity transform as the
// compatible DC so that the following bitblt call will not scale.
if (!(iSaveState = SaveDC(hdcSrc)))
goto mfbb_src_exit;
// Must be in the advanced graphics mode to modify the world transform.
SetGraphicsMode(hdcSrc, GM_ADVANCED);
if (!SetMapMode(hdcSrc, MM_TEXT)
|| !ModifyWorldTransform(hdcSrc, (LPXFORM) NULL, MWT_IDENTITY)
|| !SetWindowOrgEx(hdcSrc, 0, 0, (LPPOINT) NULL)
|| !SetViewportOrgEx(hdcSrc, 0, 0, (LPPOINT) NULL))
goto mfbb_src_exit;
// Copy the source bits into the compatible bitmap.
if (!BitBlt(hdcCompat, // Dest dc
0, // Dest x
0, // Dest y
(int) rclBitmap.right + 1, // Width
(int) rclBitmap.bottom + 1, // Height
hdcSrc, // Src dc
(int) rclSrc.left, // Src x
(int) rclSrc.top, // Src y
SRCCOPY)) // Rop
goto mfbb_src_exit;
// Retrieve the bitmap info header.
SelectObject(hdcCompat, hbmTmp);
hbmTmp = 0; // don't deselect it again later.
// Get the bitmap info header and sizes.
if (!bMetaGetDIBInfo(hdcCompat, hbmCompat, &bmihCompat,
&cbBitsInfoCompat, &cbBitsCompat, DIB_RGB_COLORS, 0, FALSE))
goto mfbb_src_exit;
// Finally create the record and get the bits.
switch (mrType)
{
case EMR_BITBLT:
bRet = MF_DoBitBlt
(
pmdcDst, // pmdcDst
xDst, // xDst
yDst, // yDst
cxDst, // cxDst
cyDst, // cyDst
rop, // rop
xSrc, // xSrc
ySrc, // ySrc
&xformSrc, // source DC transform
clrBkSrc, // source DC BkColor
&bmihCompat, // source bitmap info header
hbmCompat, // source bitmap to save
cbBitsInfoCompat, // size of bitmap info
cbBitsCompat // size of bits buffer
);
break;
case EMR_STRETCHBLT:
bRet = MF_DoStretchBlt
(
pmdcDst, // pmdcDst
xDst, // xDst
yDst, // yDst
cxDst, // cxDst
cyDst, // cyDst
rop, // rop
xSrc, // xSrc
ySrc, // ySrc
cxSrc, // cxSrc
cySrc, // cySrc
&xformSrc, // source DC transform
clrBkSrc, // source DC BkColor
&bmihCompat, // source bitmap info header
hbmCompat, // source bitmap to save
cbBitsInfoCompat, // size of bitmap info
cbBitsCompat // size of bits buffer
);
break;
case EMR_MASKBLT:
bRet = MF_DoMaskBlt
(
pmdcDst, // pmdcDst
xDst, // xDst
yDst, // yDst
cxDst, // cxDst
cyDst, // cyDst
rop, // rop
pbmihMask, // mask bitmap info header
hbmMask, // hbmMask
cbBitsInfoMask, // size of mask bitmap info
cbBitsMask, // size of mask bits buffer
xMask, // xMask
yMask, // yMask
xSrc, // xSrc
ySrc, // ySrc
&xformSrc, // source DC transform
clrBkSrc, // source DC BkColor
&bmihCompat, // source bitmap info header
hbmCompat, // source bitmap to save
cbBitsInfoCompat, // size of bitmap info
cbBitsCompat // size of bits buffer
);
break;
case EMR_PLGBLT:
bRet = MF_DoPlgBlt
(
pmdcDst, // pmdcDst
pptDst, // pptDst
pbmihMask, // mask bitmap info header
hbmMask, // hbmMask
cbBitsInfoMask, // size of mask bitmap info
cbBitsMask, // size of mask bits buffer
xMask, // xMask
yMask, // yMask
xSrc, // xSrc
ySrc, // ySrc
cxSrc, // cxSrc
cySrc, // cySrc
&xformSrc, // source DC transform
clrBkSrc, // source DC BkColor
&bmihCompat, // source bitmap info header
hbmCompat, // source bitmap to save
cbBitsInfoCompat, // size of bitmap info
cbBitsCompat // size of bits buffer
);
break;
}
mfbb_src_exit:
// Clean up and go home.
if (iSaveState)
if (!RestoreDC(hdcSrc, -1))
ASSERTGDI(FALSE, "MF_AnyBitBlt: RestoreDC failed");
if (hbmTmp)
if (!SelectObject(hdcCompat, hbmTmp))
ASSERTGDI(FALSE, "MF_AnyBitBlt: SelectObject failed");
if (hbmCompat)
if (!DeleteObject(hbmCompat))
ASSERTGDI(FALSE, "MF_AnyBitBlt: DeleteObject failed");
if (hdcCompat)
if (!DeleteDC(hdcCompat))
ASSERTGDI(FALSE, "MF_AnyBitBlt: DeleteDC failed");
return(bRet);
}
// It requires no source DC.
switch (mrType)
{
// StretchBlt is just a BitBlt here.
case EMR_BITBLT:
case EMR_STRETCHBLT:
return
(
MF_DoBitBlt
(
pmdcDst,
xDst,
yDst,
cxDst,
cyDst,
rop
)
);
case EMR_MASKBLT:
return
(
MF_DoMaskBlt
(
pmdcDst,
xDst,
yDst,
cxDst,
cyDst,
rop,
pbmihMask,
hbmMask,
cbBitsInfoMask,
cbBitsMask,
xMask,
yMask,
xSrc,
ySrc,
&xformSrc
)
);
// PlgBlt requires a source.
case EMR_PLGBLT:
ASSERTGDI(FALSE, "MF_AnyBitBlt: Source needed in PlgBlt");
return(FALSE);
}
return FALSE;
}
// SetDIBitsToDevice (for both 16- and 32-bit metafiles)
// StretchDIBits (for both 16- and 32-bit metafiles)
extern "C" BOOL MF_AnyDIBits
(
HDC hdcDst,
int xDst,
int yDst,
int cxDst,
int cyDst,
int xDib,
int yDib,
int cxDib,
int cyDib,
DWORD iStartScan,
DWORD cScans,
CONST VOID * pBitsDib,
CONST BITMAPINFO *pBitsInfoDib,
DWORD iUsageDib,
DWORD rop,
DWORD mrType
)
{
DWORD cbBitsInfoDib = 0;
DWORD cbBitsDib = 0;
PUTS("MF_AnyDIBits\n");
ASSERTGDI(mrType == EMR_SETDIBITSTODEVICE || mrType == EMR_STRETCHDIBITS
|| mrType == META_SETDIBTODEV || mrType == META_STRETCHDIB,
"MF_AnyDIBits: Bad mrType");
// These two checks are needed to make sure that the following rop test works.
if ((rop & 0xff000000) != 0)
{
WARNING("MF_AnyDIBits: Bad rop");
return(FALSE);
}
ASSERTGDI(mrType == EMR_STRETCHDIBITS || mrType == META_STRETCHDIB
|| rop == SRCCOPY,
"MF_AnyDIBits: Bad rop");
if (ISSOURCEINROP3(rop))
{
// Get the bitmap sizes.
// We will store only BITMAPINFO in the record only. The
// BITMAPCOREINFO structure will be converted and stored as
// BITMAPINFO in the metafile.
// If it is a SetDIBitsToDevice, cScans cannot be zero.
// If it is a StretchDIBits, cScans must be zero.
if (mrType == EMR_SETDIBITSTODEVICE || mrType == META_SETDIBTODEV)
if (!cScans)
return(FALSE);
if (mrType == EMR_STRETCHDIBITS || mrType == META_STRETCHDIB)
{
ASSERTGDI(cScans == 0, "MF_AnyDIBits: cScans must be zero");
}
if (!bMetaGetDIBInfo(hdcDst, (HBITMAP) 0, (PBMIH) pBitsInfoDib,
&cbBitsInfoDib, &cbBitsDib, iUsageDib, cScans, FALSE))
return(FALSE);
}
switch (mrType)
{
case EMR_SETDIBITSTODEVICE:
{
PMRSETDIBITSTODEVICE pmrsdb;
PLDC pldc;
DC_PLDC(hdcDst,pldc,FALSE);
PMDC pmdcDst = (PMDC)pldc->pvPMDC;
ASSERTGDI(pmdcDst,"no pmdc\n");
if (!(pmrsdb = (PMRSETDIBITSTODEVICE) pmdcDst->pvNewRecord
(SIZEOF_MRSETDIBITSTODEVICE(cbBitsInfoDib,cbBitsDib))))
return(FALSE);
pmrsdb->vInit
(
pmdcDst, // pmdcDst
(LONG) xDst, // xDst
(LONG) yDst, // yDst
(LONG) xDib, // xDib
(LONG) yDib, // yDib
(DWORD) cxDib, // cxDib
(DWORD) cyDib, // cyDib
iStartScan, // iStartScan
cScans, // cScans
cbBitsDib, // size of bits buffer
pBitsDib, // dib bits
cbBitsInfoDib, // size of bitmap info
pBitsInfoDib, // dib info
iUsageDib // dib info usage
);
pmrsdb->vCommit(pmdcDst);
}
break;
case EMR_STRETCHDIBITS:
{
PMRSTRETCHDIBITS pmrstrdb;
PLDC pldc;
DC_PLDC(hdcDst,pldc,FALSE);
PMDC pmdcDst = (PMDC)pldc->pvPMDC;
ASSERTGDI(pmdcDst,"no pmdc\n");
if (!(pmrstrdb = (PMRSTRETCHDIBITS) pmdcDst->pvNewRecord
(SIZEOF_MRSTRETCHDIBITS(cbBitsInfoDib,cbBitsDib))))
return(FALSE);
pmrstrdb->vInit
(
pmdcDst, // pmdcDst
(LONG) xDst, // xDst
(LONG) yDst, // yDst
(LONG) cxDst, // cxDst
(LONG) cyDst, // cyDst
(LONG) xDib, // xDib
(LONG) yDib, // yDib
(LONG) cxDib, // cxDib
(LONG) cyDib, // cyDib
cbBitsDib, // size of bits buffer
pBitsDib, // dib bits
cbBitsInfoDib, // size of bitmap info
pBitsInfoDib, // dib info
iUsageDib, // dib info usage
rop // rop
);
pmrstrdb->vCommit(pmdcDst);
}
break;
case META_SETDIBTODEV:
case META_STRETCHDIB:
{
// Do not handle DIB_PAL_INDICES because there is no palette
// information available.
if (cbBitsInfoDib != 0 && iUsageDib == DIB_PAL_INDICES)
return(FALSE);
// Convert new bitmap formats to win3 bitmap formats
if (cbBitsInfoDib != 0
&& (pBitsInfoDib->bmiHeader.biSize == sizeof(BMIH))
&& (pBitsInfoDib->bmiHeader.biPlanes != 1
||pBitsInfoDib->bmiHeader.biBitCount == 16
||pBitsInfoDib->bmiHeader.biBitCount == 32))
{
BOOL b = FALSE;
HDC hdc = (HDC) 0;
HBITMAP hbm = (HBITMAP) 0;
PBYTE pBits24 = (PBYTE) NULL;
DWORD cbBits24;
BMIH bmih;
if (iUsageDib == DIB_PAL_COLORS)
return(FALSE); // illegal usage
hdc = CreateCompatibleDC((HDC) 0);
if (!(hbm = CreateDIBitmap(hdc,
(LPBITMAPINFOHEADER) pBitsInfoDib,
CBM_CREATEDIB, (LPBYTE) NULL, pBitsInfoDib, DIB_RGB_COLORS)))
goto error_exit;
if (!SetDIBits(hdc, hbm,
cScans ? (UINT) iStartScan : 0,
cScans ? (UINT) cScans : (UINT) pBitsInfoDib->bmiHeader.biHeight,
(CONST VOID *) pBitsDib, pBitsInfoDib, (UINT) iUsageDib))
goto error_exit;
bmih = *(PBITMAPINFOHEADER) pBitsInfoDib;
bmih.biPlanes = 1;
bmih.biBitCount = 24;
bmih.biCompression = BI_RGB;
bmih.biSizeImage = 0;
bmih.biClrUsed = 0;
bmih.biClrImportant = 0;
cbBits24 = CJSCAN(bmih.biWidth,bmih.biPlanes,bmih.biBitCount)
* (cScans ? cScans : ABS(bmih.biHeight));
pBits24 = (LPBYTE) LocalAlloc(LMEM_FIXED, (UINT) cbBits24);
if (pBits24 == (LPBYTE) NULL)
goto error_exit;
// Get bitmap info and bits in 24bpp.
if (!GetDIBits(hdc,
hbm,
cScans ? (UINT) iStartScan : 0,
cScans ? (UINT) cScans : (UINT) bmih.biHeight,
(LPVOID) pBits24,
(LPBITMAPINFO) &bmih,
DIB_RGB_COLORS))
goto error_exit;
b = MF16_RecordDIBits
(
hdcDst,
xDst,
yDst,
cxDst,
cyDst,
xDib,
yDib,
cxDib,
cyDib,
iStartScan,
cScans,
cbBits24,
pBits24,
sizeof(bmih),
(LPBMI) &bmih,
DIB_RGB_COLORS,
rop,
mrType
);
error_exit:
if (hdc)
DeleteDC(hdc);
if (hbm)
DeleteObject(hbm);
if (pBits24)
LocalFree((HANDLE) pBits24);
return(b);
}
else
{
return
(
MF16_RecordDIBits
(
hdcDst,
xDst,
yDst,
cxDst,
cyDst,
xDib,
yDib,
cxDib,
cyDib,
iStartScan,
cScans,
cbBitsDib,
pBitsDib,
cbBitsInfoDib,
pBitsInfoDib,
iUsageDib,
rop,
mrType
)
);
}
}
}
return(TRUE);
}
// SetFontXform
// This function is called only by the metafile playback code.
// If hdc is an enhanced metafile DC, we need to remember the scales
// so that we can metafile it in the compatible ExtTextOut or PolyTextOut
// record that follows.
extern "C" BOOL MF_SetFontXform(HDC hdc,FLOAT exScale,FLOAT eyScale)
{
PLDC pldc;
DC_PLDC(hdc,pldc,FALSE);
PMDC pmdc = (PMDC)pldc->pvPMDC;
ASSERTGDI(pmdc,"no pmdc\n");
pmdc->exFontScale(exScale);
pmdc->eyFontScale(eyScale);
return(TRUE);
}
// TextOutA
// TextOutW
// ExtTextOutA
// ExtTextOutW
extern "C" BOOL MF_ExtTextOut(
HDC hdc
, int x
, int y
, UINT fl
, CONST RECT *prcl
, LPCSTR psz
, int c
, CONST INT *pdx
, DWORD mrType
)
{
#define BUFCOUNT 256
WCHAR awc[BUFCOUNT];
WCHAR *pwsz;
PLDC pldc;
int bAlloc = 0;
BOOL bRet = TRUE;
DWORD dwCP;
INT pDxCaptureBuffer[BUFCOUNT];
INT cSave;
DC_PLDC(hdc,pldc,FALSE);
PMDC pmdc = (PMDC)pldc->pvPMDC;
ASSERTGDI(pmdc,"no pmdc\n");
PUTS("MF_ExtTextOut\n");
pldc = GET_PLDC( hdc );
if( ( pldc->fl & LDC_FONT_CHANGE ) &&
(( pldc->fl & LDC_DOWNLOAD_FONTS ) ||
( pldc->fl & LDC_FORCE_MAPPING )) )
{
bDoFontChange( hdc );
pldc->fl &= ~LDC_FONT_CHANGE;
}
switch (mrType)
{
case EMR_EXTTEXTOUTW:
pwsz = (WCHAR*) psz;
break;
case EMR_EXTTEXTOUTA:
if (c < BUFCOUNT)
{
// if the multi byte string is small enough then use
// the buffer on the frame
pwsz = awc;
}
else
{
if (!(pwsz = (WCHAR*) LOCALALLOC((c+1) * (sizeof(WCHAR)+sizeof(INT)))))
{
WARNING("MF_ExtTextOut: failed memory allocation\n");
return(FALSE);
}
bAlloc = 1;
}
dwCP = GetCodePage(hdc);
cSave = c;
c = MultiByteToWideChar(dwCP, 0, psz, c, pwsz, c*sizeof(WCHAR));
break;
default:
WARNING("MF_ExtTextOut: Bad record type");
return(FALSE);
}
// optimization for printing. If there is no pdx array, don't record one
if((pldc->fl & LDC_META_PRINT) && (pdx == NULL) )
{
PMRSMALLTEXTOUT pmrsto;
BOOL bSmallGlyphs = TRUE;
int cGlyphs;
UINT cSize;
for( cGlyphs = 0; cGlyphs < c; cGlyphs++ )
{
if( pwsz[cGlyphs] & 0xFF00 )
{
bSmallGlyphs = FALSE;
break;
}
}
cSize = sizeof(MRSMALLTEXTOUT);
cSize += c * ( ( bSmallGlyphs ) ? sizeof(char) : sizeof(WCHAR) );
cSize += ( prcl == NULL ) ? 0 : sizeof(RECT);
cSize = ( cSize + 3 ) & ~3;
if( !(pmrsto = (PMRSMALLTEXTOUT) pmdc->pvNewRecord(cSize)) )
{
bRet = FALSE;
}
else
{
pmrsto->vInit(hdc,
pmdc,
EMR_SMALLTEXTOUT,
x,
y,
fl,
(RECT*) prcl,
c,
pwsz,
bSmallGlyphs );
pmrsto->vCommit(pmdc);
}
}
else
{
PMREXTTEXTOUT pmreto;
UINT cjCh = sizeof(WCHAR);
CONST INT *pDxCapt = pdx;
if((mrType == EMR_EXTTEXTOUTA) &&
(IS_ANY_DBCS_CODEPAGE(dwCP)) &&
(pdx != NULL))
{
INT *pDxCapt = (bAlloc) ? (INT*) &pwsz[(cSave+1)&~1] : pDxCaptureBuffer;
ConvertDxArray(dwCP,
(char*) psz,
(int*) pdx,
cSave,
pDxCapt);
}
if (!(pmreto = (PMREXTTEXTOUT) pmdc->pvNewRecord(SIZEOF_MREXTTEXTOUT(c,cjCh))) ||
!pmreto->bInit(EMR_EXTTEXTOUTW,pmdc,hdc,x,y,fl,prcl,(LPCSTR)pwsz,
c,pDxCapt,cjCh))
{
bRet = FALSE;
}
else
{
pmreto->vCommit(pmdc);
}
}
if (bAlloc)
LOCALFREE((void*) pwsz);
return(bRet);
#undef BUFCOUNT
}
// PolyTextOutA
// PolyTextOutW
extern "C" BOOL MF_PolyTextOut(HDC hdc, CONST POLYTEXTA *ppta, int c, DWORD mrType)
{
DWORD mrTypeT;
BOOL b;
CONST POLYTEXTA *pptaT;
PLDC pldc;
DC_PLDC(hdc,pldc,FALSE);
PMDC pmdc = (PMDC)pldc->pvPMDC;
ASSERTGDI(pmdc,"no pmdc\n");
PUTS("MF_PolyTextOut\n");
// [kirko] 19-Apr-94
//
// I have changed this routine to call off to MF_ExtTextOut for each member
// of the POLYTEXT? array. This is a little sleazy in that we are recording
// a different function than what was sent down by the application. On the
// other hand, it works and it is not incompatible with Chicago since they
// don't support a PolyTextOut function. You may be concerned that we are losing
// speed since we no longer call off to the spiffy fase PolyTextOut routine.
// But, if you look in GDI you will find that that PolyTextOut just calls off
// to ExtTextOut in a loop. We have just moved the loop to the Metafile recording.
// If PolyTextOut is ever made fast again, the Metafile code should then be
// modified to record those calls directly.
switch (mrType)
{
case EMR_POLYTEXTOUTA:
mrTypeT = EMR_EXTTEXTOUTA;
break;
case EMR_POLYTEXTOUTW:
mrTypeT = EMR_EXTTEXTOUTW;
break;
default:
WARNING("MF_PolyTextOut -- bad mrType");
return(FALSE);
}
for (b = TRUE, pptaT = ppta + c; ppta < pptaT && b; ppta++)
{
b = MF_ExtTextOut(hdc, ppta->x, ppta->y, ppta->uiFlags, &(ppta->rcl)
, ppta->lpstr, ppta->n, ppta->pdx, mrTypeT);
}
return(b);
}
extern "C" BOOL MF_ExtFloodFill(HDC hdc,int x,int y,COLORREF color,DWORD iMode)
{
PMREXTFLOODFILL pmreff;
PLDC pldc;
DC_PLDC(hdc,pldc,FALSE);
PMDC pmdc = (PMDC)pldc->pvPMDC;
ASSERTGDI(pmdc,"no pmdc\n");
PUTS("MF_ExtFloodFill\n");
if (!(pmreff = (PMREXTFLOODFILL) pmdc->pvNewRecord(SIZEOF_MREXTFLOODFILL)))
return(FALSE);
pmreff->vInit(x, y, color, iMode);
pmreff->vCommit(pmdc);
return(TRUE);
}
// SetColorAdjustment
extern "C" BOOL MF_SetColorAdjustment(HDC hdc, CONST COLORADJUSTMENT *pca)
{
PMRSETCOLORADJUSTMENT pmrsca;
PLDC pldc;
DC_PLDC(hdc,pldc,FALSE);
PMDC pmdc = (PMDC)pldc->pvPMDC;
ASSERTGDI(pmdc,"no pmdc\n");
PUTS("MF_SetColorAdjustment\n");
if (!(pmrsca = (PMRSETCOLORADJUSTMENT) pmdc->pvNewRecord(SIZEOF_MRSETCOLORADJUSTMENT(pca))))
return(FALSE);
pmrsca->vInit(pca);
pmrsca->vCommit(pmdc);
return(TRUE);
}
extern "C" BOOL MF_WriteEscape(HDC hdc, int nEscape, int nCount, LPCSTR lpInData, int type )
{
PMRESCAPE pmre;
PLDC pldc;
DC_PLDC(hdc,pldc,FALSE);
PMDC pmdc = (PMDC)pldc->pvPMDC;
ASSERTGDI(pmdc,"no pmdc\n");
MFD2("Recording escape %d\n", nEscape );
// just in case some one (pagemaker) passes in NULL with non 0 count!
if (lpInData == NULL)
nCount = 0;
if (!(pmre = (PMRESCAPE) pmdc->pvNewRecord((sizeof(MRESCAPE)+nCount+3)&~3)))
{
WARNING("MF_WriteEscape: failed memory allocation\n");
return(FALSE);
}
pmre->vInit(type, nEscape, nCount, lpInData);
pmre->vCommit(pmdc);
return(TRUE);
}
extern "C" BOOL MF_WriteNamedEscape(
HDC hdc,
LPWSTR pwszDriver,
int nEscape,
int nCount,
LPCSTR lpInData)
{
PMRNAMEDESCAPE pmre;
PLDC pldc;
DC_PLDC(hdc,pldc,FALSE);
PMDC pmdc = (PMDC)pldc->pvPMDC;
ASSERTGDI(pmdc,"no pmdc\n");
MFD2("Recording named escape %d\n", nEscape );
INT cjSizeOfRecord = (sizeof(MRNAMEDESCAPE) + nCount +
((wcslen(pwszDriver)+1) * sizeof(WCHAR)) +3)&~3;
if(!(pmre = (PMRNAMEDESCAPE) pmdc->pvNewRecord(cjSizeOfRecord)))
{
WARNING("MF_WriteEscape: failed memory allocation\n");
return(FALSE);
}
pmre->vInit(EMR_NAMEDESCAPE, nEscape, pwszDriver, lpInData, nCount);
pmre->vCommit(pmdc);
return(TRUE);
}
extern "C" BOOL MF_StartDoc(HDC hdc, CONST DOCINFOW *pDocInfo )
{
PMRSTARTDOC pmrs;
DWORD cj;
PLDC pldc;
DC_PLDC(hdc,pldc,FALSE);
PMDC pmdc = (PMDC)pldc->pvPMDC;
ASSERTGDI(pmdc,"no pmdc\n");
MFD1( "Recording MF_StartDocW\n" );
cj = sizeof(MRSTARTDOC);
if( pDocInfo->lpszDocName != NULL )
{
cj += (lstrlenW( pDocInfo->lpszDocName ) + 1) * sizeof(WCHAR);
cj = (cj+3) & ~(0x3);
}
if( pDocInfo->lpszOutput != NULL )
{
cj += (lstrlenW( pDocInfo->lpszOutput ) + 1) * sizeof(WCHAR);
}
cj = (cj+3) & ~(0x3); // make things DWORD alligned
if (!(pmrs = (PMRSTARTDOC) pmdc->pvNewRecord( cj+40 )))
{
WARNING("MF_StartDoc: failed memory allocation\n");
return(FALSE);
}
pmrs->vInit(EMR_STARTDOC, pDocInfo);
pmrs->vCommit(pmdc);
return(TRUE);
}
extern "C" BOOL MF_ForceUFIMapping(HDC hdc, PUNIVERSAL_FONT_ID pufi )
{
PMRFORCEUFIMAPPING pmre;
PLDC pldc;
DC_PLDC(hdc,pldc,FALSE);
PMDC pmdc = (PMDC)pldc->pvPMDC;
ASSERTGDI(pmdc,"no pmdc\n");
MFD1("Recording forced mapping\n");
if (!(pmre = (PMRFORCEUFIMAPPING) pmdc->pvNewRecord(sizeof(MRFORCEUFIMAPPING))))
{
WARNING("MF_ForceUFIMapping: failed memory allocation\n");
return(FALSE);
}
pmre->vInit(EMR_FORCEUFIMAPPING, pufi);
pmre->vCommit(pmdc);
return(TRUE);
}
// OpenGL metafile records
#ifdef GL_METAFILE
BOOL APIENTRY GdiAddGlsRecord(HDC hdc, DWORD cb, BYTE *pb, LPRECTL prclBounds)
{
PMRGLSRECORD pmrgr;
PMRGLSBOUNDEDRECORD pmrgbr;
PLDC pldc;
DC_PLDC(hdc, pldc, FALSE);
PMDC pmdc = (PMDC)pldc->pvPMDC;
ASSERTGDI(pmdc, "no pmdc\n");
if (prclBounds == NULL)
{
pmrgr = (PMRGLSRECORD)pmdc->pvNewRecord(SIZEOF_MRGLSRECORD(cb));
if (pmrgr == NULL)
{
return FALSE;
}
pmrgr->vInit(cb, pb);
pmrgr->vCommit(pmdc);
}
else
{
pmrgbr = (PMRGLSBOUNDEDRECORD)
pmdc->pvNewRecord(SIZEOF_MRGLSBOUNDEDRECORD(cb));
if (pmrgbr == NULL)
{
return FALSE;
}
pmrgbr->vInit(cb, pb, prclBounds);
pmrgbr->vCommit(pmdc);
}
// Mark the metafile as containing OpenGL records
pmdc->mrmf.bOpenGL = TRUE;
return TRUE;
}
#endif
#ifdef GL_METAFILE
extern "C" BOOL APIENTRY GdiAddGlsBounds(HDC hdc, LPRECTL prclBounds)
{
// Bounds are given as a well-ordered rectangle in
// device coordinates
return SetBoundsRectAlt(hdc, (RECT *)prclBounds,
(UINT)(DCB_WINDOWMGR | DCB_ACCUMULATE)) != 0;
}
#endif
#ifdef GL_METAFILE
extern "C" BOOL APIENTRY MF_SetPixelFormat(HDC hdc,
int iPixelFormat,
CONST PIXELFORMATDESCRIPTOR *ppfd)
{
PMRPIXELFORMAT pmrpf;
PLDC pldc;
DC_PLDC(hdc, pldc, FALSE);
PMDC pmdc = (PMDC)pldc->pvPMDC;
ASSERTGDI(pmdc, "no pmdc\n");
pmrpf = (PMRPIXELFORMAT)pmdc->pvNewRecord(SIZEOF_MRPIXELFORMAT);
if (pmrpf == NULL)
{
return FALSE;
}
pmrpf->vInit(ppfd);
pmrpf->vCommit(pmdc);
// Fix up the pixel format offset in the header
// BUGBUG - This only allows one pixel format to be
// described in the header. This doesn't seem too bad
// but we don't really need the pixel format offset in the
// header since there should always be a pixel format record
// in the metafile (as long as a pixel format is set)
pmdc->mrmf.cbPixelFormat = sizeof(PIXELFORMATDESCRIPTOR);
pmdc->mrmf.offPixelFormat = pmdc->iMem-sizeof(MRPIXELFORMAT)+
FIELD_OFFSET(MRPIXELFORMAT, pfd);
return TRUE;
}
#endif