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.
This commit is contained in:
Huw D M Davies 1999-12-20 04:14:48 +00:00 committed by Alexandre Julliard
parent de73965d67
commit b8e94b6119
13 changed files with 553 additions and 289 deletions

View File

@ -379,3 +379,25 @@ MFDRV_SetTextColor( DC *dc, COLORREF color )
LOWORD(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;
}

View File

@ -65,8 +65,8 @@ static const DC_FUNCTIONS MFDRV_Funcs =
MFDRV_PaintRgn, /* pPaintRgn */ MFDRV_PaintRgn, /* pPaintRgn */
MFDRV_PatBlt, /* pPatBlt */ MFDRV_PatBlt, /* pPatBlt */
MFDRV_Pie, /* pPie */ MFDRV_Pie, /* pPie */
NULL, /* pPolyBezier */ MFDRV_PolyBezier, /* pPolyBezier */
NULL, /* pPolyBezierTo */ MFDRV_PolyBezierTo, /* pPolyBezierTo */
NULL, /* pPolyDraw */ NULL, /* pPolyDraw */
MFDRV_PolyPolygon, /* pPolyPolygon */ MFDRV_PolyPolygon, /* pPolyPolygon */
NULL, /* pPolyPolyline */ NULL, /* pPolyPolyline */

View File

