gdi32: Add null driver entry points for painting functions that have a fallback implementation.

oldstable
Alexandre Julliard 2011-03-08 21:15:59 +01:00
parent 1f6f82782c
commit 7e3a871497
3 changed files with 252 additions and 213 deletions

View File

@ -403,9 +403,9 @@ const DC_FUNCTIONS null_driver =
NULL, /* pAbortDoc */
NULL, /* pAbortPath */
NULL, /* pAlphaBlend */
NULL, /* pAngleArc */
nulldrv_AngleArc, /* pAngleArc */
nulldrv_Arc, /* pArc */
NULL, /* pArcTo */
nulldrv_ArcTo, /* pArcTo */
NULL, /* pBeginPath */
NULL, /* pBitBlt */
NULL, /* pChoosePixelFormat */
@ -432,9 +432,9 @@ const DC_FUNCTIONS null_driver =
NULL, /* pExtSelectClipRgn */
NULL, /* pExtTextOut */
NULL, /* pFillPath */
NULL, /* pFillRgn */
nulldrv_FillRgn, /* pFillRgn */
NULL, /* pFlattenPath */
NULL, /* pFrameRgn */
nulldrv_FrameRgn, /* pFrameRgn */
NULL, /* pGdiComment */
NULL, /* pGetBitmapBits */
NULL, /* pGetCharWidth */
@ -449,7 +449,7 @@ const DC_FUNCTIONS null_driver =
NULL, /* pGetTextExtentExPoint */
NULL, /* pGetTextMetrics */
NULL, /* pIntersectClipRect */
NULL, /* pInvertRgn */
nulldrv_InvertRgn, /* pInvertRgn */
nulldrv_LineTo, /* pLineTo */
NULL, /* pModifyWorldTransform */
nulldrv_MoveTo, /* pMoveTo */
@ -459,14 +459,14 @@ const DC_FUNCTIONS null_driver =
nulldrv_PaintRgn, /* pPaintRgn */
NULL, /* pPatBlt */
nulldrv_Pie, /* pPie */
NULL, /* pPolyBezier */
NULL, /* pPolyBezierTo */
NULL, /* pPolyDraw */
nulldrv_PolyBezier, /* pPolyBezier */
nulldrv_PolyBezierTo, /* pPolyBezierTo */
nulldrv_PolyDraw, /* pPolyDraw */
nulldrv_PolyPolygon, /* pPolyPolygon */
nulldrv_PolyPolyline, /* pPolyPolyline */
nulldrv_Polygon, /* pPolygon */
nulldrv_Polyline, /* pPolyline */
NULL, /* pPolylineTo */
nulldrv_PolylineTo, /* pPolylineTo */
NULL, /* pRealizeDefaultPalette */
NULL, /* pRealizePalette */
nulldrv_Rectangle, /* pRectangle */

View File

@ -501,6 +501,17 @@ extern HPALETTE PALETTE_Init(void) DECLSPEC_HIDDEN;
extern INT mirror_region( HRGN dst, HRGN src, INT width ) DECLSPEC_HIDDEN;
extern BOOL REGION_FrameRgn( HRGN dest, HRGN src, INT x, INT y ) DECLSPEC_HIDDEN;
/* null driver entry points */
extern BOOL CDECL nulldrv_AngleArc( PHYSDEV dev, INT x, INT y, DWORD radius, FLOAT start, FLOAT sweep ) DECLSPEC_HIDDEN;
extern BOOL CDECL nulldrv_ArcTo( PHYSDEV dev, INT left, INT top, INT right, INT bottom, INT xstart, INT ystart, INT xend, INT yend ) DECLSPEC_HIDDEN;
extern BOOL CDECL nulldrv_FillRgn( PHYSDEV dev, HRGN rgn, HBRUSH brush ) DECLSPEC_HIDDEN;
extern BOOL CDECL nulldrv_FrameRgn( PHYSDEV dev, HRGN rgn, HBRUSH brush, INT width, INT height ) DECLSPEC_HIDDEN;
extern BOOL CDECL nulldrv_InvertRgn( PHYSDEV dev, HRGN rgn ) DECLSPEC_HIDDEN;
extern BOOL CDECL nulldrv_PolyBezier( PHYSDEV dev, const POINT *points, DWORD count ) DECLSPEC_HIDDEN;
extern BOOL CDECL nulldrv_PolyBezierTo( PHYSDEV dev, const POINT *points, DWORD count ) DECLSPEC_HIDDEN;
extern BOOL CDECL nulldrv_PolyDraw( PHYSDEV dev, const POINT *points, const BYTE *types, DWORD count ) DECLSPEC_HIDDEN;
extern BOOL CDECL nulldrv_PolylineTo( PHYSDEV dev, const POINT *points, INT count ) DECLSPEC_HIDDEN;
/* Undocumented value for DIB's iUsage: Indicates a mono DIB w/o pal entries */
#define DIB_PAL_MONO 2

