extern "C" { #include "precomp.h" } #include "wtypes.h" #include "objbase.h" #include "gdiplus.h" extern "C" BOOL bInvertxform(PXFORM pxformSrc, PXFORM pxformDest); extern "C" BOOL bXformWorkhorse(PPOINTL aptl, DWORD nCount, PXFORM pXform); using namespace Gdiplus; inline REAL GetDistance( GpPointF & p1, GpPointF & p2 ) { double dx = (double)p2.X - p1.X; double dy = (double)p2.Y - p1.Y; return (REAL)sqrt((dx * dx) + (dy * dy)); } // Flatten a path using GDI+ and transform the points before hand so we flatten // the points that will go in the metafile. We allocate one buffer that will // contain the points and types. The caller has to free that buffer extern "C" BOOL GdipFlattenGdiPath(PLOCALDC pLocalDC, LPVOID *buffer, INT *count) { BOOL b = FALSE; INT i ; INT cpt; PBYTE pb = NULL; PointF* pptf; LPPOINT ppt; PBYTE pjType; INT flattenCount; PBYTE flattenpb = NULL; PointF* flattenPoints; PBYTE flattenTypes; PBYTE returnpb = NULL; ASSERT(buffer != NULL && *buffer == NULL && count != NULL); // Get the path data. // First get a count of the number of points. cpt = GetPath(pLocalDC->hdcHelper, (LPPOINT) NULL, (LPBYTE) NULL, 0); if (cpt == -1) { RIPS("MF3216: DoFlattenPath, GetPath failed\n"); goto exit_DoFlattenPath; } // Check for empty path. if (cpt == 0) { b = TRUE; goto exit_DoFlattenPath; } // Allocate memory for the path data. if (!(pb = (PBYTE) LocalAlloc ( LMEM_FIXED, cpt * (sizeof(PointF) + sizeof(POINT) + sizeof(BYTE)) ) ) ) { RIPS("MF3216: DoFlattenPath, LocalAlloc failed\n"); goto exit_DoFlattenPath; } // Order of assignment is important for dword alignment. pptf = (PointF*) pb; ppt = (LPPOINT) (pptf + cpt); pjType = (LPBYTE) (ppt + cpt); // Finally, get the path data. if (GetPath(pLocalDC->hdcHelper, ppt, pjType, cpt) != cpt) { RIPS("MF3216: DoFlattenPath, GetPath failed\n"); goto exit_DoFlattenPath; } if (pfnSetVirtualResolution == NULL) { if (!bXformWorkhorse((PPOINTL) ppt, cpt, &pLocalDC->xformRDevToRWorld)) goto exit_DoFlattenPath; } BYTE tempType; for (i = 0; i < cpt; i++) { pptf[i] = PointF((REAL) ppt[i].x, (REAL) ppt[i].y); switch (pjType[i] & ~PT_CLOSEFIGURE) { case PT_LINETO: tempType = PathPointTypeLine; break; case PT_MOVETO: tempType = PathPointTypeStart; break; case PT_BEZIERTO: tempType = PathPointTypeBezier; break; default: WARNING(("MF3216: There's something wrong with this path")); tempType = PathPointTypeLine; break; } if (pjType[i] & PT_CLOSEFIGURE) { tempType |= PathPointTypeCloseSubpath; } pjType[i] = tempType; } { XFORM* xform = &(pLocalDC->xformRWorldToPPage); Matrix matrix((REAL)xform->eM11, (REAL)xform->eM12, (REAL)xform->eM21, (REAL)xform->eM22, (REAL)xform->eDx, (REAL)xform->eDy); GraphicsPath gdipPath (pptf, pjType, cpt); // This will transform the flattened point into the resolution of the // metafile, giving us the best resolution for playtime gdipPath.Flatten(&matrix, 1.0f/6.0f); flattenCount = gdipPath.GetPointCount(); if (flattenCount < 0) { RIPS("MF3216: GDIP failed in flatting the path\n"); goto exit_DoFlattenPath; } if (!(flattenpb = (PBYTE) LocalAlloc ( LMEM_FIXED, flattenCount * (sizeof(PointF) + sizeof(BYTE)) ) ) ) { RIPS("MF3216: DoFlattenPath, LocalAlloc failed\n"); goto exit_DoFlattenPath; } flattenPoints = (PointF*) flattenpb; flattenTypes = (PBYTE) (flattenPoints + flattenCount); if (!(returnpb = (PBYTE) LocalAlloc ( LMEM_FIXED, flattenCount * (sizeof(POINT) + sizeof(BYTE)) ) ) ) { RIPS("MF3216: DoFlattenPath, LocalAlloc failed\n"); goto exit_DoFlattenPath; } ppt = (LPPOINT) returnpb; pjType = (PBYTE) (ppt + flattenCount); if (gdipPath.GetPathTypes(flattenTypes, flattenCount) != Ok) { RIPS("MF3216: DoFlattenPath, GetPathTypes failed\n"); goto exit_DoFlattenPath; } if (gdipPath.GetPathPoints(flattenPoints, flattenCount) != Ok) { RIPS("MF3216: DoFlattenPath, GetPathPoints failed\n"); goto exit_DoFlattenPath; } for (i = 0; i < flattenCount; i++) { ppt[i].x = (INT)(flattenPoints[i].X + 0.5f); ppt[i].y = (INT)(flattenPoints[i].Y + 0.5f); switch (flattenTypes[i] & ~PathPointTypeCloseSubpath) { case PathPointTypeLine: tempType = PT_LINETO; break; case PathPointTypeStart: tempType = PT_MOVETO; break; break; default: WARNING(("MF3216: There's something wrong with this path")); break; } if (flattenTypes[i] & PathPointTypeCloseSubpath) { tempType |= PT_CLOSEFIGURE; } pjType[i] = tempType; } } *buffer = returnpb; *count = flattenCount; returnpb = NULL; b = TRUE; exit_DoFlattenPath: // Cleanup any allocations if (pb != NULL) { LocalFree((HANDLE)pb); } if (flattenpb != NULL) { LocalFree((HANDLE)flattenpb); } // This should only happen if we failed if (returnpb != NULL) { LocalFree((HANDLE)returnpb); } return b; }