|
|
/*****************************************************************************
* * paths - 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
#pragma pack(2)
typedef struct PathInfo16 { WORD RenderMode; BYTE FillMode; BYTE BkMode; LOGPEN16 Pen; LOGBRUSH16 Brush; DWORD BkColor; } PathInfo16;
#pragma pack()
BOOL GdipFlattenGdiPath(PLOCALDC, LPVOID*, INT*);
/****************************************************************************
* GillesK 2001/02/12 * Convert a PolyPolygon call to multiple Polygons calls. * PolyPolygons cannot be used for Postscript paths. So we need to convert * them to Polygon calls and wrap a Postscipt BeginPath/EndPath sequence * around each polygon ****************************************************************************/
BOOL ConvertPolyPolygonToPolygons( PLOCALDC pLocalDC, PPOINTL pptl, PDWORD pcptl, DWORD cptl, DWORD ccptl, BOOL transform ) { PathInfo16 pathInfo16 = { 0, 1, TRANSPARENT, { PS_NULL, {0,0}, RGB(0, 0, 0)}, {BS_HOLLOW, RGB(0, 0, 0), 0}, RGB(0, 0, 0) } ; DWORD polyCount; BOOL b = TRUE; // In case there are 0 polygons
PPOINTL buffer = NULL; PPOINTS shortBuffer = NULL; WORD wEscape;
// Convert the points from POINTL to POINTS
buffer = (PPOINTL) LocalAlloc(LMEM_FIXED, cptl * sizeof(POINTL)); if (buffer == NULL) { return FALSE; } RtlCopyMemory(buffer, pptl, cptl*sizeof(POINTL)); if (transform) { b = bXformRWorldToPPage(pLocalDC, buffer, cptl); if (b == FALSE) goto exitFreeMem; }
vCompressPoints(buffer, cptl) ; shortBuffer = (PPOINTS) buffer;
// For each polygon in the polycount, we do a BeginPath, and EndPath
for (polyCount = 0; polyCount < ccptl; shortBuffer += pcptl[polyCount], polyCount++) { // Emit the Postscript escape to End the Path
if(!bEmitWin16Escape(pLocalDC, BEGIN_PATH, 0, NULL, NULL)) goto exitFreeMem;
// Call the Win16 routine to emit the poly to the metafile.
b = bEmitWin16Poly(pLocalDC, (LPPOINTS) shortBuffer, (SHORT) pcptl[polyCount], META_POLYGON) ;
// Emit the Postscript escape to End the Path
if(!bEmitWin16Escape(pLocalDC, END_PATH, sizeof(pathInfo16), (LPSTR)&pathInfo16, NULL)) goto exitFreeMem;
// If the bEmitWin16Poly has failed, we at least want to end the path
if (!b) { goto exitFreeMem; }
}
exitFreeMem: if (buffer != NULL) { LocalFree((HLOCAL) buffer); }
return b;
}
BOOL ConvertPathToPSClipPath(PLOCALDC pLocalDC, BOOL psOnly) { INT ihW32Br; LONG lhpn32 = pLocalDC->lhpn32; LONG lhbr32 = pLocalDC->lhbr32; WORD wEscape;
if( pLocalDC->iROP == R2_NOTCOPYPEN ) { ihW32Br = WHITE_BRUSH | ENHMETA_STOCK_OBJECT ; } else { ihW32Br = BLACK_BRUSH | ENHMETA_STOCK_OBJECT ; }
// Emit the Postscript escape to ignore the pen change
wEscape = STARTPSIGNORE ; if(!bEmitWin16Escape(pLocalDC, POSTSCRIPT_IGNORE, sizeof(wEscape), (LPSTR)&wEscape, NULL)) return FALSE ;
if (DoSelectObject(pLocalDC, ihW32Br)) { // Do it to the helper DC.
DWORD oldRop = SetROP2(pLocalDC->hdcHelper, R2_COPYPEN); // Emit the Win16 metafile drawing order.
if (!bEmitWin16SetROP2(pLocalDC, LOWORD(R2_COPYPEN))) return FALSE;
wEscape = ENDPSIGNORE ; if(!bEmitWin16Escape(pLocalDC, POSTSCRIPT_IGNORE, sizeof(wEscape), (LPSTR)&wEscape, NULL)) return FALSE ;
// If we only want the path in PS then we need to save the previous one
if (psOnly) { wEscape = CLIP_SAVE ; if(!bEmitWin16Escape(pLocalDC, CLIP_TO_PATH, sizeof(wEscape), (LPSTR)&wEscape, NULL)) return FALSE ; }
if(!DoRenderPath(pLocalDC, EMR_FILLPATH, psOnly)) // We need to fill the path with black
return FALSE;
if(pLocalDC->pbLastSelectClip == pLocalDC->pbRecord || psOnly) { wEscape = CLIP_INCLUSIVE; if(!bEmitWin16Escape(pLocalDC, CLIP_TO_PATH, sizeof(wEscape), (LPSTR)&wEscape, NULL)) return FALSE; }
// Emit the Postscript escape to ignore the pen change
wEscape = STARTPSIGNORE ; if(!bEmitWin16Escape(pLocalDC, POSTSCRIPT_IGNORE, sizeof(wEscape), (LPSTR)&wEscape, NULL)) return FALSE ;
if(!DoSelectObject(pLocalDC, lhbr32)) return FALSE;
// Do it to the helper DC.
SetROP2(pLocalDC->hdcHelper, oldRop); // Emit the Win16 metafile drawing order.
if (!bEmitWin16SetROP2(pLocalDC, LOWORD(oldRop))) return FALSE;
wEscape = ENDPSIGNORE ; if(!bEmitWin16Escape(pLocalDC, POSTSCRIPT_IGNORE, sizeof(wEscape), (LPSTR)&wEscape, NULL)) return FALSE ;
} return TRUE ;
}
/***************************************************************************
* BeginPath - Win32 to Win16 Metafile Converter Entry Point **************************************************************************/ BOOL WINAPI DoBeginPath ( PLOCALDC pLocalDC ) { BOOL b ;
// Set the global flag telling all all the geometric
// rendering routines that we are accumulating drawing orders
// for the path.
pLocalDC->flags |= RECORDING_PATH ;
// Tell the helper DC we are begining the path accumulation.
b = BeginPath(pLocalDC->hdcHelper) ;
// Save the position of the path if we haven't started the XOR passes
if (pLocalDC->flags & INCLUDE_W32MF_XORPATH) { if(pLocalDC->iXORPass == NOTXORPASS) { pLocalDC->pbChange = (PBYTE) pLocalDC->pbRecord ; pLocalDC->lholdp32 = pLocalDC->lhpn32 ; pLocalDC->lholdbr32 = pLocalDC->lhbr32; } } ASSERTGDI((b == TRUE), "MF3216: DoBeginPath, BeginPath failed\n") ;
return (b) ; }
/***************************************************************************
* EndPath - Win32 to Win16 Metafile Converter Entry Point **************************************************************************/ BOOL WINAPI DoEndPath ( PLOCALDC pLocalDC ) { BOOL b ;
// Reset the global flag, turning off the path accumulation.
pLocalDC->flags &= ~RECORDING_PATH ;
b = EndPath(pLocalDC->hdcHelper) ;
ASSERTGDI((b == TRUE), "MF3216: DoEndPath, EndPath failed\n") ;
return (b) ; }
/***************************************************************************
* WidenPath - Win32 to Win16 Metafile Converter Entry Point **************************************************************************/ BOOL WINAPI DoWidenPath ( PLOCALDC pLocalDC ) { BOOL b ;
b = WidenPath(pLocalDC->hdcHelper) ;
ASSERTGDI((b == TRUE), "MF3216: DoWidenPath, WidenPath failed\n") ;
return (b) ; }
/***************************************************************************
* SelectClipPath - Win32 to Win16 Metafile Converter Entry Point * * History: * Tue Apr 07 17:05:37 1992 -by- Hock San Lee [hockl] * Wrote it. **************************************************************************/
BOOL WINAPI DoSelectClipPath(PLOCALDC pLocalDC, INT iMode) { INT iROP2 ; BOOL bRet = TRUE; WORD wEscape; PathInfo16 pathInfo16 = { 0, 1, 1, { PS_NULL, {0,0}, 0}, {BS_NULL, 0, 0}, 0 } ;
BOOL bNoClipping = bNoDCRgn(pLocalDC, DCRGN_CLIP); BOOL bIgnorePS = FALSE;
// Since we cannot do any other operations then an OR with multiple clipping regions
// Only do the XOR if we are with a RGN_OR
if ((iMode == RGN_COPY || iMode == RGN_AND || (iMode == RGN_OR && bNoClipping)) && (pLocalDC->flags & INCLUDE_W32MF_XORPATH)) { if (pLocalDC->iXORPass == NOTXORPASS ) { pLocalDC->iXORPass = DRAWXORPASS ; pLocalDC->iXORPassDCLevel = pLocalDC->iLevel ; iROP2 = GetROP2( pLocalDC->hdcHelper ) ; if( iROP2 == R2_COPYPEN || iROP2 == R2_NOTCOPYPEN ) { if(!DoSaveDC(pLocalDC)) return FALSE; pLocalDC->iROP = iROP2;
// Emit the Postscript escape to ignore the XOR
wEscape = STARTPSIGNORE ; if(!bEmitWin16Escape(pLocalDC, POSTSCRIPT_IGNORE, sizeof(wEscape), (LPSTR)&wEscape, NULL)) return FALSE ;
// Do it to the helper DC.
SetROP2(pLocalDC->hdcHelper, R2_XORPEN); // Emit the Win16 metafile drawing order.
if (!bEmitWin16SetROP2(pLocalDC, LOWORD(R2_XORPEN))) return FALSE;
MoveToEx( pLocalDC->hdcHelper, 0, 0, &(pLocalDC->pOldPosition ) ) ; MoveToEx( pLocalDC->hdcHelper, pLocalDC->pOldPosition.x, pLocalDC->pOldPosition.y, NULL );
// Save this record number. When we pass again the last one will be the one that send the
// Postscript clip path.
pLocalDC->pbLastSelectClip = pLocalDC->pbRecord ; return bRet ; } pLocalDC->flags |= ERR_XORCLIPPATH;
return FALSE; } else if(pLocalDC->iXORPass == DRAWXORPASS ) { // Save this record number. When we pass again the last one will be the one that send the
// Postscript clip path.
pLocalDC->pbLastSelectClip = pLocalDC->pbRecord ; return TRUE; } else if( pLocalDC->iXORPass == ERASEXORPASS ) { if (!ConvertPathToPSClipPath(pLocalDC, FALSE) || !bEmitWin16EmitSrcCopyComment(pLocalDC, msocommentBeginSrcCopy)) { return FALSE; } return TRUE; } else { ASSERT(FALSE); } } // Convert the clippath to a PS clippath
if (ConvertPathToPSClipPath(pLocalDC, TRUE)) { bIgnorePS = TRUE; pLocalDC->iSavePSClipPath++; // Emit the Postscript escape to ignore the pen change
wEscape = STARTPSIGNORE ; if(!bEmitWin16Escape(pLocalDC, POSTSCRIPT_IGNORE, sizeof(wEscape), (LPSTR)&wEscape, NULL)) return FALSE ; }
// If there is no initial clip region and we are going to operate
// on the initial clip region, we have to
// create one. Otherwise, GDI will create some random default
// clipping region for us!
if ((iMode == RGN_DIFF || iMode == RGN_XOR || iMode == RGN_OR) && bNoClipping) { HRGN hrgnDefault;
if (!(hrgnDefault = CreateRectRgn((int) (SHORT) MINSHORT, (int) (SHORT) MINSHORT, (int) (SHORT) MAXSHORT, (int) (SHORT) MAXSHORT))) { ASSERTGDI(FALSE, "MF3216: CreateRectRgn failed"); return(FALSE); }
bRet = (ExtSelectClipRgn(pLocalDC->hdcHelper, hrgnDefault, RGN_COPY) != ERROR); ASSERTGDI(bRet, "MF3216: ExtSelectClipRgn failed");
if (!DeleteObject(hrgnDefault)) ASSERTGDI(FALSE, "MF3216: DeleteObject failed");
if (!bRet) return(FALSE); } // Do it to the helper DC.
// When we do this. It clears the path so it has to be
// done when we are not using the path
if(!SelectClipPath(pLocalDC->hdcHelper, iMode)) return(FALSE);
// Dump the clip region data.
bRet = bDumpDCClipping(pLocalDC);
if (bIgnorePS) { // Emit the Postscript escape to ignore the pen change
wEscape = ENDPSIGNORE ; if(!bEmitWin16Escape(pLocalDC, POSTSCRIPT_IGNORE, sizeof(wEscape), (LPSTR)&wEscape, NULL)) return FALSE ; }
return(bRet); }
/***************************************************************************
* FlattenPath - Win32 to Win16 Metafile Converter Entry Point **************************************************************************/ BOOL WINAPI DoFlattenPath ( PLOCALDC pLocalDC ) { BOOL b; b = FlattenPath(pLocalDC->hdcHelper) ; ASSERTGDI((b == TRUE), "MF3216: DoFlattenPath, FlattenPath failed\n") ;
return (b) ; }
/***************************************************************************
* AbortPath - Win32 to Win16 Metafile Converter Entry Point **************************************************************************/ BOOL WINAPI DoAbortPath ( PLOCALDC pLocalDC ) { BOOL b ;
// Reset the global flag, turning off the path accumulation.
pLocalDC->flags &= ~RECORDING_PATH ;
b = AbortPath(pLocalDC->hdcHelper) ;
// We cannot abort a path if we have a XORPass so return FALSE
if (pLocalDC->flags & INCLUDE_W32MF_XORPATH) return FALSE ;
ASSERTGDI((b == TRUE), "MF3216: DoAbortPath, AbortPath failed\n") ;
return (b) ; }
/***************************************************************************
* CloseFigure - Win32 to Win16 Metafile Converter Entry Point **************************************************************************/ BOOL WINAPI DoCloseFigure ( PLOCALDC pLocalDC ) { BOOL b ;
b = CloseFigure(pLocalDC->hdcHelper) ;
ASSERTGDI((b == TRUE), "MF3216: DoCloseFigure, CloseFigure failed\n") ;
return (b) ; }
/***************************************************************************
* DoRenderPath - Common code for StrokePath, FillPath and StrokeAndFillPath. **************************************************************************/
// Macro for copy a point in the path data.
#define MOVE_A_POINT(iDst, pjTypeDst, pptDst, iSrc, pjTypeSrc, pptSrc) \
{ \ pjTypeDst[iDst] = pjTypeSrc[iSrc]; \ pptDst[iDst] = pptSrc[iSrc]; \ }
BOOL WINAPI DoRenderPath(PLOCALDC pLocalDC, INT mrType, BOOL psOnly) { BOOL b; PBYTE pb = (PBYTE) NULL; PBYTE pbNew = (PBYTE) NULL; LPPOINT ppt, pptNew; LPBYTE pjType, pjTypeNew; PDWORD pPolyCount; INT cpt, cptNew, cPolyCount; INT i, j, jStart; LONG lhpn32; LPVOID pGdipFlatten = NULL; INT count = 0; BOOL transform = TRUE; WORD wEscape;
b = FALSE; // assume failure
ppt = NULL; pjType = NULL;
// Flatten the path, to convert all the beziers into polylines.
// Try to use GDIPlus and transform the points before hand, if we fail then
// go back and try to do it with GDI
if (GdipFlattenGdiPath(pLocalDC, &pGdipFlatten, &count)) { ASSERT(pGdipFlatten != NULL); ppt = (LPPOINT)pGdipFlatten; pjType = (PBYTE) (ppt + count); cpt = count; transform = FALSE; } else { if (!DoFlattenPath(pLocalDC)) { RIPS("MF3216: DoRenderPath, FlattenPath failed\n"); goto exit_DoRenderPath; }
// 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: DoRenderPath, GetPath failed\n"); goto exit_DoRenderPath; }
// Check for empty path.
if (cpt == 0) { b = TRUE; goto exit_DoRenderPath; }
// Allocate memory for the path data.
if (!(pb = (PBYTE) LocalAlloc ( LMEM_FIXED, cpt * (sizeof(POINT) + sizeof(BYTE)) ) ) ) { RIPS("MF3216: DoRenderPath, LocalAlloc failed\n"); goto exit_DoRenderPath; }
// Order of assignment is important for dword alignment.
ppt = (LPPOINT) pb; pjType = (LPBYTE) (ppt + cpt);
// Finally, get the path data.
if (GetPath(pLocalDC->hdcHelper, ppt, pjType, cpt) != cpt) { RIPS("MF3216: DoRenderPath, GetPath failed\n"); goto exit_DoRenderPath; } } // The path data is in record-time world coordinates. They are the
// coordinates we will use in the PolyPoly rendering functions below.
//
// Since we have flattened the path, the path data should only contain
// the following types:
//
// PT_MOVETO
// PT_LINETO
// (PT_LINETO | PT_CLOSEFIGURE)
//
// To simplify, we will close the figure explicitly by inserting points
// and removing the (PT_LINETO | PT_CLOSEFIGURE) type from the path data.
// At the same time, we will create the PolyPoly structure to prepare for
// the PolyPolygon or PolyPolyline call.
//
// Note that there cannot be more than one half (PT_LINETO | PT_CLOSEFIGURE)
// points since they are followed by the PT_MOVETO points (except for the
// last point). In addition, the first point must be a PT_MOVETO.
//
// We will also remove the empty figure, i.e. consecutive PT_MOVETO, from
// the new path data in the process.
// First, allocate memory for the new path data.
cptNew = cpt + cpt / 2; if (!(pbNew = (PBYTE) LocalAlloc ( LMEM_FIXED, cptNew * (sizeof(POINT) + sizeof(DWORD) + sizeof(BYTE)) ) ) ) { RIPS("MF3216: DoRenderPath, LocalAlloc failed\n"); goto exit_DoRenderPath; }
// Order of assignment is important for dword alignment.
pptNew = (LPPOINT) pbNew; pPolyCount = (PDWORD) (pptNew + cptNew); pjTypeNew = (LPBYTE) (pPolyCount + cptNew);
// Close the path explicitly.
i = 0; j = 0; cPolyCount = 0; // number of entries in PolyCount array
while (i < cpt) { ASSERTGDI(pjType[i] == PT_MOVETO, "MF3216: DoRenderPath, bad pjType[]");
// Copy everything upto the next closefigure or moveto.
jStart = j;
// copy the moveto
MOVE_A_POINT(j, pjTypeNew, pptNew, i, pjType, ppt); i++; j++;
if (i >= cpt) // stop if the last point is a moveto
{ j--; // don't include the last moveto
break; }
while (i < cpt) { MOVE_A_POINT(j, pjTypeNew, pptNew, i, pjType, ppt); i++; j++;
// look for closefigure and moveto
if (pjTypeNew[j - 1] != PT_LINETO) break; }
if (pjTypeNew[j - 1] == PT_MOVETO) { i--; j--; // restart the next figure from moveto
if (j - jStart == 1) // don't include consecutive moveto's
j = jStart; // ignore the first moveto
else pPolyCount[cPolyCount++] = j - jStart; // add one poly
} else if (pjTypeNew[j - 1] == PT_LINETO) { // we have reached the end of path data
pPolyCount[cPolyCount++] = j - jStart; // add one poly
break; } else if (pjTypeNew[j - 1] == (PT_LINETO | PT_CLOSEFIGURE)) { pjTypeNew[j - 1] = PT_LINETO;
// Insert a PT_LINETO to close the figure.
pjTypeNew[j] = PT_LINETO; pptNew[j] = pptNew[jStart]; j++; pPolyCount[cPolyCount++] = j - jStart; // add one poly
} else { ASSERTGDI(FALSE, "MF3216: DoRenderPath, unknown pjType[]"); } } // while
ASSERTGDI(j <= cptNew && cPolyCount <= cptNew, "MF3216: DoRenderPath, path data overrun");
cptNew = j;
// Check for empty path.
if (cptNew == 0) { b = TRUE; goto exit_DoRenderPath; }
// Now we have a path data that consists of only PT_MOVETO and PT_LINETO.
// Furthermore, there is no "empty" figure, i.e. consecutive PT_MOVETO, in
// the path. We can finally render the picture with PolyPolyline or
// PolyPolygon.
if (mrType == EMR_STROKEPATH && !psOnly) { // Do StrokePath.
b = DoPolyPolyline(pLocalDC, (PPOINTL) pptNew, (PDWORD) pPolyCount, (DWORD) cPolyCount, transform); } else // FILLPATH or PSOnly
{ // Setup our PS clippath
if (pLocalDC->iXORPass == ERASEXORPASS || psOnly) { LONG lhpn32 = pLocalDC->lhpn32; LONG lhbr32 = pLocalDC->lhbr32;
// Do it to the helper DC.
DWORD oldRop = SetROP2(pLocalDC->hdcHelper, R2_NOP); // Emit the Win16 metafile drawing order.
if (!bEmitWin16SetROP2(pLocalDC, LOWORD(R2_NOP))) goto exit_DoRenderPath;
b = ConvertPolyPolygonToPolygons(pLocalDC, (PPOINTL) pptNew, (PDWORD) pPolyCount, (DWORD) cptNew, (DWORD) cPolyCount, transform);
if (!b) { ASSERTGDI(FALSE, "GPMF3216: DoRenderPath, PolyPolygon conversion failed"); goto exit_DoRenderPath; }
// Do it to the helper DC.
SetROP2(pLocalDC->hdcHelper, oldRop); // Emit the Win16 metafile drawing order.
if (!bEmitWin16SetROP2(pLocalDC, LOWORD(oldRop))) goto exit_DoRenderPath;
wEscape = STARTPSIGNORE ; if(!bEmitWin16Escape(pLocalDC, POSTSCRIPT_IGNORE, sizeof(wEscape), (LPSTR)&wEscape, NULL)) goto exit_DoRenderPath; } if (!psOnly) { // Do FillPath and StrokeAndFillPath.
// If we are doing fill only, we need to select in a NULL pen.
if (mrType == EMR_FILLPATH) { lhpn32 = pLocalDC->lhpn32; // remember the previous pen
if (!DoSelectObject(pLocalDC, ENHMETA_STOCK_OBJECT | NULL_PEN)) { ASSERTGDI(FALSE, "MF3216: DoRenderPath, DoSelectObject failed"); goto exit_DoRenderPath; } }
// Do the PolyPolygon.
b = DoPolyPolygon(pLocalDC, (PPOINTL) pptNew, (PDWORD) pPolyCount, (DWORD) cptNew, (DWORD) cPolyCount, transform);
// Restore the previous pen.
if (mrType == EMR_FILLPATH) if (!DoSelectObject(pLocalDC, lhpn32)) ASSERTGDI(FALSE, "MF3216: DoRenderPath, DoSelectObject failed"); }
if (pLocalDC->iXORPass == ERASEXORPASS || psOnly) { // End the PS ignore sequence
wEscape = ENDPSIGNORE ; if(!bEmitWin16Escape(pLocalDC, POSTSCRIPT_IGNORE, sizeof(wEscape), (LPSTR)&wEscape, NULL)) goto exit_DoRenderPath; } }
exit_DoRenderPath:
// If we are doing a PSOnly path, then don't abort because we are gonna
// use the path as a clipping region later
if (!psOnly) { // Clear the path by calling AbortPath
AbortPath(pLocalDC->hdcHelper); } if (pbNew) if (LocalFree((HANDLE) pbNew)) RIPS("MF3216: DoRenderPath, LocalFree failed\n"); if (pb) if (LocalFree((HANDLE) pb)) RIPS("MF3216: DoRenderPath, LocalFree failed\n");
if (pGdipFlatten) { if (LocalFree((HANDLE) pGdipFlatten)) RIPS("MF3216: DoRenderPath, LocalFree failed\n"); } return(b); }
|