@ -1,8 +1,9 @@
/* /*
* Misc. graphics operations * GDI drawing functions.
* *
* Copyright 1993, 1994 Alexandre Julliard * Copyright 1993, 1994 Alexandre Julliard
* Copyright 1997 Bertho A. Stultiens * Copyright 1997 Bertho A. Stultiens
* 1999 Huw D M Davies
*/ */
#include <string.h> #include <string.h>
@ -100,7 +101,7 @@ BOOL WINAPI MoveToEx( HDC hdc, INT x, INT y, LPPOINT pt )
if(dc->funcs->pMoveToEx) if(dc->funcs->pMoveToEx)
return dc->funcs->pMoveToEx(dc,x,y,pt); 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 ) INT xend, INT yend )
{ {
DC * dc = DC_GetDCPtr( hdc ); DC * dc = DC_GetDCPtr( hdc );
if(!dc) return FALSE;
if(dc && PATH_IsPathOpen(dc->w.path))
if(PATH_IsPathOpen(dc->w.path))
return PATH_Arc(hdc, left, top, right, bottom, xstart, ystart, xend, return PATH_Arc(hdc, left, top, right, bottom, xstart, ystart, xend,
yend); yend);
return dc && dc->funcs->pArc && return dc->funcs->pArc &&
dc->funcs->pArc(dc,left,top,right,bottom,xstart,ystart,xend,yend); dc->funcs->pArc(dc,left,top,right,bottom,xstart,ystart,xend,yend);
} }
@ -145,7 +147,6 @@ BOOL WINAPI ArcTo( HDC hdc,
{ {
BOOL result; BOOL result;
DC * dc = DC_GetDCPtr( hdc ); DC * dc = DC_GetDCPtr( hdc );
if(!dc) return FALSE; if(!dc) return FALSE;
if(dc->funcs->pArcTo) if(dc->funcs->pArcTo)
@ -200,8 +201,14 @@ BOOL WINAPI Pie( HDC hdc, INT left, INT top,
INT xend, INT yend ) INT xend, INT yend )
{ {
DC * dc = DC_GetDCPtr( hdc ); DC * dc = DC_GetDCPtr( hdc );
if(!dc) return FALSE;
return dc && dc->funcs->pPie &&
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); 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 ) INT xend, INT yend )
{ {
DC * dc = DC_GetDCPtr( hdc ); 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); 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 ) INT right, INT bottom )
{ {
DC * dc = DC_GetDCPtr( hdc ); 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); 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 ) INT right, INT bottom )
{ {
DC * dc = DC_GetDCPtr( hdc ); DC * dc = DC_GetDCPtr( hdc );
if(!dc) return FALSE;
if(dc && PATH_IsPathOpen(dc->w.path))
if(PATH_IsPathOpen(dc->w.path))
return PATH_Rectangle(hdc, left, top, right, bottom); 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); 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, BOOL WINAPI RoundRect( HDC hdc, INT left, INT top, INT right,
INT bottom, INT ell_width, INT ell_height ) INT bottom, INT ell_width, INT ell_height )
{ {
DC * dc = DC_GetDCPtr( hdc );
if(ell_width == 0 || ell_height == 0) /* Just an optimization */ if(!dc) return FALSE;
return Rectangle(hdc, left, top, right, bottom);
else { if(PATH_IsPathOpen(dc->w.path)) {
DC * dc = DC_GetDCPtr( hdc ); FIXME("-> Path: stub\n");
return FALSE;
return dc && dc->funcs->pRoundRect &&
dc->funcs->pRoundRect(dc,left,top,right,bottom,ell_width,ell_height);
} }
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 ) BOOL WINAPI Polyline( HDC hdc, const POINT* pt, INT count )
{ {
DC * dc = DC_GetDCPtr( hdc ); DC * dc = DC_GetDCPtr( hdc );
if(!dc) return FALSE;
return dc && dc->funcs->pPolyline && if(PATH_IsPathOpen(dc->w.path))
return PATH_Polyline(hdc, pt, count);
return dc->funcs->pPolyline &&
dc->funcs->pPolyline(dc,pt,count); 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) 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); ret = dc->funcs->pPolylineTo(dc, pt, cCount);
else { /* do it using Polyline */ 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 ) BOOL WINAPI Polygon( HDC hdc, const POINT* pt, INT count )
{ {
DC * dc = DC_GetDCPtr( hdc ); DC * dc = DC_GetDCPtr( hdc );
if(!dc) return FALSE;
return dc && dc->funcs->pPolygon && if(PATH_IsPathOpen(dc->w.path))
return PATH_Polygon(hdc, pt, count);
return dc->funcs->pPolygon &&
dc->funcs->pPolygon(dc,pt,count); dc->funcs->pPolygon(dc,pt,count);
} }
@ -699,8 +730,12 @@ BOOL WINAPI PolyPolygon( HDC hdc, const POINT* pt, const INT* counts,
UINT polygons ) UINT polygons )
{ {
DC * dc = DC_GetDCPtr( hdc ); DC * dc = DC_GetDCPtr( hdc );
if(!dc) return FALSE;
return dc && dc->funcs->pPolyPolygon && if(PATH_IsPathOpen(dc->w.path))
return PATH_PolyPolygon(hdc, pt, counts, polygons);
return dc->funcs->pPolyPolygon &&
dc->funcs->pPolyPolygon(dc,pt,counts,polygons); dc->funcs->pPolyPolygon(dc,pt,counts,polygons);
} }
@ -711,8 +746,12 @@ BOOL WINAPI PolyPolyline( HDC hdc, const POINT* pt, const DWORD* counts,
DWORD polylines ) DWORD polylines )
{ {
DC * dc = DC_GetDCPtr( hdc ); 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); 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 ) BOOL WINAPI PolyBezier( HDC hdc, const POINT* lppt, DWORD cPoints )
{ {
DC * dc = DC_GetDCPtr( hdc ); DC * dc = DC_GetDCPtr( hdc );
if(!dc) return FALSE;
return dc && dc->funcs->pPolyBezier && if(PATH_IsPathOpen(dc->w.path))
dc->funcs->pPolyBezier(dc, lppt, cPoints); return PATH_PolyBezier(hdc, 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)) if(PATH_IsPathOpen(dc->w.path))
ret = PATH_PolyBezierTo(hdc, lppt, cPoints); ret = PATH_PolyBezierTo(hdc, lppt, cPoints);
else else if(dc->funcs->pPolyBezierTo)
ret = dc->funcs->pPolyBezierTo && ret = dc->funcs->pPolyBezierTo(dc, lppt, cPoints);
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) { if(ret) {
dc->w.CursPosX = lppt[cPoints-1].x; dc->w.CursPosX = lppt[cPoints-1].x;
dc->w.CursPosY = lppt[cPoints-1].y; 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"); FIXME("PolyDraw, stub\n");
return 0; 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)
#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 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;
}

