From b8e94b611917352dde2422b1dc20f2587dd70a4c Mon Sep 17 00:00:00 2001 From: Huw D M Davies Date: Mon, 20 Dec 1999 04:14:48 +0000 Subject: [PATCH] Move Bezier code out of x11drv into commmon GDI code; if any driver does not implement PolyBezier[To] the curve is approximated to lines and drawn with Polyline. Implement many GDI-Path recording functions (at least the win9x subset). Implement FlattenPath and FillPath. --- graphics/metafiledrv/graphics.c | 22 +++ graphics/metafiledrv/init.c | 4 +- graphics/painting.c | 324 ++++++++++++++++++++++++++++++++++++---- graphics/path.c | 224 ++++++++++++++++++++++++++- graphics/ttydrv/graphics.c | 10 -- graphics/ttydrv/init.c | 2 +- graphics/x11drv/graphics.c | 233 ----------------------------- graphics/x11drv/init.c | 4 +- include/gdi.h | 4 + include/metafiledrv.h | 2 + include/path.h | 8 + include/ttydrv.h | 1 - include/x11drv.h | 4 - 13 files changed, 553 insertions(+), 289 deletions(-) diff --git a/graphics/metafiledrv/graphics.c b/graphics/metafiledrv/graphics.c index c96e6803cc1..664a9a0ee18 100644 --- a/graphics/metafiledrv/graphics.c +++ b/graphics/metafiledrv/graphics.c @@ -379,3 +379,25 @@ MFDRV_SetTextColor( DC *dc, COLORREF color ) LOWORD(color)); } + +/********************************************************************** + * MFDRV_PolyBezier + * Since MetaFiles don't record Beziers and they don't even record + * approximations to them using lines, we need this stub function. + */ +BOOL +MFDRV_PolyBezier( DC *dc, const POINT *pts, DWORD count ) +{ + return FALSE; +} + +/********************************************************************** + * MFDRV_PolyBezierTo + * Since MetaFiles don't record Beziers and they don't even record + * approximations to them using lines, we need this stub function. + */ +BOOL +MFDRV_PolyBezierTo( DC *dc, const POINT *pts, DWORD count ) +{ + return FALSE; +} diff --git a/graphics/metafiledrv/init.c b/graphics/metafiledrv/init.c index 5bbb301b780..4b518cb8211 100644 --- a/graphics/metafiledrv/init.c +++ b/graphics/metafiledrv/init.c @@ -65,8 +65,8 @@ static const DC_FUNCTIONS MFDRV_Funcs = MFDRV_PaintRgn, /* pPaintRgn */ MFDRV_PatBlt, /* pPatBlt */ MFDRV_Pie, /* pPie */ - NULL, /* pPolyBezier */ - NULL, /* pPolyBezierTo */ + MFDRV_PolyBezier, /* pPolyBezier */ + MFDRV_PolyBezierTo, /* pPolyBezierTo */ NULL, /* pPolyDraw */ MFDRV_PolyPolygon, /* pPolyPolygon */ NULL, /* pPolyPolyline */ diff --git a/graphics/painting.c b/graphics/painting.c index 54a0190da9d..049583ee587 100644 --- a/graphics/painting.c +++ b/graphics/painting.c @@ -1,8 +1,9 @@ /* - * Misc. graphics operations + * GDI drawing functions. * * Copyright 1993, 1994 Alexandre Julliard * Copyright 1997 Bertho A. Stultiens + * 1999 Huw D M Davies */ #include @@ -100,7 +101,7 @@ BOOL WINAPI MoveToEx( HDC hdc, INT x, INT y, LPPOINT pt ) if(dc->funcs->pMoveToEx) return dc->funcs->pMoveToEx(dc,x,y,pt); - return TRUE; + return FALSE; } @@ -125,12 +126,13 @@ BOOL WINAPI Arc( HDC hdc, INT left, INT top, INT right, INT xend, INT yend ) { DC * dc = DC_GetDCPtr( hdc ); - - if(dc && PATH_IsPathOpen(dc->w.path)) + if(!dc) return FALSE; + + if(PATH_IsPathOpen(dc->w.path)) return PATH_Arc(hdc, left, top, right, bottom, xstart, ystart, xend, yend); - return dc && dc->funcs->pArc && + return dc->funcs->pArc && dc->funcs->pArc(dc,left,top,right,bottom,xstart,ystart,xend,yend); } @@ -145,7 +147,6 @@ BOOL WINAPI ArcTo( HDC hdc, { BOOL result; DC * dc = DC_GetDCPtr( hdc ); - if(!dc) return FALSE; if(dc->funcs->pArcTo) @@ -200,8 +201,14 @@ BOOL WINAPI Pie( HDC hdc, INT left, INT top, INT xend, INT yend ) { DC * dc = DC_GetDCPtr( hdc ); - - return dc && dc->funcs->pPie && + if(!dc) return FALSE; + + if(PATH_IsPathOpen(dc->w.path)) { + FIXME("-> Path: stub\n"); + return FALSE; + } + + return dc->funcs->pPie && dc->funcs->pPie(dc,left,top,right,bottom,xstart,ystart,xend,yend); } @@ -225,8 +232,14 @@ BOOL WINAPI Chord( HDC hdc, INT left, INT top, INT xend, INT yend ) { DC * dc = DC_GetDCPtr( hdc ); + if(!dc) return FALSE; + + if(PATH_IsPathOpen(dc->w.path)) { + FIXME("-> Path: stub\n"); + return FALSE; + } - return dc && dc->funcs->pChord && + return dc->funcs->pChord && dc->funcs->pChord(dc,left,top,right,bottom,xstart,ystart,xend,yend); } @@ -248,8 +261,14 @@ BOOL WINAPI Ellipse( HDC hdc, INT left, INT top, INT right, INT bottom ) { DC * dc = DC_GetDCPtr( hdc ); + if(!dc) return FALSE; + + if(PATH_IsPathOpen(dc->w.path)) { + FIXME("-> Path: stub\n"); + return FALSE; + } - return dc && dc->funcs->pEllipse && + return dc->funcs->pEllipse && dc->funcs->pEllipse(dc,left,top,right,bottom); } @@ -271,11 +290,12 @@ BOOL WINAPI Rectangle( HDC hdc, INT left, INT top, INT right, INT bottom ) { DC * dc = DC_GetDCPtr( hdc ); - - if(dc && PATH_IsPathOpen(dc->w.path)) + if(!dc) return FALSE; + + if(PATH_IsPathOpen(dc->w.path)) return PATH_Rectangle(hdc, left, top, right, bottom); - return dc && dc->funcs->pRectangle && + return dc->funcs->pRectangle && dc->funcs->pRectangle(dc,left,top,right,bottom); } @@ -296,16 +316,16 @@ BOOL16 WINAPI RoundRect16( HDC16 hdc, INT16 left, INT16 top, INT16 right, BOOL WINAPI RoundRect( HDC hdc, INT left, INT top, INT right, INT bottom, INT ell_width, INT ell_height ) { - - if(ell_width == 0 || ell_height == 0) /* Just an optimization */ - return Rectangle(hdc, left, top, right, bottom); - - else { - DC * dc = DC_GetDCPtr( hdc ); + DC * dc = DC_GetDCPtr( hdc ); + if(!dc) return FALSE; - return dc && dc->funcs->pRoundRect && - dc->funcs->pRoundRect(dc,left,top,right,bottom,ell_width,ell_height); + if(PATH_IsPathOpen(dc->w.path)) { + FIXME("-> Path: stub\n"); + return FALSE; } + + return dc->funcs->pRoundRect && + dc->funcs->pRoundRect(dc,left,top,right,bottom,ell_width,ell_height); } /*********************************************************************** @@ -599,8 +619,12 @@ BOOL16 WINAPI Polyline16( HDC16 hdc, const POINT16* pt, INT16 count ) BOOL WINAPI Polyline( HDC hdc, const POINT* pt, INT count ) { DC * dc = DC_GetDCPtr( hdc ); + if(!dc) return FALSE; + + if(PATH_IsPathOpen(dc->w.path)) + return PATH_Polyline(hdc, pt, count); - return dc && dc->funcs->pPolyline && + return dc->funcs->pPolyline && dc->funcs->pPolyline(dc,pt,count); } @@ -614,7 +638,10 @@ BOOL WINAPI PolylineTo( HDC hdc, const POINT* pt, DWORD cCount ) if(!dc) return FALSE; - if(dc->funcs->pPolylineTo) + if(PATH_IsPathOpen(dc->w.path)) + ret = PATH_PolylineTo(hdc, pt, cCount); + + else if(dc->funcs->pPolylineTo) ret = dc->funcs->pPolylineTo(dc, pt, cCount); else { /* do it using Polyline */ @@ -659,8 +686,12 @@ BOOL16 WINAPI Polygon16( HDC16 hdc, const POINT16* pt, INT16 count ) BOOL WINAPI Polygon( HDC hdc, const POINT* pt, INT count ) { DC * dc = DC_GetDCPtr( hdc ); + if(!dc) return FALSE; + + if(PATH_IsPathOpen(dc->w.path)) + return PATH_Polygon(hdc, pt, count); - return dc && dc->funcs->pPolygon && + return dc->funcs->pPolygon && dc->funcs->pPolygon(dc,pt,count); } @@ -699,8 +730,12 @@ BOOL WINAPI PolyPolygon( HDC hdc, const POINT* pt, const INT* counts, UINT polygons ) { DC * dc = DC_GetDCPtr( hdc ); + if(!dc) return FALSE; + + if(PATH_IsPathOpen(dc->w.path)) + return PATH_PolyPolygon(hdc, pt, counts, polygons); - return dc && dc->funcs->pPolyPolygon && + return dc->funcs->pPolyPolygon && dc->funcs->pPolyPolygon(dc,pt,counts,polygons); } @@ -711,8 +746,12 @@ BOOL WINAPI PolyPolyline( HDC hdc, const POINT* pt, const DWORD* counts, DWORD polylines ) { DC * dc = DC_GetDCPtr( hdc ); + if(!dc) return FALSE; - return dc && dc->funcs->pPolyPolyline && + if(PATH_IsPathOpen(dc->w.path)) + return PATH_PolyPolyline(hdc, pt, counts, polylines); + + return dc->funcs->pPolyPolyline && dc->funcs->pPolyPolyline(dc,pt,counts,polylines); } @@ -803,9 +842,27 @@ BOOL16 WINAPI PolyBezierTo16( HDC16 hDc, const POINT16* lppt, INT16 cPoints ) BOOL WINAPI PolyBezier( HDC hdc, const POINT* lppt, DWORD cPoints ) { DC * dc = DC_GetDCPtr( hdc ); + if(!dc) return FALSE; + + if(PATH_IsPathOpen(dc->w.path)) + return PATH_PolyBezier(hdc, lppt, cPoints); - return dc && dc->funcs->pPolyBezier && - dc->funcs->pPolyBezier(dc, lppt, cPoints); + if(dc->funcs->pPolyBezier) + return dc->funcs->pPolyBezier(dc, lppt, cPoints); + + /* We'll convert it into line segments and draw them using Polyline */ + { + POINT *Pts; + INT nOut; + BOOL ret; + + Pts = GDI_Bezier( lppt, cPoints, &nOut ); + if(!Pts) return FALSE; + TRACE("Pts = %p, no = %d\n", Pts, nOut); + ret = Polyline( dc->hSelf, Pts, nOut ); + HeapFree( GetProcessHeap(), 0, Pts ); + return ret; + } } /****************************************************************************** @@ -828,10 +885,18 @@ BOOL WINAPI PolyBezierTo( HDC hdc, const POINT* lppt, DWORD cPoints ) if(PATH_IsPathOpen(dc->w.path)) ret = PATH_PolyBezierTo(hdc, lppt, cPoints); - else - ret = dc->funcs->pPolyBezierTo && - dc->funcs->pPolyBezierTo(dc, lppt, cPoints); - + else if(dc->funcs->pPolyBezierTo) + ret = dc->funcs->pPolyBezierTo(dc, lppt, cPoints); + else { /* We'll do it using PolyBezier */ + POINT *pt; + pt = HeapAlloc( GetProcessHeap(), 0, sizeof(POINT) * (cPoints + 1) ); + if(!pt) return FALSE; + pt[0].x = dc->w.CursPosX; + pt[0].y = dc->w.CursPosY; + memcpy(pt + 1, lppt, sizeof(POINT) * cPoints); + ret = PolyBezier(dc->hSelf, pt, cPoints+1); + HeapFree( GetProcessHeap(), 0, pt ); + } if(ret) { dc->w.CursPosX = lppt[cPoints-1].x; dc->w.CursPosY = lppt[cPoints-1].y; @@ -860,3 +925,198 @@ BOOL WINAPI PolyDraw(HDC hdc, const POINT *lppt, const BYTE *lpbTypes, FIXME("PolyDraw, stub\n"); return 0; } + +/****************************************************************** + * + * *Very* simple bezier drawing code, + * + * It uses a recursive algorithm to divide the curve in a series + * of straight line segements. Not ideal but for me sufficient. + * If you are in need for something better look for some incremental + * algorithm. + * + * 7 July 1998 Rein Klazes + */ + + /* + * some macro definitions for bezier drawing + * + * to avoid trucation errors the coordinates are + * shifted upwards. When used in drawing they are + * shifted down again, including correct rounding + * and avoiding floating point arithmatic + * 4 bits should allow 27 bits coordinates which I saw + * somewere in the win32 doc's + * + */ + +#define BEZIERSHIFTBITS 4 +#define BEZIERSHIFTUP(x) ((x)<>BEZIERSHIFTBITS) +/* maximum depth of recursion */ +#define BEZIERMAXDEPTH 8 + +/* size of array to store points on */ +/* enough for one curve */ +#define BEZIER_INITBUFSIZE (150) + +/* calculate Bezier average, in this case the middle + * correctly rounded... + * */ + +#define BEZIERMIDDLE(Mid, P1, P2) \ + (Mid).x=((P1).x+(P2).x + 1)/2;\ + (Mid).y=((P1).y+(P2).y + 1)/2; + +/********************************************************** +* BezierCheck helper function to check +* that recursion can be terminated +* Points[0] and Points[3] are begin and endpoint +* Points[1] and Points[2] are control points +* level is the recursion depth +* returns true if the recusion can be terminated +*/ +static BOOL BezierCheck( int level, POINT *Points) +{ + INT dx, dy; + dx=Points[3].x-Points[0].x; + dy=Points[3].y-Points[0].y; + if(abs(dy)<=abs(dx)){/* shallow line */ + /* check that control points are between begin and end */ + if(Points[1].x < Points[0].x){ + if(Points[1].x < Points[3].x) + return FALSE; + }else + if(Points[1].x > Points[3].x) + return FALSE; + if(Points[2].x < Points[0].x){ + if(Points[2].x < Points[3].x) + return FALSE; + }else + if(Points[2].x > Points[3].x) + return FALSE; + dx=BEZIERSHIFTDOWN(dx); + if(!dx) return TRUE; + if(abs(Points[1].y-Points[0].y-(dy/dx)* + BEZIERSHIFTDOWN(Points[1].x-Points[0].x)) > BEZIERPIXEL || + abs(Points[2].y-Points[0].y-(dy/dx)* + BEZIERSHIFTDOWN(Points[2].x-Points[0].x)) > BEZIERPIXEL ) + return FALSE; + else + return TRUE; + }else{ /* steep line */ + /* check that control points are between begin and end */ + if(Points[1].y < Points[0].y){ + if(Points[1].y < Points[3].y) + return FALSE; + }else + if(Points[1].y > Points[3].y) + return FALSE; + if(Points[2].y < Points[0].y){ + if(Points[2].y < Points[3].y) + return FALSE; + }else + if(Points[2].y > Points[3].y) + return FALSE; + dy=BEZIERSHIFTDOWN(dy); + if(!dy) return TRUE; + if(abs(Points[1].x-Points[0].x-(dx/dy)* + BEZIERSHIFTDOWN(Points[1].y-Points[0].y)) > BEZIERPIXEL || + abs(Points[2].x-Points[0].x-(dx/dy)* + BEZIERSHIFTDOWN(Points[2].y-Points[0].y)) > BEZIERPIXEL ) + return FALSE; + else + return TRUE; + } +} + +/* Helper for GDI_Bezier. + * Just handles one Bezier, so Points should point to four POINTs + */ +static void GDI_InternalBezier( POINT *Points, POINT **PtsOut, INT *dwOut, + INT *nPtsOut, INT level ) +{ + if(*nPtsOut == *dwOut) { + *dwOut *= 2; + *PtsOut = HeapReAlloc( GetProcessHeap(), 0, *PtsOut, + *dwOut * sizeof(POINT) ); + } + + if(!level || BezierCheck(level, Points)) { + if(*nPtsOut == 0) { + (*PtsOut)[0].x = BEZIERSHIFTDOWN(Points[0].x); + (*PtsOut)[0].y = BEZIERSHIFTDOWN(Points[0].y); + *nPtsOut = 1; + } + (*PtsOut)[*nPtsOut].x = BEZIERSHIFTDOWN(Points[3].x); + (*PtsOut)[*nPtsOut].y = BEZIERSHIFTDOWN(Points[3].y); + (*nPtsOut) ++; + } else { + POINT Points2[4]; /* for the second recursive call */ + Points2[3]=Points[3]; + BEZIERMIDDLE(Points2[2], Points[2], Points[3]); + BEZIERMIDDLE(Points2[0], Points[1], Points[2]); + BEZIERMIDDLE(Points2[1],Points2[0],Points2[2]); + + BEZIERMIDDLE(Points[1], Points[0], Points[1]); + BEZIERMIDDLE(Points[2], Points[1], Points2[0]); + BEZIERMIDDLE(Points[3], Points[2], Points2[1]); + + Points2[0]=Points[3]; + + /* do the two halves */ + GDI_InternalBezier(Points, PtsOut, dwOut, nPtsOut, level-1); + GDI_InternalBezier(Points2, PtsOut, dwOut, nPtsOut, level-1); + } +} + + + +/*********************************************************************** + * GDI_Bezier [INTERNAL] + * Calculate line segments that approximate -what microsoft calls- a bezier + * curve. + * The routine recursively divides the curve in two parts until a straight + * line can be drawn + * + * PARAMS + * + * Points [I] Ptr to count POINTs which are the end and control points + * of the set of Bezier curves to flatten. + * count [I] Number of Points. Must be 3n+1. + * nPtsOut [O] Will contain no of points that have been produced (i.e. no. of + * lines+1). + * + * RETURNS + * + * Ptr to an array of POINTs that contain the lines that approximinate the + * Beziers. The array is allocated on the process heap and it is the caller's + * responsibility to HeapFree it. [this is not a particularly nice interface + * but since we can't know in advance how many points will generate, the + * alternative would be to call the function twice, once to determine the size + * and a second time to do the work - I decided this was too much of a pain]. + */ +POINT *GDI_Bezier( const POINT *Points, INT count, INT *nPtsOut ) +{ + POINT *out; + INT Bezier, dwOut = BEZIER_INITBUFSIZE, i; + + if((count - 1) % 3 != 0) { + ERR("Invalid no. of points\n"); + return NULL; + } + *nPtsOut = 0; + out = HeapAlloc( GetProcessHeap(), 0, dwOut * sizeof(POINT)); + for(Bezier = 0; Bezier < (count-1)/3; Bezier++) { + POINT ptBuf[4]; + memcpy(ptBuf, Points + Bezier * 3, sizeof(POINT) * 4); + for(i = 0; i < 4; i++) { + ptBuf[i].x = BEZIERSHIFTUP(ptBuf[i].x); + ptBuf[i].y = BEZIERSHIFTUP(ptBuf[i].y); + } + GDI_InternalBezier( ptBuf, &out, &dwOut, nPtsOut, BEZIERMAXDEPTH ); + } + TRACE("Produced %d points\n", *nPtsOut); + return out; +} diff --git a/graphics/path.c b/graphics/path.c index 43d19d3c5cb..d875f476cc0 100644 --- a/graphics/path.c +++ b/graphics/path.c @@ -2,6 +2,7 @@ * Graphics paths (BeginPath, EndPath etc.) * * Copyright 1997, 1998 Martin Boehme + * 1999 Huw D M Davies */ #include @@ -903,6 +904,7 @@ BOOL PATH_PolyBezierTo(HDC hdc, const POINT *pts, DWORD cbPoints) if(!PATH_AddEntry(pPath, &pt, PT_MOVETO)) return FALSE; } + for(i = 0; i < cbPoints; i++) { pt = pts[i]; if(!LPtoDP(hdc, &pt, 1)) @@ -912,10 +914,217 @@ BOOL PATH_PolyBezierTo(HDC hdc, const POINT *pts, DWORD cbPoints) return TRUE; } +BOOL PATH_PolyBezier(HDC hdc, const POINT *pts, DWORD cbPoints) +{ + GdiPath *pPath; + POINT pt; + INT i; + + if(!PATH_GetPathFromHDC(hdc, &pPath)) + return FALSE; + + /* Check that path is open */ + if(pPath->state!=PATH_Open) + return FALSE; + + for(i = 0; i < cbPoints; i++) { + pt = pts[i]; + if(!LPtoDP(hdc, &pt, 1)) + return FALSE; + PATH_AddEntry(pPath, &pt, (i == 0) ? PT_MOVETO : PT_BEZIERTO); + } + return TRUE; +} + +BOOL PATH_Polyline(HDC hdc, const POINT *pts, DWORD cbPoints) +{ + GdiPath *pPath; + POINT pt; + INT i; + + if(!PATH_GetPathFromHDC(hdc, &pPath)) + return FALSE; + + /* Check that path is open */ + if(pPath->state!=PATH_Open) + return FALSE; + + for(i = 0; i < cbPoints; i++) { + pt = pts[i]; + if(!LPtoDP(hdc, &pt, 1)) + return FALSE; + PATH_AddEntry(pPath, &pt, (i == 0) ? PT_MOVETO : PT_LINETO); + } + return TRUE; +} + +BOOL PATH_PolylineTo(HDC hdc, const POINT *pts, DWORD cbPoints) +{ + GdiPath *pPath; + POINT pt; + INT i; + + if(!PATH_GetPathFromHDC(hdc, &pPath)) + return FALSE; + + /* Check that path is open */ + if(pPath->state!=PATH_Open) + return FALSE; + + /* Add a PT_MOVETO if necessary */ + if(pPath->newStroke) + { + pPath->newStroke=FALSE; + if(!GetCurrentPositionEx(hdc, &pt) || + !LPtoDP(hdc, &pt, 1)) + return FALSE; + if(!PATH_AddEntry(pPath, &pt, PT_MOVETO)) + return FALSE; + } + + for(i = 0; i < cbPoints; i++) { + pt = pts[i]; + if(!LPtoDP(hdc, &pt, 1)) + return FALSE; + PATH_AddEntry(pPath, &pt, PT_LINETO); + } + + return TRUE; +} + + +BOOL PATH_Polygon(HDC hdc, const POINT *pts, DWORD cbPoints) +{ + GdiPath *pPath; + POINT pt; + INT i; + + if(!PATH_GetPathFromHDC(hdc, &pPath)) + return FALSE; + + /* Check that path is open */ + if(pPath->state!=PATH_Open) + return FALSE; + + for(i = 0; i < cbPoints; i++) { + pt = pts[i]; + if(!LPtoDP(hdc, &pt, 1)) + return FALSE; + PATH_AddEntry(pPath, &pt, (i == 0) ? PT_MOVETO : + ((i == cbPoints-1) ? PT_LINETO | PT_CLOSEFIGURE : + PT_LINETO)); + } + return TRUE; +} + +BOOL PATH_PolyPolygon( HDC hdc, const POINT* pts, const INT* counts, + UINT polygons ) +{ + GdiPath *pPath; + POINT pt, startpt; + INT poly, point, i; + + if(!PATH_GetPathFromHDC(hdc, &pPath)) + return FALSE; + + /* Check that path is open */ + if(pPath->state!=PATH_Open) + return FALSE; + + for(i = 0, poly = 0; poly < polygons; poly++) { + for(point = 0; point < counts[poly]; point++, i++) { + pt = pts[i]; + if(!LPtoDP(hdc, &pt, 1)) + return FALSE; + if(point == 0) startpt = pt; + PATH_AddEntry(pPath, &pt, (point == 0) ? PT_MOVETO : PT_LINETO); + } + /* win98 adds an extra line to close the figure for some reason */ + PATH_AddEntry(pPath, &startpt, PT_LINETO | PT_CLOSEFIGURE); + } + return TRUE; +} + +BOOL PATH_PolyPolyline( HDC hdc, const POINT* pts, const DWORD* counts, + DWORD polylines ) +{ + GdiPath *pPath; + POINT pt; + INT poly, point, i; + + if(!PATH_GetPathFromHDC(hdc, &pPath)) + return FALSE; + + /* Check that path is open */ + if(pPath->state!=PATH_Open) + return FALSE; + + for(i = 0, poly = 0; poly < polylines; poly++) { + for(point = 0; point < counts[poly]; point++, i++) { + pt = pts[i]; + if(!LPtoDP(hdc, &pt, 1)) + return FALSE; + PATH_AddEntry(pPath, &pt, (point == 0) ? PT_MOVETO : PT_LINETO); + } + } + return TRUE; +} + /*********************************************************************** * Internal functions */ + +/* PATH_AddFlatBezier + * + */ +static BOOL PATH_AddFlatBezier(GdiPath *pPath, POINT *pt, BOOL closed) +{ + POINT *pts; + INT no, i; + + pts = GDI_Bezier( pt, 4, &no ); + if(!pts) return FALSE; + + for(i = 1; i < no; i++) + PATH_AddEntry(pPath, &pts[i], + (i == no-1 && closed) ? PT_LINETO | PT_CLOSEFIGURE : PT_LINETO); + HeapFree( GetProcessHeap(), 0, pts ); + return TRUE; +} + +/* PATH_FlattenPath + * + * Replaces Beziers with line segments + * + */ +static BOOL PATH_FlattenPath(GdiPath *pPath) +{ + GdiPath newPath; + INT srcpt; + + memset(&newPath, 0, sizeof(newPath)); + newPath.state = PATH_Open; + for(srcpt = 0; srcpt < pPath->numEntriesUsed; srcpt++) { + switch(pPath->pFlags[srcpt] & ~PT_CLOSEFIGURE) { + case PT_MOVETO: + case PT_LINETO: + PATH_AddEntry(&newPath, &pPath->pPoints[srcpt], + pPath->pFlags[srcpt]); + break; + case PT_BEZIERTO: + PATH_AddFlatBezier(&newPath, &pPath->pPoints[srcpt-1], + pPath->pFlags[srcpt+2] & PT_CLOSEFIGURE); + srcpt += 2; + break; + } + } + newPath.state = PATH_Closed; + PATH_AssignGdiPath(pPath, &newPath); + PATH_EmptyPath(&newPath); + return TRUE; +} + /* PATH_PathToRegion * * Creates a region from the specified path using the specified polygon @@ -933,7 +1142,9 @@ static BOOL PATH_PathToRegion(const GdiPath *pPath, INT nPolyFillMode, assert(pPath!=NULL); assert(pHrgn!=NULL); - + + PATH_FlattenPath(pPath); + /* FIXME: What happens when number of points is zero? */ /* First pass: Find out how many strokes there are in the path */ @@ -1008,6 +1219,7 @@ BOOL PATH_AddEntry(GdiPath *pPath, const POINT *pPoint, BYTE flags) /* FIXME: If newStroke is true, perhaps we want to check that we're * getting a PT_MOVETO */ + TRACE("(%ld,%ld) - %d\n", pPoint->x, pPoint->y, flags); /* Check that path is open */ if(pPath->state!=PATH_Open) @@ -1225,7 +1437,9 @@ BOOL16 WINAPI FlattenPath16(HDC16 hdc) BOOL WINAPI FlattenPath(HDC hdc) { DC *dc = DC_GetDCPtr( hdc ); - + GdiPath *pPath; + TRACE("%08x\n", hdc); + if(!dc) { SetLastError(ERROR_INVALID_HANDLE); return FALSE; @@ -1234,8 +1448,10 @@ BOOL WINAPI FlattenPath(HDC hdc) if(dc->funcs->pFlattenPath) return dc->funcs->pFlattenPath(dc); - FIXME("stub\n"); - return 0; + pPath = &dc->w.path; + if(pPath->state != PATH_Closed) + return FALSE; + return PATH_FlattenPath(pPath); } /******************************************************************* diff --git a/graphics/ttydrv/graphics.c b/graphics/ttydrv/graphics.c index f2bff6a4787..e8ee74d08d5 100644 --- a/graphics/ttydrv/graphics.c +++ b/graphics/ttydrv/graphics.c @@ -140,16 +140,6 @@ BOOL TTYDRV_DC_Pie(DC *dc, INT left, INT top, INT right, INT bottom, } /*********************************************************************** - * TTYDRV_DC_PolyBezier - */ -BOOL TTYDRV_DC_PolyBezier(DC *dc, const POINT* BezierPoints, DWORD count) -{ - FIXME("(%p, %p, %lu): stub\n", dc, BezierPoints, count); - - return TRUE; -} - -/*********************************************************************** * TTYDRV_DC_Polygon */ BOOL TTYDRV_DC_Polygon(DC *dc, const POINT* pt, INT count) diff --git a/graphics/ttydrv/init.c b/graphics/ttydrv/init.c index efb03a37b20..7fb79bec1f3 100644 --- a/graphics/ttydrv/init.c +++ b/graphics/ttydrv/init.c @@ -63,7 +63,7 @@ static const DC_FUNCTIONS TTYDRV_DC_Driver = TTYDRV_DC_PaintRgn, /* pPaintRgn */ TTYDRV_DC_PatBlt, /* pPatBlt */ TTYDRV_DC_Pie, /* pPie */ - TTYDRV_DC_PolyBezier, /* pPolyBezier */ + NULL, /* pPolyBezier */ NULL, /* pPolyBezierTo */ NULL, /* pPolyDraw */ TTYDRV_DC_PolyPolygon, /* pPolyPolygon */ diff --git a/graphics/x11drv/graphics.c b/graphics/x11drv/graphics.c index 40cf348f86a..e97557338a9 100644 --- a/graphics/x11drv/graphics.c +++ b/graphics/x11drv/graphics.c @@ -1189,239 +1189,6 @@ X11DRV_ExtFloodFill( DC *dc, INT x, INT y, COLORREF color, return result; } -/****************************************************************** - * - * *Very* simple bezier drawing code, - * - * It uses a recursive algorithm to divide the curve in a series - * of straight line segements. Not ideal but for me sufficient. - * If you are in need for something better look for some incremental - * algorithm. - * - * 7 July 1998 Rein Klazes - */ - - /* - * some macro definitions for bezier drawing - * - * to avoid trucation errors the coordinates are - * shifted upwards. When used in drawing they are - * shifted down again, including correct rounding - * and avoiding floating point arithmatic - * 4 bits should allow 27 bits coordinates which I saw - * somewere in the win32 doc's - * - */ - -#define BEZIERSHIFTBITS 4 -#define BEZIERSHIFTUP(x) ((x)<>BEZIERSHIFTBITS) -/* maximum depth of recursion */ -#define BEZIERMAXDEPTH 8 - -/* size of array to store points on */ -/* enough for one curve */ -#define BEZMAXPOINTS (150) - -/* calculate Bezier average, in this case the middle - * correctly rounded... - * */ - -#define BEZIERMIDDLE(Mid, P1, P2) \ - (Mid).x=((P1).x+(P2).x + 1)/2;\ - (Mid).y=((P1).y+(P2).y + 1)/2; - -/********************************************************** -* BezierCheck helper function to check -* that recursion can be terminated -* Points[0] and Points[3] are begin and endpoint -* Points[1] and Points[2] are control points -* level is the recursion depth -* returns true if the recusion can be terminated -*/ -static BOOL BezierCheck( int level, POINT *Points) -{ - INT dx, dy; - dx=Points[3].x-Points[0].x; - dy=Points[3].y-Points[0].y; - if(ABS(dy)<=ABS(dx)){/* shallow line */ - /* check that control points are between begin and end */ - if(Points[1].x < Points[0].x){ - if(Points[1].x < Points[3].x) - return FALSE; - }else - if(Points[1].x > Points[3].x) - return FALSE; - if(Points[2].x < Points[0].x){ - if(Points[2].x < Points[3].x) - return FALSE; - }else - if(Points[2].x > Points[3].x) - return FALSE; - dx=BEZIERSHIFTDOWN(dx); - if(!dx) return TRUE; - if(abs(Points[1].y-Points[0].y-(dy/dx)* - BEZIERSHIFTDOWN(Points[1].x-Points[0].x)) > BEZIERPIXEL || - abs(Points[2].y-Points[0].y-(dy/dx)* - BEZIERSHIFTDOWN(Points[2].x-Points[0].x)) > BEZIERPIXEL ) - return FALSE; - else - return TRUE; - }else{ /* steep line */ - /* check that control points are between begin and end */ - if(Points[1].y < Points[0].y){ - if(Points[1].y < Points[3].y) - return FALSE; - }else - if(Points[1].y > Points[3].y) - return FALSE; - if(Points[2].y < Points[0].y){ - if(Points[2].y < Points[3].y) - return FALSE; - }else - if(Points[2].y > Points[3].y) - return FALSE; - dy=BEZIERSHIFTDOWN(dy); - if(!dy) return TRUE; - if(abs(Points[1].x-Points[0].x-(dx/dy)* - BEZIERSHIFTDOWN(Points[1].y-Points[0].y)) > BEZIERPIXEL || - abs(Points[2].x-Points[0].x-(dx/dy)* - BEZIERSHIFTDOWN(Points[2].y-Points[0].y)) > BEZIERPIXEL ) - return FALSE; - else - return TRUE; - } -} - -/*********************************************************************** - * X11DRV_Bezier - * Draw a -what microsoft calls- bezier curve - * The routine recursively devides the curve - * in two parts until a straight line can be drawn - * - * level recusion depth counted backwards - * dc device context - * Points array of begin(0), end(3) and control points(1 and 2) - * XPoints array with points calculated sofar - * *pIx nr points calculated sofar - * - */ -static void X11DRV_Bezier(int level, DC * dc, POINT *Points, - XPoint* xpoints, unsigned int* pIx) -{ - X11DRV_PDEVICE *physDev = (X11DRV_PDEVICE *)dc->physDev; - - if(*pIx == BEZMAXPOINTS){ - if (X11DRV_SetupGCForPen( dc )) - TSXDrawLines( display, physDev->drawable, physDev->gc, - xpoints, *pIx, CoordModeOrigin ); - *pIx=0; - } - if(!level || BezierCheck(level, Points)) { - if(*pIx == 0){ - xpoints[*pIx].x= dc->w.DCOrgX + BEZIERSHIFTDOWN(Points[0].x); - xpoints[*pIx].y= dc->w.DCOrgY + BEZIERSHIFTDOWN(Points[0].y); - *pIx=1; - } - xpoints[*pIx].x= dc->w.DCOrgX + BEZIERSHIFTDOWN(Points[3].x); - xpoints[*pIx].y= dc->w.DCOrgY + BEZIERSHIFTDOWN(Points[3].y); - (*pIx) ++; - } else { - POINT Points2[4]; /* for the second recursive call */ - Points2[3]=Points[3]; - BEZIERMIDDLE(Points2[2], Points[2], Points[3]); - BEZIERMIDDLE(Points2[0], Points[1], Points[2]); - BEZIERMIDDLE(Points2[1],Points2[0],Points2[2]); - - BEZIERMIDDLE(Points[1], Points[0], Points[1]); - BEZIERMIDDLE(Points[2], Points[1], Points2[0]); - BEZIERMIDDLE(Points[3], Points[2], Points2[1]); - - Points2[0]=Points[3]; - - /* do the two halves */ - X11DRV_Bezier(level-1, dc, Points, xpoints, pIx); - X11DRV_Bezier(level-1, dc, Points2, xpoints, pIx); - } -} - - - - -/*********************************************************************** - * X11DRV_InternalPolyBezier - * Implement functionality for PolyBezier and PolyBezierTo - * calls. - * [i] dc pointer to device context - * [i] start, first point in curve - * [i] BezierPoints , array of point filled with rest of the points - * [i] count, number of points in BezierPoints, must be a - * multiple of 3. - */ -static BOOL -X11DRV_InternalPolyBezier(DC *dc, POINT start, const POINT* BezierPoints, -DWORD count) -{ - POINT Points[4]; - int i; - unsigned int ix=0; - XPoint* xpoints; - X11DRV_PDEVICE *physDev = (X11DRV_PDEVICE *)dc->physDev; - - TRACE("dc=%p count=%ld %ld,%ld - %ld,%ld - %ld,%ld - %ld,%ld\n", - dc, count, - start.x, start.y, - (BezierPoints+0)->x, (BezierPoints+0)->y, - (BezierPoints+1)->x, (BezierPoints+1)->y, - (BezierPoints+2)->x, (BezierPoints+2)->y); - if(!count || count % 3){/* paranoid */ - WARN(" bad value for count : %ld\n", count); - return FALSE; - } - xpoints=(XPoint*) xmalloc( sizeof(XPoint)*BEZMAXPOINTS); - start.x=BEZIERSHIFTUP(XLPTODP(dc,start.x)); - start.y=BEZIERSHIFTUP(YLPTODP(dc,start.y)); - while(count){ - Points[0]=start; - for(i=1;i<4;i++) { - Points[i].x= BEZIERSHIFTUP(XLPTODP(dc,BezierPoints->x)); - Points[i].y= BEZIERSHIFTUP(YLPTODP(dc,BezierPoints->y)); - BezierPoints++; - } - start=Points[3]; - X11DRV_Bezier(BEZIERMAXDEPTH , dc, Points, xpoints, &ix ); - count -=3; - } - if (ix && X11DRV_SetupGCForPen( dc )) - TSXDrawLines( display, physDev->drawable, physDev->gc, - xpoints, ix, CoordModeOrigin ); - free(xpoints); - return TRUE; -} - -/********************************************************************** - * X11DRV_PolyBezier - */ -BOOL -X11DRV_PolyBezier(DC *dc, const POINT *Points, DWORD count) -{ - return X11DRV_InternalPolyBezier(dc, Points[0], Points+1, count-1); -} - -/********************************************************************** - * X11DRV_PolyBezierTo - */ -BOOL -X11DRV_PolyBezierTo(DC *dc, const POINT *Points, DWORD count) -{ - POINT pt; - - pt.x = dc->w.CursPosX; - pt.y = dc->w.CursPosY; - return X11DRV_InternalPolyBezier(dc, pt, Points, count); -} - /********************************************************************** * X11DRV_SetBkColor */ diff --git a/graphics/x11drv/init.c b/graphics/x11drv/init.c index ad33c947765..064c30745db 100644 --- a/graphics/x11drv/init.c +++ b/graphics/x11drv/init.c @@ -78,8 +78,8 @@ static const DC_FUNCTIONS X11DRV_Funcs = X11DRV_PaintRgn, /* pPaintRgn */ X11DRV_PatBlt, /* pPatBlt */ X11DRV_Pie, /* pPie */ - X11DRV_PolyBezier, /* pPolyBezier */ - X11DRV_PolyBezierTo, /* pPolyBezierTo */ + NULL, /* pPolyBezier */ + NULL, /* pPolyBezierTo */ NULL, /* pPolyDraw */ X11DRV_PolyPolygon, /* pPolyPolygon */ X11DRV_PolyPolyline, /* pPolyPolyline */ diff --git a/include/gdi.h b/include/gdi.h index f456d5b003b..dad68163a78 100644 --- a/include/gdi.h +++ b/include/gdi.h @@ -467,4 +467,8 @@ extern BOOL DRIVER_RegisterDriver( LPCSTR name, const DC_FUNCTIONS *funcs ); extern const DC_FUNCTIONS *DRIVER_FindDriver( LPCSTR name ); extern BOOL DRIVER_UnregisterDriver( LPCSTR name ); extern BOOL DRIVER_GetDriverName( LPCSTR device, LPSTR driver, DWORD size ); + +extern POINT *GDI_Bezier( const POINT *Points, INT count, INT *nPtsOut ); + + #endif /* __WINE_GDI_H */ diff --git a/include/metafiledrv.h b/include/metafiledrv.h index 8542c72b205..91579096773 100644 --- a/include/metafiledrv.h +++ b/include/metafiledrv.h @@ -74,6 +74,8 @@ extern BOOL MFDRV_PatBlt( DC *dc, INT left, INT top, INT width, INT height, extern BOOL MFDRV_Pie( DC *dc, INT left, INT top, INT right, INT bottom, INT xstart, INT ystart, INT xend, INT yend ); +extern BOOL MFDRV_PolyBezier( DC *dc, const POINT* pt, DWORD count ); +extern BOOL MFDRV_PolyBezierTo( DC *dc, const POINT* pt, DWORD count ); extern BOOL MFDRV_PolyPolygon( DC *dc, const POINT* pt, const INT* counts, UINT polygons); extern BOOL MFDRV_Polygon( DC *dc, const POINT* pt, INT count ); diff --git a/include/path.h b/include/path.h index 9b34e718174..c75d3568a0a 100644 --- a/include/path.h +++ b/include/path.h @@ -51,6 +51,14 @@ extern BOOL PATH_Ellipse(HDC hdc, INT x1, INT y1, extern BOOL PATH_Arc(HDC hdc, INT x1, INT y1, INT x2, INT y2, INT xStart, INT yStart, INT xEnd, INT yEnd); extern BOOL PATH_PolyBezierTo(HDC hdc, const POINT *pt, DWORD cbCount); +extern BOOL PATH_PolyBezier(HDC hdc, const POINT *pt, DWORD cbCount); +extern BOOL PATH_PolylineTo(HDC hdc, const POINT *pt, DWORD cbCount); +extern BOOL PATH_Polyline(HDC hdc, const POINT *pt, DWORD cbCount); +extern BOOL PATH_Polygon(HDC hdc, const POINT *pt, DWORD cbCount); +extern BOOL PATH_PolyPolyline(HDC hdc, const POINT *pt, const DWORD *counts, + DWORD polylines); +extern BOOL PATH_PolyPolygon(HDC hdc, const POINT *pt, const INT *counts, + UINT polygons); #endif /* __WINE_PATH_H */ diff --git a/include/ttydrv.h b/include/ttydrv.h index 49497780777..4eef6182c66 100644 --- a/include/ttydrv.h +++ b/include/ttydrv.h @@ -86,7 +86,6 @@ extern HANDLE TTYDRV_DC_LoadOEMResource(WORD resid, WORD type); extern BOOL TTYDRV_DC_PaintRgn(struct tagDC *dc, HRGN hrgn); extern BOOL TTYDRV_DC_PatBlt(struct tagDC *dc, INT left, INT top, INT width, INT height, DWORD rop); extern BOOL TTYDRV_DC_Pie(struct tagDC *dc, INT left, INT top, INT right, INT bottom, INT xstart, INT ystart, INT xend, INT yend); -extern BOOL TTYDRV_DC_PolyBezier(struct tagDC *dc, const POINT* BezierPoints, DWORD count); extern BOOL TTYDRV_DC_Polygon(struct tagDC *dc, const POINT* pt, INT count); extern BOOL TTYDRV_DC_Polyline(struct tagDC *dc, const POINT* pt, INT count); extern BOOL TTYDRV_DC_PolyPolygon(struct tagDC *dc, const POINT* pt, const INT* counts, UINT polygons); diff --git a/include/x11drv.h b/include/x11drv.h index 4fdf6a3fa4d..a3c9c4012ce 100644 --- a/include/x11drv.h +++ b/include/x11drv.h @@ -125,10 +125,6 @@ extern COLORREF X11DRV_SetPixel( struct tagDC *dc, INT x, INT y, extern COLORREF X11DRV_GetPixel( struct tagDC *dc, INT x, INT y); extern BOOL X11DRV_PaintRgn( struct tagDC *dc, HRGN hrgn ); extern BOOL X11DRV_Polyline( struct tagDC *dc,const POINT* pt,INT count); -extern BOOL X11DRV_PolyBezier( struct tagDC *dc, const POINT* lppt, - DWORD cPoints); -extern BOOL X11DRV_PolyBezierTo( struct tagDC *dc, const POINT* lppt, - DWORD cPoints); extern BOOL X11DRV_Polygon( struct tagDC *dc, const POINT* pt, INT count ); extern BOOL X11DRV_PolyPolygon( struct tagDC *dc, const POINT* pt, const INT* counts, UINT polygons); -- 2.11.4.GIT