Commit b8e94b61 authored by Huw D M Davies's avatar Huw D M Davies Committed by Alexandre Julliard

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.
parent de73965d
......@@ -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;
}
......@@ -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 */
......
......@@ -2,6 +2,7 @@
* Graphics paths (BeginPath, EndPath etc.)
*
* Copyright 1997, 1998 Martin Boehme
* 1999 Huw D M Davies
*/
#include <assert.h>
......@@ -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);
}
/*******************************************************************
......
......@@ -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)
......
......@@ -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 */
......
......@@ -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)
#define BEZIERPIXEL BEZIERSHIFTUP(1)
#define BEZIERSHIFTDOWN(x) (((x)+(1<<(BEZIERSHIFTBITS-1)))>>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
*/
......
......@@ -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 */
......
......@@ -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 */
......@@ -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 );
......
......@@ -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 */
......@@ -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);
......
......@@ -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);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment