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:
parent
de73965d67
commit
b8e94b6119
@ -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;
|
||||||
|
}
|
||||||
|
@ -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 */
|
||||||
|
@ -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;
|
||||||
|
}
|
||||||
|
224
graphics/path.c
224
graphics/path.c
@ -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);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*******************************************************************
|
/*******************************************************************
|
||||||
|
@ -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
|
||||||
*/
|
*/
|
||||||
|
@ -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 */
|
||||||
|
@ -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
|
||||||
*/
|
*/
|
||||||
|
@ -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 */
|
||||||
|
@ -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 */
|
||||||
|
@ -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 );
|
||||||
|
@ -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 */
|
||||||
|
|
||||||
|
|
||||||
|
@ -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);
|
||||||
|
@ -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);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user