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.
oldstable
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));
}
/**********************************************************************
* 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_PatBlt, /* pPatBlt */
MFDRV_Pie, /* pPie */
NULL, /* pPolyBezier */
NULL, /* pPolyBezierTo */
MFDRV_PolyBezier, /* pPolyBezier */
MFDRV_PolyBezierTo, /* pPolyBezierTo */
NULL, /* pPolyDraw */
MFDRV_PolyPolygon, /* pPolyPolygon */
NULL, /* pPolyPolyline */

View File

@ -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 <string.h>
@ -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);
DC * dc = DC_GetDCPtr( hdc );
if(!dc) return FALSE;
else {
DC * dc = DC_GetDCPtr( hdc );
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;
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);
}
@ -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;
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);
}
@ -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;
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);
}
@ -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;
return dc && dc->funcs->pPolyBezier &&
dc->funcs->pPolyBezier(dc, lppt, cPoints);
if(PATH_IsPathOpen(dc->w.path))
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))
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)
#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.)
*
* 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);
}
/*******************************************************************

View File

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

View File

@ -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 */

View File

@ -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
*/

View File

@ -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 */

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 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 */

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,
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 );

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,
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 */

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_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);

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 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);