View File

@ -37,6 +37,195 @@
WINE_DEFAULT_DEBUG_CHANNEL(gdi);
/***********************************************************************
* null driver fallback implementations
*/
BOOL CDECL nulldrv_AngleArc( PHYSDEV dev, INT x, INT y, DWORD radius, FLOAT start, FLOAT sweep )
{
INT x1 = GDI_ROUND( x + cos( start * M_PI / 180 ) * radius );
INT y1 = GDI_ROUND( y - sin( start * M_PI / 180 ) * radius );
INT x2 = GDI_ROUND( x + cos( (start + sweep) * M_PI / 180) * radius );
INT y2 = GDI_ROUND( y - sin( (start + sweep) * M_PI / 180) * radius );
INT arcdir = SetArcDirection( dev->hdc, sweep >= 0 ? AD_COUNTERCLOCKWISE : AD_CLOCKWISE );
BOOL ret = ArcTo( dev->hdc, x - radius, y - radius, x + radius, y + radius, x1, y1, x2, y2 );
SetArcDirection( dev->hdc, arcdir );
return ret;
}
BOOL CDECL nulldrv_ArcTo( PHYSDEV dev, INT left, INT top, INT right, INT bottom,
INT xstart, INT ystart, INT xend, INT yend )
{
INT width = abs( right - left );
INT height = abs( bottom - top );
double xradius = width / 2.0;
double yradius = height / 2.0;
double xcenter = right > left ? left + xradius : right + xradius;
double ycenter = bottom > top ? top + yradius : bottom + yradius;
double angle;
if (!height || !width) return FALSE;
/* draw a line from the current position to the starting point of the arc, then draw the arc */
angle = atan2( (ystart - ycenter) / height, (xstart - xcenter) / width );
LineTo( dev->hdc, GDI_ROUND( xcenter + cos(angle) * xradius ),
GDI_ROUND( ycenter + sin(angle) * yradius ));
return Arc( dev->hdc, left, top, right, bottom, xstart, ystart, xend, yend );
}
BOOL CDECL nulldrv_FillRgn( PHYSDEV dev, HRGN rgn, HBRUSH brush )
{
BOOL ret = FALSE;
HBRUSH prev;
if ((prev = SelectObject( dev->hdc, brush )))
{
ret = PaintRgn( dev->hdc, rgn );
SelectObject( dev->hdc, prev );
}
return ret;
}
BOOL CDECL nulldrv_FrameRgn( PHYSDEV dev, HRGN rgn, HBRUSH brush, INT width, INT height )
{
BOOL ret = FALSE;
HRGN tmp = CreateRectRgn( 0, 0, 0, 0 );
if (tmp)
{
if (REGION_FrameRgn( tmp, rgn, width, height )) ret = FillRgn( dev->hdc, tmp, brush );
DeleteObject( tmp );
}
return ret;
}
BOOL CDECL nulldrv_InvertRgn( PHYSDEV dev, HRGN rgn )
{
HBRUSH prev_brush = SelectObject( dev->hdc, GetStockObject(BLACK_BRUSH) );
INT prev_rop = SetROP2( dev->hdc, R2_NOT );
BOOL ret = PaintRgn( dev->hdc, rgn );
SelectObject( dev->hdc, prev_brush );
SetROP2( dev->hdc, prev_rop );
return ret;
}
BOOL CDECL nulldrv_PolyBezier( PHYSDEV dev, const POINT *points, DWORD count )
{
BOOL ret = FALSE;
POINT *pts;
INT n;
if ((pts = GDI_Bezier( points, count, &n )))
{
ret = Polyline( dev->hdc, pts, n );
HeapFree( GetProcessHeap(), 0, pts );
}
return ret;
}
BOOL CDECL nulldrv_PolyBezierTo( PHYSDEV dev, const POINT *points, DWORD count )
{
BOOL ret = FALSE;
POINT *pts = HeapAlloc( GetProcessHeap(), 0, sizeof(POINT) * (count + 1) );
if (pts)
{
GetCurrentPositionEx( dev->hdc, &pts[0] );
memcpy( pts + 1, points, sizeof(POINT) * count );
ret = PolyBezier( dev->hdc, pts, count + 1 );
HeapFree( GetProcessHeap(), 0, pts );
}
return ret;
}
BOOL CDECL nulldrv_PolyDraw( PHYSDEV dev, const POINT *points, const BYTE *types, DWORD count )
{
POINT *line_pts = NULL, *bzr_pts = NULL, bzr[4];
INT i, num_pts, num_bzr_pts, space, size;
/* check for valid point types */
for (i = 0; i < count; i++)
{
switch (types[i])
{
case PT_MOVETO:
case PT_LINETO | PT_CLOSEFIGURE:
case PT_LINETO:
break;
case PT_BEZIERTO:
if((i + 2 < count) && (types[i + 1] == PT_BEZIERTO) &&
((types[i + 2] & ~PT_CLOSEFIGURE) == PT_BEZIERTO))
{
i += 2;
break;
}
default:
return FALSE;
}
}
space = count + 300;
line_pts = HeapAlloc( GetProcessHeap(), 0, space * sizeof(POINT) );
num_pts = 1;
GetCurrentPositionEx( dev->hdc, &line_pts[0] );
for (i = 0; i < count; i++)
{
switch (types[i])
{
case PT_MOVETO:
if (num_pts >= 2) Polyline( dev->hdc, line_pts, num_pts );
num_pts = 0;
line_pts[num_pts++] = points[i];
break;
case PT_LINETO:
case (PT_LINETO | PT_CLOSEFIGURE):
line_pts[num_pts++] = points[i];
break;
case PT_BEZIERTO:
bzr[0].x = line_pts[num_pts - 1].x;
bzr[0].y = line_pts[num_pts - 1].y;
memcpy( &bzr[1], &points[i], 3 * sizeof(POINT) );
if ((bzr_pts = GDI_Bezier( bzr, 4, &num_bzr_pts )))
{
size = num_pts + (count - i) + num_bzr_pts;
if (space < size)
{
space = size * 2;
line_pts = HeapReAlloc( GetProcessHeap(), 0, line_pts, space * sizeof(POINT) );
}
memcpy( &line_pts[num_pts], &bzr_pts[1], (num_bzr_pts - 1) * sizeof(POINT) );
num_pts += num_bzr_pts - 1;
HeapFree( GetProcessHeap(), 0, bzr_pts );
}
i += 2;
break;
}
if (types[i] & PT_CLOSEFIGURE) line_pts[num_pts++] = line_pts[0];
}
if (num_pts >= 2) Polyline( dev->hdc, line_pts, num_pts );
MoveToEx( dev->hdc, line_pts[num_pts - 1].x, line_pts[num_pts - 1].y, NULL );
HeapFree( GetProcessHeap(), 0, line_pts );
return TRUE;
}
BOOL CDECL nulldrv_PolylineTo( PHYSDEV dev, const POINT *points, INT count )
{
BOOL ret = FALSE;
POINT *pts;
if (!count) return FALSE;
if ((pts = HeapAlloc( GetProcessHeap(), 0, sizeof(POINT) * (count + 1) )))
{
GetCurrentPositionEx( dev->hdc, &pts[0] );
memcpy( pts + 1, points, sizeof(POINT) * count );
ret = Polyline( dev->hdc, pts, count + 1 );
HeapFree( GetProcessHeap(), 0, pts );
}
return ret;
}
/***********************************************************************
* LineTo (GDI32.@)
*/
@ -140,16 +329,10 @@ BOOL WINAPI ArcTo( HDC hdc,
update_dc( dc );
if(PATH_IsPathOpen(dc->path))
result = PATH_Arc(dc,left,top,right,bottom,xstart,ystart,xend,yend,-1);
else if(dc->funcs->pArcTo)
result = dc->funcs->pArcTo( dc->physDev, left, top, right, bottom,
xstart, ystart, xend, yend );
else /* We'll draw a line from the current position to the starting point of the arc, then draw the arc */
else
{
angle = atan2(((ystart-ycenter)/height),
((xstart-xcenter)/width));
LineTo(hdc, GDI_ROUND(xcenter+(cos(angle)*xradius)),
GDI_ROUND(ycenter+(sin(angle)*yradius)));
result = Arc(hdc, left, top, right, bottom, xstart, ystart, xend, yend);
PHYSDEV physdev = GET_DC_PHYSDEV( dc, pArcTo );
result = physdev->funcs->pArcTo( physdev, left, top, right, bottom, xstart, ystart, xend, yend );
}
if (result) {
angle = atan2(((yend-ycenter)/height),
@ -530,21 +713,15 @@ BOOL WINAPI PaintRgn( HDC hdc, HRGN hrgn )
BOOL WINAPI FillRgn( HDC hdc, HRGN hrgn, HBRUSH hbrush )
{
BOOL retval = FALSE;
HBRUSH prevBrush;
DC * dc = get_dc_ptr( hdc );
if (!dc) return FALSE;
if(dc->funcs->pFillRgn)
if (dc)
{
PHYSDEV physdev = GET_DC_PHYSDEV( dc, pFillRgn );
update_dc( dc );
retval = dc->funcs->pFillRgn(dc->physDev, hrgn, hbrush);
retval = physdev->funcs->pFillRgn( physdev, hrgn, hbrush );
release_dc_ptr( dc );
}
else if ((prevBrush = SelectObject( hdc, hbrush )))
{
retval = PaintRgn( hdc, hrgn );
SelectObject( hdc, prevBrush );
}
release_dc_ptr( dc );
return retval;
}
@ -558,27 +735,13 @@ BOOL WINAPI FrameRgn( HDC hdc, HRGN hrgn, HBRUSH hbrush,
BOOL ret = FALSE;
DC *dc = get_dc_ptr( hdc );
if (!dc) return FALSE;
if(dc->funcs->pFrameRgn)
if (dc)
{
PHYSDEV physdev = GET_DC_PHYSDEV( dc, pFrameRgn );
update_dc( dc );
ret = dc->funcs->pFrameRgn( dc->physDev, hrgn, hbrush, nWidth, nHeight );
ret = physdev->funcs->pFrameRgn( physdev, hrgn, hbrush, nWidth, nHeight );
release_dc_ptr( dc );
}
else
{
HRGN tmp = CreateRectRgn( 0, 0, 0, 0 );
if (tmp)
{
if (REGION_FrameRgn( tmp, hrgn, nWidth, nHeight ))
{
FillRgn( hdc, tmp, hbrush );
ret = TRUE;
}
DeleteObject( tmp );
}
}
release_dc_ptr( dc );
return ret;
}
@ -588,27 +751,17 @@ BOOL WINAPI FrameRgn( HDC hdc, HRGN hrgn, HBRUSH hbrush,
*/
BOOL WINAPI InvertRgn( HDC hdc, HRGN hrgn )
{
HBRUSH prevBrush;
INT prevROP;
BOOL retval;
BOOL ret = FALSE;
DC *dc = get_dc_ptr( hdc );
if (!dc) return FALSE;
if(dc->funcs->pInvertRgn)
if (dc)
{
PHYSDEV physdev = GET_DC_PHYSDEV( dc, pInvertRgn );
update_dc( dc );
retval = dc->funcs->pInvertRgn( dc->physDev, hrgn );
ret = physdev->funcs->pInvertRgn( physdev, hrgn );
release_dc_ptr( dc );
}
else
{
prevBrush = SelectObject( hdc, GetStockObject(BLACK_BRUSH) );
prevROP = SetROP2( hdc, R2_NOT );
retval = PaintRgn( hdc, hrgn );
SelectObject( hdc, prevBrush );
SetROP2( hdc, prevROP );
}
release_dc_ptr( dc );
return retval;
return ret;
}
@ -644,30 +797,15 @@ BOOL WINAPI PolylineTo( HDC hdc, const POINT* pt, DWORD cCount )
if(!dc) return FALSE;
if(PATH_IsPathOpen(dc->path))
update_dc( dc );
if(PATH_IsPathOpen(dc->path)) ret = PATH_PolylineTo(dc, pt, cCount);
else
{
update_dc( dc );
ret = PATH_PolylineTo(dc, pt, cCount);
PHYSDEV physdev = GET_DC_PHYSDEV( dc, pPolylineTo );
ret = physdev->funcs->pPolylineTo( physdev, pt, cCount );
}
else if(dc->funcs->pPolylineTo)
if (ret && cCount)
{
update_dc( dc );
ret = dc->funcs->pPolylineTo(dc->physDev, pt, cCount);
}
else /* do it using Polyline */
{
POINT *pts = HeapAlloc( GetProcessHeap(), 0,
sizeof(POINT) * (cCount + 1) );
if (pts)
{
pts[0].x = dc->CursPosX;
pts[0].y = dc->CursPosY;
memcpy( pts + 1, pt, sizeof(POINT) * cCount );
ret = Polyline( hdc, pts, cCount + 1 );
HeapFree( GetProcessHeap(), 0, pts );
}
}
if(ret) {
dc->CursPosX = pt[cCount-1].x;
dc->CursPosY = pt[cCount-1].y;
}
@ -799,29 +937,13 @@ BOOL WINAPI PolyBezier( HDC hdc, const POINT* lppt, DWORD cPoints )
dc = get_dc_ptr( hdc );
if(!dc) return FALSE;
if(PATH_IsPathOpen(dc->path))
update_dc( dc );
if(PATH_IsPathOpen(dc->path)) ret = PATH_PolyBezier(dc, lppt, cPoints);
else
{
update_dc( dc );
ret = PATH_PolyBezier(dc, lppt, cPoints);
PHYSDEV physdev = GET_DC_PHYSDEV( dc, pPolyBezier );
ret = physdev->funcs->pPolyBezier( physdev, lppt, cPoints );
}
else if (dc->funcs->pPolyBezier)
{
update_dc( dc );
ret = dc->funcs->pPolyBezier(dc->physDev, lppt, cPoints);
}
else /* We'll convert it into line segments and draw them using Polyline */
{
POINT *Pts;
INT nOut;
if ((Pts = GDI_Bezier( lppt, cPoints, &nOut )))
{
TRACE("Pts = %p, no = %d\n", Pts, nOut);
ret = Polyline( hdc, Pts, nOut );
HeapFree( GetProcessHeap(), 0, Pts );
}
}
release_dc_ptr( dc );
return ret;
}
@ -850,27 +972,12 @@ BOOL WINAPI PolyBezierTo( HDC hdc, const POINT* lppt, DWORD cPoints )
dc = get_dc_ptr( hdc );
if(!dc) return FALSE;
if(PATH_IsPathOpen(dc->path))
update_dc( dc );
if(PATH_IsPathOpen(dc->path)) ret = PATH_PolyBezierTo(dc, lppt, cPoints);
else
{
update_dc( dc );
ret = PATH_PolyBezierTo(dc, lppt, cPoints);
}
else if(dc->funcs->pPolyBezierTo)
{
update_dc( dc );
ret = dc->funcs->pPolyBezierTo(dc->physDev, lppt, cPoints);
}
else /* We'll do it using PolyBezier */
{
POINT *pt = HeapAlloc( GetProcessHeap(), 0, sizeof(POINT) * (cPoints + 1) );
if(pt)
{
pt[0].x = dc->CursPosX;
pt[0].y = dc->CursPosY;
memcpy(pt + 1, lppt, sizeof(POINT) * cPoints);
ret = PolyBezier(hdc, pt, cPoints+1);
HeapFree( GetProcessHeap(), 0, pt );
}
PHYSDEV physdev = GET_DC_PHYSDEV( dc, pPolyBezierTo );
ret = physdev->funcs->pPolyBezierTo( physdev, lppt, cPoints );
}
if(ret) {
dc->CursPosX = lppt[cPoints-1].x;
@ -899,10 +1006,11 @@ BOOL WINAPI AngleArc(HDC hdc, INT x, INT y, DWORD dwRadius, FLOAT eStartAngle, F
x2 = GDI_ROUND( x + cos((eStartAngle+eSweepAngle)*M_PI/180) * dwRadius );
y2 = GDI_ROUND( y - sin((eStartAngle+eSweepAngle)*M_PI/180) * dwRadius );
if(!PATH_IsPathOpen(dc->path) && dc->funcs->pAngleArc)
update_dc( dc );
if(!PATH_IsPathOpen(dc->path))
{
update_dc( dc );
result = dc->funcs->pAngleArc( dc->physDev, x, y, dwRadius, eStartAngle, eSweepAngle );
PHYSDEV physdev = GET_DC_PHYSDEV( dc, pAngleArc );
result = physdev->funcs->pAngleArc( physdev, x, y, dwRadius, eStartAngle, eSweepAngle );
}
else { /* do it using ArcTo */
x1 = GDI_ROUND( x + cos(eStartAngle*M_PI/180) * dwRadius );
@ -927,98 +1035,18 @@ BOOL WINAPI AngleArc(HDC hdc, INT x, INT y, DWORD dwRadius, FLOAT eStartAngle, F
BOOL WINAPI PolyDraw(HDC hdc, const POINT *lppt, const BYTE *lpbTypes,
DWORD cCount)
{
DC *dc;
DC *dc = get_dc_ptr( hdc );
BOOL result = FALSE;
POINT * line_pts = NULL, * bzr_pts = NULL, bzr[4];
INT i, num_pts, num_bzr_pts, space, size;
dc = get_dc_ptr( hdc );
if(!dc) return FALSE;
if( PATH_IsPathOpen( dc->path ) )
update_dc( dc );
if( PATH_IsPathOpen( dc->path ) ) result = PATH_PolyDraw(dc, lppt, lpbTypes, cCount);
else
{
update_dc( dc );
result = PATH_PolyDraw(dc, lppt, lpbTypes, cCount);
PHYSDEV physdev = GET_DC_PHYSDEV( dc, pPolyDraw );
result = physdev->funcs->pPolyDraw( physdev, lppt, lpbTypes, cCount );
}
else if(dc->funcs->pPolyDraw)
{
update_dc( dc );
result = dc->funcs->pPolyDraw( dc->physDev, lppt, lpbTypes, cCount );
}
else {
/* check for valid point types */
for(i = 0; i < cCount; i++) {
switch(lpbTypes[i]) {
case PT_MOVETO:
case PT_LINETO | PT_CLOSEFIGURE:
case PT_LINETO:
break;
case PT_BEZIERTO:
if((i + 2 < cCount) && (lpbTypes[i + 1] == PT_BEZIERTO) &&
((lpbTypes[i + 2] & ~PT_CLOSEFIGURE) == PT_BEZIERTO)){
i += 2;
break;
}
default:
goto end;
}
}
space = cCount + 300;
line_pts = HeapAlloc(GetProcessHeap(), 0, space * sizeof(POINT));
num_pts = 1;
line_pts[0].x = dc->CursPosX;
line_pts[0].y = dc->CursPosY;
for(i = 0; i < cCount; i++) {
switch(lpbTypes[i]) {
case PT_MOVETO:
if(num_pts >= 2)
Polyline(hdc, line_pts, num_pts);
num_pts = 0;
line_pts[num_pts++] = lppt[i];
break;
case PT_LINETO:
case (PT_LINETO | PT_CLOSEFIGURE):
line_pts[num_pts++] = lppt[i];
break;
case PT_BEZIERTO:
bzr[0].x = line_pts[num_pts - 1].x;
bzr[0].y = line_pts[num_pts - 1].y;
memcpy(&bzr[1], &lppt[i], 3 * sizeof(POINT));
bzr_pts = GDI_Bezier(bzr, 4, &num_bzr_pts);
size = num_pts + (cCount - i) + num_bzr_pts;
if(space < size){
space = size * 2;
line_pts = HeapReAlloc(GetProcessHeap(), 0, line_pts,
space * sizeof(POINT));
}
memcpy(&line_pts[num_pts], &bzr_pts[1],
(num_bzr_pts - 1) * sizeof(POINT));
num_pts += num_bzr_pts - 1;
HeapFree(GetProcessHeap(), 0, bzr_pts);
i += 2;
break;
default:
goto end;
}
if(lpbTypes[i] & PT_CLOSEFIGURE)
line_pts[num_pts++] = line_pts[0];
}
if(num_pts >= 2)
Polyline(hdc, line_pts, num_pts);
MoveToEx(hdc, line_pts[num_pts - 1].x, line_pts[num_pts - 1].y, NULL);
HeapFree(GetProcessHeap(), 0, line_pts);
result = TRUE;
}
end:
release_dc_ptr( dc );
return result;
}