View File

@ -2,6 +2,7 @@
* Graphics paths (BeginPath, EndPath etc.) * Graphics paths (BeginPath, EndPath etc.)
* *
* Copyright 1997, 1998 Martin Boehme * Copyright 1997, 1998 Martin Boehme
* 1999 Huw D M Davies
*/ */
#include <assert.h> #include <assert.h>
@ -903,6 +904,7 @@ BOOL PATH_PolyBezierTo(HDC hdc, const POINT *pts, DWORD cbPoints)
if(!PATH_AddEntry(pPath, &pt, PT_MOVETO)) if(!PATH_AddEntry(pPath, &pt, PT_MOVETO))
return FALSE; return FALSE;
} }
for(i = 0; i < cbPoints; i++) { for(i = 0; i < cbPoints; i++) {
pt = pts[i]; pt = pts[i];
if(!LPtoDP(hdc, &pt, 1)) if(!LPtoDP(hdc, &pt, 1))
@ -912,10 +914,217 @@ BOOL PATH_PolyBezierTo(HDC hdc, const POINT *pts, DWORD cbPoints)
return TRUE; 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 * 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 /* PATH_PathToRegion
* *
* Creates a region from the specified path using the specified polygon * 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(pPath!=NULL);
assert(pHrgn!=NULL); assert(pHrgn!=NULL);
PATH_FlattenPath(pPath);
/* FIXME: What happens when number of points is zero? */ /* FIXME: What happens when number of points is zero? */
/* First pass: Find out how many strokes there are in the path */ /* 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 /* FIXME: If newStroke is true, perhaps we want to check that we're
* getting a PT_MOVETO * getting a PT_MOVETO
*/ */
TRACE("(%ld,%ld) - %d\n", pPoint->x, pPoint->y, flags);
/* Check that path is open */ /* Check that path is open */
if(pPath->state!=PATH_Open) if(pPath->state!=PATH_Open)
@ -1225,7 +1437,9 @@ BOOL16 WINAPI FlattenPath16(HDC16 hdc)
BOOL WINAPI FlattenPath(HDC hdc) BOOL WINAPI FlattenPath(HDC hdc)
{ {
DC *dc = DC_GetDCPtr( hdc ); DC *dc = DC_GetDCPtr( hdc );
GdiPath *pPath;
TRACE("%08x\n", hdc);
if(!dc) { if(!dc) {
SetLastError(ERROR_INVALID_HANDLE); SetLastError(ERROR_INVALID_HANDLE);
return FALSE; return FALSE;
@ -1234,8 +1448,10 @@ BOOL WINAPI FlattenPath(HDC hdc)
if(dc->funcs->pFlattenPath) if(dc->funcs->pFlattenPath)
return dc->funcs->pFlattenPath(dc); return dc->funcs->pFlattenPath(dc);
FIXME("stub\n"); pPath = &dc->w.path;
return 0; if(pPath->state != PATH_Closed)
return FALSE;
return PATH_FlattenPath(pPath);
} }
/******************************************************************* /*******************************************************************

View File

@ -139,16 +139,6 @@ BOOL TTYDRV_DC_Pie(DC *dc, INT left, INT top, INT right, INT bottom,
return TRUE; return TRUE;
} }
/***********************************************************************
* 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 * TTYDRV_DC_Polygon
*/ */

View File

@ -63,7 +63,7 @@ static const DC_FUNCTIONS TTYDRV_DC_Driver =
TTYDRV_DC_PaintRgn, /* pPaintRgn */ TTYDRV_DC_PaintRgn, /* pPaintRgn */
TTYDRV_DC_PatBlt, /* pPatBlt */ TTYDRV_DC_PatBlt, /* pPatBlt */
TTYDRV_DC_Pie, /* pPie */ TTYDRV_DC_Pie, /* pPie */
TTYDRV_DC_PolyBezier, /* pPolyBezier */ NULL, /* pPolyBezier */
NULL, /* pPolyBezierTo */ NULL, /* pPolyBezierTo */
NULL, /* pPolyDraw */ NULL, /* pPolyDraw */
TTYDRV_DC_PolyPolygon, /* pPolyPolygon */ TTYDRV_DC_PolyPolygon, /* pPolyPolygon */

View File

@ -1189,239 +1189,6 @@ X11DRV_ExtFloodFill( DC *dc, INT x, INT y, COLORREF color,
return result; 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 * X11DRV_SetBkColor
*/ */

View File

@ -78,8 +78,8 @@ static const DC_FUNCTIONS X11DRV_Funcs =
X11DRV_PaintRgn, /* pPaintRgn */ X11DRV_PaintRgn, /* pPaintRgn */
X11DRV_PatBlt, /* pPatBlt */ X11DRV_PatBlt, /* pPatBlt */
X11DRV_Pie, /* pPie */ X11DRV_Pie, /* pPie */
X11DRV_PolyBezier, /* pPolyBezier */ NULL, /* pPolyBezier */
X11DRV_PolyBezierTo, /* pPolyBezierTo */ NULL, /* pPolyBezierTo */
NULL, /* pPolyDraw */ NULL, /* pPolyDraw */
X11DRV_PolyPolygon, /* pPolyPolygon */ X11DRV_PolyPolygon, /* pPolyPolygon */
X11DRV_PolyPolyline, /* pPolyPolyline */ X11DRV_PolyPolyline, /* pPolyPolyline */

View File

@ -467,4 +467,8 @@ extern BOOL DRIVER_RegisterDriver( LPCSTR name, const DC_FUNCTIONS *funcs );
extern const DC_FUNCTIONS *DRIVER_FindDriver( LPCSTR name ); extern const DC_FUNCTIONS *DRIVER_FindDriver( LPCSTR name );
extern BOOL DRIVER_UnregisterDriver( LPCSTR name ); extern BOOL DRIVER_UnregisterDriver( LPCSTR name );
extern BOOL DRIVER_GetDriverName( LPCSTR device, LPSTR driver, DWORD size ); 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 */ #endif /* __WINE_GDI_H */

View File

@ -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, extern BOOL MFDRV_Pie( DC *dc, INT left, INT top, INT right,
INT bottom, INT xstart, INT ystart, INT xend, INT bottom, INT xstart, INT ystart, INT xend,
INT yend ); 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, extern BOOL MFDRV_PolyPolygon( DC *dc, const POINT* pt, const INT* counts,
UINT polygons); UINT polygons);
extern BOOL MFDRV_Polygon( DC *dc, const POINT* pt, INT count ); extern BOOL MFDRV_Polygon( DC *dc, const POINT* pt, INT count );

View File

@ -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, extern BOOL PATH_Arc(HDC hdc, INT x1, INT y1, INT x2, INT y2,
INT xStart, INT yStart, INT xEnd, INT yEnd); INT xStart, INT yStart, INT xEnd, INT yEnd);
extern BOOL PATH_PolyBezierTo(HDC hdc, const POINT *pt, DWORD cbCount); 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 */ #endif /* __WINE_PATH_H */

View File

@ -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_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_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_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_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_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); extern BOOL TTYDRV_DC_PolyPolygon(struct tagDC *dc, const POINT* pt, const INT* counts, UINT polygons);

View File

@ -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 COLORREF X11DRV_GetPixel( struct tagDC *dc, INT x, INT y);
extern BOOL X11DRV_PaintRgn( struct tagDC *dc, HRGN hrgn ); extern BOOL X11DRV_PaintRgn( struct tagDC *dc, HRGN hrgn );
extern BOOL X11DRV_Polyline( struct tagDC *dc,const POINT* pt,INT count); 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_Polygon( struct tagDC *dc, const POINT* pt, INT count );
extern BOOL X11DRV_PolyPolygon( struct tagDC *dc, const POINT* pt, extern BOOL X11DRV_PolyPolygon( struct tagDC *dc, const POINT* pt,
const INT* counts, UINT polygons); const INT* counts, UINT polygons);