Make the functions Pie, Chord, RoundRect, AngleArc, PolyDraw and

Ellipse work with an open path.
This commit is contained in:
Mark Dufour 2000-11-01 02:12:52 +00:00 committed by Alexandre Julliard
parent d0ff2ec08b
commit 704c67505d
3 changed files with 175 additions and 81 deletions

View File

@ -7,6 +7,8 @@
*/
#include <string.h>
#include <stdlib.h>
#include "dc.h"
#include "bitmap.h"
#include "heap.h"
@ -128,7 +130,7 @@ BOOL WINAPI Arc( HDC hdc, INT left, INT top, INT right,
if (dc)
{
if(PATH_IsPathOpen(dc->w.path))
ret = PATH_Arc(dc, left, top, right, bottom, xstart, ystart, xend, yend);
ret = PATH_Arc(dc, left, top, right, bottom, xstart, ystart, xend, yend,0);
else if (dc->funcs->pArc)
ret = dc->funcs->pArc(dc,left,top,right,bottom,xstart,ystart,xend,yend);
GDI_ReleaseObj( hdc );
@ -197,14 +199,14 @@ BOOL WINAPI Pie( HDC hdc, INT left, INT top,
{
BOOL ret = FALSE;
DC * dc = DC_GetDCUpdate( hdc );
if (dc)
{
if (PATH_IsPathOpen(dc->w.path))
FIXME("-> Path: stub\n");
else if (dc->funcs->pPie)
ret = dc->funcs->pPie(dc,left,top,right,bottom,xstart,ystart,xend,yend);
GDI_ReleaseObj( hdc );
}
if (!dc) return FALSE;
if(PATH_IsPathOpen(dc->w.path))
ret = PATH_Arc(dc,left,top,right,bottom,xstart,ystart,xend,yend,2);
else if(dc->funcs->pPie)
ret = dc->funcs->pPie(dc,left,top,right,bottom,xstart,ystart,xend,yend);
GDI_ReleaseObj( hdc );
return ret;
}
@ -229,14 +231,14 @@ BOOL WINAPI Chord( HDC hdc, INT left, INT top,
{
BOOL ret = FALSE;
DC * dc = DC_GetDCUpdate( hdc );
if (dc)
{
if(PATH_IsPathOpen(dc->w.path))
FIXME("-> Path: stub\n");
else if (dc->funcs->pChord)
ret = dc->funcs->pChord(dc,left,top,right,bottom,xstart,ystart,xend,yend);
GDI_ReleaseObj( hdc );
}
if (!dc) return FALSE;
if(PATH_IsPathOpen(dc->w.path))
ret = PATH_Arc(dc,left,top,right,bottom,xstart,ystart,xend,yend,1);
else if(dc->funcs->pChord)
ret = dc->funcs->pChord(dc,left,top,right,bottom,xstart,ystart,xend,yend);
GDI_ReleaseObj( hdc );
return ret;
}
@ -259,14 +261,14 @@ BOOL WINAPI Ellipse( HDC hdc, INT left, INT top,
{
BOOL ret = FALSE;
DC * dc = DC_GetDCUpdate( hdc );
if (dc)
{
if(PATH_IsPathOpen(dc->w.path))
FIXME("-> Path: stub\n");
else if (dc->funcs->pEllipse)
ret = dc->funcs->pEllipse(dc,left,top,right,bottom);
GDI_ReleaseObj( hdc );
}
if (!dc) return FALSE;
if(PATH_IsPathOpen(dc->w.path))
ret = PATH_Ellipse(dc,left,top,right,bottom);
else if (dc->funcs->pEllipse)
ret = dc->funcs->pEllipse(dc,left,top,right,bottom);
GDI_ReleaseObj( hdc );
return ret;
}
@ -323,7 +325,7 @@ BOOL WINAPI RoundRect( HDC hdc, INT left, INT top, INT right,
if (dc)
{
if(PATH_IsPathOpen(dc->w.path))
FIXME("-> Path: stub\n");
ret = PATH_RoundRect(dc,left,top,right,bottom,ell_width,ell_height);
else if (dc->funcs->pRoundRect)
ret = dc->funcs->pRoundRect(dc,left,top,right,bottom,ell_width,ell_height);
GDI_ReleaseObj( hdc );
@ -1016,12 +1018,10 @@ BOOL WINAPI PolyBezierTo( HDC hdc, const POINT* lppt, DWORD cPoints )
/***********************************************************************
* AngleArc (GDI32.5)
*
*/
BOOL WINAPI AngleArc(HDC hdc, INT x, INT y, DWORD dwRadius,
FLOAT eStartAngle, FLOAT eSweepAngle)
BOOL WINAPI AngleArc(HDC hdc, INT x, INT y, DWORD dwRadius, FLOAT eStartAngle, FLOAT eSweepAngle)
{
int x1,y1,x2,y2;
INT x1,y1,x2,y2, arcdir;
BOOL result;
DC *dc;
@ -1034,11 +1034,16 @@ BOOL WINAPI AngleArc(HDC hdc, INT x, INT y, DWORD dwRadius,
if(dc->funcs->pAngleArc)
{
result = dc->funcs->pAngleArc( dc, x, y, dwRadius, eStartAngle, eSweepAngle );
GDI_ReleaseObj( hdc );
return result;
}
GDI_ReleaseObj( hdc );
/* AngleArc always works counterclockwise */
arcdir = GetArcDirection( hdc );
SetArcDirection( hdc, AD_COUNTERCLOCKWISE );
x1 = x + cos(eStartAngle*M_PI/180) * dwRadius;
y1 = y - sin(eStartAngle*M_PI/180) * dwRadius;
x2 = x + cos((eStartAngle+eSweepAngle)*M_PI/180) * dwRadius;
@ -1053,12 +1058,12 @@ BOOL WINAPI AngleArc(HDC hdc, INT x, INT y, DWORD dwRadius,
x2, y2, x1, y1 );
if( result ) MoveToEx( hdc, x2, y2, NULL );
SetArcDirection( hdc, arcdir );
return result;
}
/***********************************************************************
* PolyDraw (GDI32.270)
*
*/
BOOL WINAPI PolyDraw(HDC hdc, const POINT *lppt, const BYTE *lpbTypes,
DWORD cCount)
@ -1091,11 +1096,12 @@ BOOL WINAPI PolyDraw(HDC hdc, const POINT *lppt, const BYTE *lpbTypes,
}
/* if no moveto occurs, we will close the figure here */
lastmove.x = dc->w.CursPosX;
lastmove.x = dc->w.CursPosX;
lastmove.y = dc->w.CursPosY;
/* now let's draw */
for( i = 0; i < cCount; i++ )
{
if( lpbTypes[i] == PT_MOVETO )
{
MoveToEx( hdc, lppt[i].x, lppt[i].y, NULL );
@ -1103,24 +1109,24 @@ BOOL WINAPI PolyDraw(HDC hdc, const POINT *lppt, const BYTE *lpbTypes,
lastmove.y = dc->w.CursPosY;
}
else if( lpbTypes[i] & PT_LINETO )
{
LineTo( hdc, lppt[i].x, lppt[i].y );
if( lpbTypes[i] & PT_CLOSEFIGURE )
LineTo( hdc, lastmove.x, lastmove.y );
}
else if( lpbTypes[i] & PT_BEZIERTO )
{
/* optimizeme: multiple BezierTo's with one PolyBezierTo call */
PolyBezierTo( hdc, &lppt[i], 3 );
PolyBezierTo( hdc, &lppt[i], 3 );
i += 2;
if( lpbTypes[i] & PT_CLOSEFIGURE )
LineTo( hdc, lastmove.x, lastmove.y );
}
else
return FALSE;
if( lpbTypes[i] & PT_CLOSEFIGURE )
{
if( PATH_IsPathOpen( dc->w.path ) )
CloseFigure( hdc );
else
LineTo( hdc, lastmove.x, lastmove.y );
}
}
return TRUE;
}

View File

@ -70,8 +70,6 @@ DEFAULT_DEBUG_CHANNEL(gdi)
static BOOL PATH_PathToRegion(GdiPath *pPath, INT nPolyFillMode,
HRGN *pHrgn);
static void PATH_EmptyPath(GdiPath *pPath);
static BOOL PATH_AddEntry(GdiPath *pPath, const POINT *pPoint,
BYTE flags);
static BOOL PATH_ReserveEntries(GdiPath *pPath, INT numEntries);
static BOOL PATH_DoArcPart(GdiPath *pPath, FLOAT_POINT corners[],
double angleStart, double angleEnd, BOOL addMoveTo);
@ -79,6 +77,7 @@ static void PATH_ScaleNormalizedPoint(FLOAT_POINT corners[], double x,
double y, POINT *pPoint);
static void PATH_NormalizePoint(FLOAT_POINT corners[], const FLOAT_POINT
*pPoint, double *pX, double *pY);
static BOOL PATH_CheckCorners(DC *dc, POINT corners[], INT x1, INT y1, INT x2, INT y2);
/***********************************************************************
@ -618,6 +617,67 @@ BOOL PATH_LineTo(DC *dc, INT x, INT y)
return PATH_AddEntry(pPath, &point, PT_LINETO);
}
/* PATH_RoundRect
*
* Should be called when a call to RoundRect is performed on a DC that has
* an open path. Returns TRUE if successful, else FALSE.
*
* FIXME: it adds the same entries to the path as windows does, but there
* is an error in the bezier drawing code so that there are small pixel-size
* gaps when the resulting path is drawn by StrokePath()
*/
BOOL PATH_RoundRect(DC *dc, INT x1, INT y1, INT x2, INT y2, INT ell_width, INT ell_height)
{
GdiPath *pPath = &dc->w.path;
POINT corners[2], pointTemp;
FLOAT_POINT ellCorners[2];
/* Check that path is open */
if(pPath->state!=PATH_Open)
return FALSE;
if(!PATH_CheckCorners(dc,corners,x1,y1,x2,y2))
return FALSE;
/* Add points to the roundrect path */
ellCorners[0].x = corners[1].x-ell_width;
ellCorners[0].y = corners[0].y;
ellCorners[1].x = corners[1].x;
ellCorners[1].y = corners[0].y+ell_height;
if(!PATH_DoArcPart(pPath, ellCorners, 0, -M_PI_2, TRUE))
return FALSE;
pointTemp.x = corners[0].x+ell_width/2;
pointTemp.y = corners[0].y;
if(!PATH_AddEntry(pPath, &pointTemp, PT_LINETO))
return FALSE;
ellCorners[0].x = corners[0].x;
ellCorners[1].x = corners[0].x+ell_width;
if(!PATH_DoArcPart(pPath, ellCorners, -M_PI_2, -M_PI, FALSE))
return FALSE;
pointTemp.x = corners[0].x;
pointTemp.y = corners[1].y-ell_height/2;
if(!PATH_AddEntry(pPath, &pointTemp, PT_LINETO))
return FALSE;
ellCorners[0].y = corners[1].y-ell_height;
ellCorners[1].y = corners[1].y;
if(!PATH_DoArcPart(pPath, ellCorners, M_PI, M_PI_2, FALSE))
return FALSE;
pointTemp.x = corners[1].x-ell_width/2;
pointTemp.y = corners[1].y;
if(!PATH_AddEntry(pPath, &pointTemp, PT_LINETO))
return FALSE;
ellCorners[0].x = corners[1].x-ell_width;
ellCorners[1].x = corners[1].x;
if(!PATH_DoArcPart(pPath, ellCorners, M_PI_2, 0, FALSE))
return FALSE;
/* Close the roundrect figure */
if(!CloseFigure(dc->hSelf))
return FALSE;
return TRUE;
}
/* PATH_Rectangle
*
* Should be called when a call to Rectangle is performed on a DC that has
@ -627,40 +687,13 @@ BOOL PATH_Rectangle(DC *dc, INT x1, INT y1, INT x2, INT y2)
{
GdiPath *pPath = &dc->w.path;
POINT corners[2], pointTemp;
INT temp;
/* Check that path is open */
if(pPath->state!=PATH_Open)
return FALSE;
/* Convert points to device coordinates */
corners[0].x=x1;
corners[0].y=y1;
corners[1].x=x2;
corners[1].y=y2;
if(!LPtoDP(dc->hSelf, corners, 2))
if(!PATH_CheckCorners(dc,corners,x1,y1,x2,y2))
return FALSE;
/* Make sure first corner is top left and second corner is bottom right */
if(corners[0].x>corners[1].x)
{
temp=corners[0].x;
corners[0].x=corners[1].x;
corners[1].x=temp;
}
if(corners[0].y>corners[1].y)
{
temp=corners[0].y;
corners[0].y=corners[1].y;
corners[1].y=temp;
}
/* In GM_COMPATIBLE, don't include bottom and right edges */
if(dc->w.GraphicsMode==GM_COMPATIBLE)
{
corners[1].x--;
corners[1].y--;
}
/* Close any previous figure */
if(!CloseFigure(dc->hSelf))
@ -703,25 +736,27 @@ BOOL PATH_Rectangle(DC *dc, INT x1, INT y1, INT x2, INT y2)
*/
BOOL PATH_Ellipse(DC *dc, INT x1, INT y1, INT x2, INT y2)
{
/* TODO: This should probably be revised to call PATH_AngleArc */
/* (once it exists) */
return PATH_Arc(dc, x1, y1, x2, y2, x1, (y1+y2)/2, x1, (y1+y2)/2);
return( PATH_Arc(dc, x1, y1, x2, y2, x1, (y1+y2)/2, x1, (y1+y2)/2,0) &&
CloseFigure(dc->hSelf) );
}
/* PATH_Arc
*
* Should be called when a call to Arc is performed on a DC that has
* an open path. This adds up to five Bezier splines representing the arc
* to the path. Returns TRUE if successful, else FALSE.
* to the path. When 'lines' is 1, we add 1 extra line to get a chord,
* and when 'lines' is 2, we add 2 extra lines to get a pie.
* Returns TRUE if successful, else FALSE.
*/
BOOL PATH_Arc(DC *dc, INT x1, INT y1, INT x2, INT y2,
INT xStart, INT yStart, INT xEnd, INT yEnd)
INT xStart, INT yStart, INT xEnd, INT yEnd, INT lines)
{
GdiPath *pPath = &dc->w.path;
double angleStart, angleEnd, angleStartQuadrant, angleEndQuadrant=0.0;
/* Initialize angleEndQuadrant to silence gcc's warning */
double x, y;
FLOAT_POINT corners[2], pointStart, pointEnd;
POINT centre;
BOOL start, end;
INT temp;
@ -732,8 +767,6 @@ BOOL PATH_Arc(DC *dc, INT x1, INT y1, INT x2, INT y2,
if(pPath->state!=PATH_Open)
return FALSE;
/* FIXME: Do we have to close the current figure? */
/* Check for zero height / width */
/* FIXME: Only in GM_COMPATIBLE? */
if(x1==x2 || y1==y2)
@ -839,6 +872,20 @@ BOOL PATH_Arc(DC *dc, INT x1, INT y1, INT x2, INT y2,
start=FALSE;
} while(!end);
/* chord: close figure. pie: add line and close figure */
if(lines==1)
{
if(!CloseFigure(dc->hSelf))
return FALSE;
}
else if(lines==2)
{
centre.x = (corners[0].x+corners[1].x)/2;
centre.y = (corners[0].y+corners[1].y)/2;
if(!PATH_AddEntry(pPath, &centre, PT_LINETO | PT_CLOSEFIGURE))
return FALSE;
}
return TRUE;
}
@ -1016,9 +1063,47 @@ BOOL PATH_PolyPolyline( DC *dc, const POINT* pts, const DWORD* counts,
* Internal functions
*/
/* PATH_CheckCorners
*
* Helper function for PATH_RoundRect() and PATH_Rectangle()
*/
static BOOL PATH_CheckCorners(DC *dc, POINT corners[], INT x1, INT y1, INT x2, INT y2)
{
INT temp;
/* Convert points to device coordinates */
corners[0].x=x1;
corners[0].y=y1;
corners[1].x=x2;
corners[1].y=y2;
if(!LPtoDP(dc->hSelf, corners, 2))
return FALSE;
/* Make sure first corner is top left and second corner is bottom right */
if(corners[0].x>corners[1].x)
{
temp=corners[0].x;
corners[0].x=corners[1].x;
corners[1].x=temp;
}
if(corners[0].y>corners[1].y)
{
temp=corners[0].y;
corners[0].y=corners[1].y;
corners[1].y=temp;
}
/* In GM_COMPATIBLE, don't include bottom and right edges */
if(dc->w.GraphicsMode==GM_COMPATIBLE)
{
corners[1].x--;
corners[1].y--;
}
return TRUE;
}
/* PATH_AddFlatBezier
*
*/
static BOOL PATH_AddFlatBezier(GdiPath *pPath, POINT *pt, BOOL closed)
{

View File

@ -51,7 +51,7 @@ extern BOOL PATH_Rectangle(struct tagDC *dc, INT x1, INT y1,
extern BOOL PATH_Ellipse(struct tagDC *dc, INT x1, INT y1,
INT x2, INT y2);
extern BOOL PATH_Arc(struct tagDC *dc, INT x1, INT y1, INT x2, INT y2,
INT xStart, INT yStart, INT xEnd, INT yEnd);
INT xStart, INT yStart, INT xEnd, INT yEnd, INT lines);
extern BOOL PATH_PolyBezierTo(struct tagDC *dc, const POINT *pt, DWORD cbCount);
extern BOOL PATH_PolyBezier(struct tagDC *dc, const POINT *pt, DWORD cbCount);
extern BOOL PATH_PolylineTo(struct tagDC *dc, const POINT *pt, DWORD cbCount);
@ -61,6 +61,9 @@ extern BOOL PATH_PolyPolyline(struct tagDC *dc, const POINT *pt, const DWORD *co
DWORD polylines);
extern BOOL PATH_PolyPolygon(struct tagDC *dc, const POINT *pt, const INT *counts,
UINT polygons);
extern BOOL PATH_RoundRect(struct tagDC *dc, INT x1, INT y1, INT x2, INT y2, INT ell_width,
INT ell_height);
extern BOOL PATH_AddEntry(GdiPath *pPath, const POINT *pPoint, BYTE flags);
#endif /* __WINE_PATH_H */