graphics.c 16.2 KB
Newer Older
Alexandre Julliard's avatar
Alexandre Julliard committed
1
/*
Alexandre Julliard's avatar
Alexandre Julliard committed
2
 *	PostScript driver graphics functions
Alexandre Julliard's avatar
Alexandre Julliard committed
3 4 5
 *
 *	Copyright 1998  Huw D M Davies
 *
6 7 8 9 10 11 12 13 14 15 16 17
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
18
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
Alexandre Julliard's avatar
Alexandre Julliard committed
19
 */
20 21 22

#include "config.h"

23
#include <stdarg.h>
24
#include <stdio.h>
Alexandre Julliard's avatar
Alexandre Julliard committed
25
#include <string.h>
26
#include <math.h>
27
#if defined(HAVE_FLOAT_H)
28
# include <float.h>
29 30
#endif
#if !defined(PI)
31
# define PI M_PI
32
#endif
33 34 35
#include "windef.h"
#include "winbase.h"
#include "winuser.h"
Alexandre Julliard's avatar
Alexandre Julliard committed
36
#include "psdrv.h"
37
#include "wine/debug.h"
Alexandre Julliard's avatar
Alexandre Julliard committed
38

39
WINE_DEFAULT_DEBUG_CHANNEL(psdrv);
40

41 42 43 44 45
/***********************************************************************
 *           PSDRV_XWStoDS
 *
 * Performs a world-to-viewport transformation on the specified width.
 */
46
INT PSDRV_XWStoDS( PHYSDEV dev, INT width )
47 48 49 50 51 52 53
{
    POINT pt[2];

    pt[0].x = 0;
    pt[0].y = 0;
    pt[1].x = width;
    pt[1].y = 0;
54
    LPtoDP( dev->hdc, pt, 2 );
55 56 57
    return pt[1].x - pt[0].x;
}

58 59 60
/***********************************************************************
 *           PSDRV_DrawLine
 */
61
static void PSDRV_DrawLine( PHYSDEV dev )
62
{
63 64
    PSDRV_PDEVICE *physDev = get_psdrv_dev( dev );

65 66 67 68
    if(physDev->pathdepth)
        return;

    if (physDev->pen.style == PS_NULL)
69
	PSDRV_WriteNewPath(dev);
70
    else
71
	PSDRV_WriteStroke(dev);
72
}
73

Alexandre Julliard's avatar
Alexandre Julliard committed
74 75 76
/***********************************************************************
 *           PSDRV_LineTo
 */
77
BOOL PSDRV_LineTo(PHYSDEV dev, INT x, INT y)
Alexandre Julliard's avatar
Alexandre Julliard committed
78
{
79
    POINT pt[2];
80

81
    TRACE("%d %d\n", x, y);
Alexandre Julliard's avatar
Alexandre Julliard committed
82

83
    GetCurrentPositionEx( dev->hdc, pt );
84 85
    pt[1].x = x;
    pt[1].y = y;
86
    LPtoDP( dev->hdc, pt, 2 );
87

88
    PSDRV_SetPen(dev);
89

90 91 92 93 94
    PSDRV_SetClip(dev);
    PSDRV_WriteMoveTo(dev, pt[0].x, pt[0].y );
    PSDRV_WriteLineTo(dev, pt[1].x, pt[1].y );
    PSDRV_DrawLine(dev);
    PSDRV_ResetClip(dev);
Alexandre Julliard's avatar
Alexandre Julliard committed
95 96 97 98

    return TRUE;
}

99

Alexandre Julliard's avatar
Alexandre Julliard committed
100 101 102
/***********************************************************************
 *           PSDRV_Rectangle
 */
103
BOOL PSDRV_Rectangle( PHYSDEV dev, INT left, INT top, INT right, INT bottom )
Alexandre Julliard's avatar
Alexandre Julliard committed
104
{
105
    PSDRV_PDEVICE *physDev = get_psdrv_dev( dev );
106
    RECT rect;
Alexandre Julliard's avatar
Alexandre Julliard committed
107

108
    TRACE("%d %d - %d %d\n", left, top, right, bottom);
109

110
    SetRect(&rect, left, top, right, bottom);
111
    LPtoDP( dev->hdc, (POINT *)&rect, 2 );
112

113
    /* Windows does something truly hacky here.  If we're in passthrough mode
114 115
       and our rop is R2_NOP, then we output the string below.  This is used in
       Office 2k when inserting eps files */
116 117 118 119 120 121 122 123
    if (physDev->job.passthrough_state == passthrough_active && GetROP2(dev->hdc) == R2_NOP)
    {
        char buf[256];

        sprintf(buf, "N %d %d %d %d B\n", rect.right - rect.left, rect.bottom - rect.top, rect.left, rect.top);
        write_spool(dev, buf, strlen(buf));
        physDev->job.passthrough_state = passthrough_had_rect;
        return TRUE;
124 125
    }

126
    PSDRV_SetPen(dev);
127

128 129
    PSDRV_SetClip(dev);
    PSDRV_WriteRectangle(dev, rect.left, rect.top, rect.right - rect.left,
130
                         rect.bottom - rect.top );
131 132 133
    PSDRV_Brush(dev,0);
    PSDRV_DrawLine(dev);
    PSDRV_ResetClip(dev);
Alexandre Julliard's avatar
Alexandre Julliard committed
134 135 136 137
    return TRUE;
}


138 139 140
/***********************************************************************
 *           PSDRV_RoundRect
 */
141 142
BOOL PSDRV_RoundRect( PHYSDEV dev, INT left, INT top, INT right,
                      INT bottom, INT ell_width, INT ell_height )
143
{
144 145
    RECT rect[2];

146 147
    SetRect(&rect[0], left, top, right, bottom);
    SetRect(&rect[1], 0, 0, ell_width, ell_height);
148
    LPtoDP( dev->hdc, (POINT *)rect, 4 );
149 150 151 152 153 154 155 156 157 158 159 160

    left   = rect[0].left;
    top    = rect[0].top;
    right  = rect[0].right;
    bottom = rect[0].bottom;
    if (left > right) { INT tmp = left; left = right; right = tmp; }
    if (top > bottom) { INT tmp = top; top = bottom; bottom = tmp; }

    ell_width  = rect[1].right - rect[1].left;
    ell_height = rect[1].bottom - rect[1].top;
    if (ell_width > right - left) ell_width = right - left;
    if (ell_height > bottom - top) ell_height = bottom - top;
161

162 163
    PSDRV_WriteSpool(dev, "%RoundRect\n",11);
    PSDRV_SetPen(dev);
164

165 166 167
    PSDRV_SetClip(dev);
    PSDRV_WriteMoveTo( dev, left, top + ell_height/2 );
    PSDRV_WriteArc( dev, left + ell_width/2, top + ell_height/2, ell_width,
168
		    ell_height, 90.0, 180.0);
169 170
    PSDRV_WriteLineTo( dev, right - ell_width/2, top );
    PSDRV_WriteArc( dev, right - ell_width/2, top + ell_height/2, ell_width,
171
		    ell_height, 0.0, 90.0);
172 173
    PSDRV_WriteLineTo( dev, right, bottom - ell_height/2 );
    PSDRV_WriteArc( dev, right - ell_width/2, bottom - ell_height/2, ell_width,
174
		    ell_height, -90.0, 0.0);
175 176
    PSDRV_WriteLineTo( dev, right - ell_width/2, bottom);
    PSDRV_WriteArc( dev, left + ell_width/2, bottom - ell_height/2, ell_width,
177
		    ell_height, 180.0, -90.0);
178
    PSDRV_WriteClosePath( dev );
179

180 181 182
    PSDRV_Brush(dev,0);
    PSDRV_DrawLine(dev);
    PSDRV_ResetClip(dev);
183 184 185 186 187 188 189 190
    return TRUE;
}

/***********************************************************************
 *           PSDRV_DrawArc
 *
 * Does the work of Arc, Chord and Pie. lines is 0, 1 or 2 respectively.
 */
191
static BOOL PSDRV_DrawArc( PHYSDEV dev, INT left, INT top,
192 193
                           INT right, INT bottom, INT xstart, INT ystart,
                           INT xend, INT yend, int lines )
194
{
195
    INT x, y, h, w;
196
    double start_angle, end_angle, ratio;
197
    RECT rect;
198
    POINT start, end;
199

200
    SetRect(&rect, left, top, right, bottom);
201
    LPtoDP( dev->hdc, (POINT *)&rect, 2 );
202 203 204 205
    start.x = xstart;
    start.y = ystart;
    end.x = xend;
    end.y = yend;
206 207
    LPtoDP( dev->hdc, &start, 1 );
    LPtoDP( dev->hdc, &end, 1 );
208

209 210 211 212
    x = (rect.left + rect.right) / 2;
    y = (rect.top + rect.bottom) / 2;
    w = rect.right - rect.left;
    h = rect.bottom - rect.top;
213 214 215 216 217 218 219 220

    if(w < 0) w = -w;
    if(h < 0) h = -h;
    ratio = ((double)w)/h;

    /* angle is the angle after the rectangle is transformed to a square and is
       measured anticlockwise from the +ve x-axis */

221 222
    start_angle = atan2((double)(y - start.y) * ratio, (double)(start.x - x));
    end_angle = atan2((double)(y - end.y) * ratio, (double)(end.x - x));
223 224 225 226

    start_angle *= 180.0 / PI;
    end_angle *= 180.0 / PI;

227 228
    PSDRV_WriteSpool(dev,"%DrawArc\n", 9);
    PSDRV_SetPen(dev);
229

230
    PSDRV_SetClip(dev);
231
    if(lines == 2) /* pie */
232
        PSDRV_WriteMoveTo(dev, x, y);
233
    else
234
        PSDRV_WriteNewPath( dev );
235

236
    PSDRV_WriteArc(dev, x, y, w, h, start_angle, end_angle);
237
    if(lines == 1 || lines == 2) { /* chord or pie */
238 239
        PSDRV_WriteClosePath(dev);
	PSDRV_Brush(dev,0);
240
    }
241 242
    PSDRV_DrawLine(dev);
    PSDRV_ResetClip(dev);
243

244 245 246 247 248 249 250
    return TRUE;
}


/***********************************************************************
 *           PSDRV_Arc
 */
251 252
BOOL PSDRV_Arc( PHYSDEV dev, INT left, INT top, INT right, INT bottom,
                INT xstart, INT ystart, INT xend, INT yend )
253
{
254
    return PSDRV_DrawArc( dev, left, top, right, bottom, xstart, ystart, xend, yend, 0 );
255 256 257 258 259
}

/***********************************************************************
 *           PSDRV_Chord
 */
260 261
BOOL PSDRV_Chord( PHYSDEV dev, INT left, INT top, INT right, INT bottom,
                  INT xstart, INT ystart, INT xend, INT yend )
262
{
263
    return PSDRV_DrawArc( dev, left, top, right, bottom, xstart, ystart, xend, yend, 1 );
264 265 266 267 268 269
}


/***********************************************************************
 *           PSDRV_Pie
 */
270 271
BOOL PSDRV_Pie( PHYSDEV dev, INT left, INT top, INT right, INT bottom,
                INT xstart, INT ystart, INT xend, INT yend )
272
{
273
    return PSDRV_DrawArc( dev, left, top, right, bottom, xstart, ystart, xend, yend, 2 );
274 275 276
}


Alexandre Julliard's avatar
Alexandre Julliard committed
277 278 279
/***********************************************************************
 *           PSDRV_Ellipse
 */
280
BOOL PSDRV_Ellipse( PHYSDEV dev, INT left, INT top, INT right, INT bottom)
Alexandre Julliard's avatar
Alexandre Julliard committed
281
{
282
    INT x, y, w, h;
283
    RECT rect;
Alexandre Julliard's avatar
Alexandre Julliard committed
284

285
    TRACE("%d %d - %d %d\n", left, top, right, bottom);
Alexandre Julliard's avatar
Alexandre Julliard committed
286

287
    SetRect(&rect, left, top, right, bottom);
288
    LPtoDP( dev->hdc, (POINT *)&rect, 2 );
Alexandre Julliard's avatar
Alexandre Julliard committed
289

290 291 292 293
    x = (rect.left + rect.right) / 2;
    y = (rect.top + rect.bottom) / 2;
    w = rect.right - rect.left;
    h = rect.bottom - rect.top;
Alexandre Julliard's avatar
Alexandre Julliard committed
294

295 296
    PSDRV_WriteSpool(dev, "%Ellipse\n", 9);
    PSDRV_SetPen(dev);
297

298 299 300 301 302 303 304
    PSDRV_SetClip(dev);
    PSDRV_WriteNewPath(dev);
    PSDRV_WriteArc(dev, x, y, w, h, 0.0, 360.0);
    PSDRV_WriteClosePath(dev);
    PSDRV_Brush(dev,0);
    PSDRV_DrawLine(dev);
    PSDRV_ResetClip(dev);
Alexandre Julliard's avatar
Alexandre Julliard committed
305 306
    return TRUE;
}
Alexandre Julliard's avatar
Alexandre Julliard committed
307 308 309


/***********************************************************************
310
 *           PSDRV_PolyPolyline
Alexandre Julliard's avatar
Alexandre Julliard committed
311
 */
312
BOOL PSDRV_PolyPolyline( PHYSDEV dev, const POINT* pts, const DWORD* counts, DWORD polylines )
Alexandre Julliard's avatar
Alexandre Julliard committed
313
{
314 315
    DWORD polyline, line, total;
    POINT *dev_pts, *pt;
316

317
    TRACE("\n");
318

319 320 321
    for (polyline = total = 0; polyline < polylines; polyline++) total += counts[polyline];
    if (!(dev_pts = HeapAlloc( GetProcessHeap(), 0, total * sizeof(*dev_pts) ))) return FALSE;
    memcpy( dev_pts, pts, total * sizeof(*dev_pts) );
322
    LPtoDP( dev->hdc, dev_pts, total );
323 324

    pt = dev_pts;
325

326 327 328
    PSDRV_WriteSpool(dev, "%PolyPolyline\n",14);
    PSDRV_SetPen(dev);
    PSDRV_SetClip(dev);
329

330
    for(polyline = 0; polyline < polylines; polyline++) {
331
        PSDRV_WriteMoveTo(dev, pt->x, pt->y);
332
	pt++;
333
        for(line = 1; line < counts[polyline]; line++, pt++)
334
            PSDRV_WriteLineTo(dev, pt->x, pt->y);
335
    }
336
    HeapFree( GetProcessHeap(), 0, dev_pts );
337

338 339
    PSDRV_DrawLine(dev);
    PSDRV_ResetClip(dev);
Alexandre Julliard's avatar
Alexandre Julliard committed
340
    return TRUE;
341
}
342 343


Alexandre Julliard's avatar
Alexandre Julliard committed
344
/***********************************************************************
345
 *           PSDRV_PolyPolygon
Alexandre Julliard's avatar
Alexandre Julliard committed
346
 */
347
BOOL PSDRV_PolyPolygon( PHYSDEV dev, const POINT* pts, const INT* counts, UINT polygons )
Alexandre Julliard's avatar
Alexandre Julliard committed
348
{
349 350
    DWORD polygon, total;
    INT line;
351
    POINT *dev_pts, *pt;
352

353
    TRACE("\n");
Alexandre Julliard's avatar
Alexandre Julliard committed
354

355 356 357
    for (polygon = total = 0; polygon < polygons; polygon++) total += counts[polygon];
    if (!(dev_pts = HeapAlloc( GetProcessHeap(), 0, total * sizeof(*dev_pts) ))) return FALSE;
    memcpy( dev_pts, pts, total * sizeof(*dev_pts) );
358
    LPtoDP( dev->hdc, dev_pts, total );
359 360

    pt = dev_pts;
361

362 363 364
    PSDRV_WriteSpool(dev, "%PolyPolygon\n",13);
    PSDRV_SetPen(dev);
    PSDRV_SetClip(dev);
365

366
    for(polygon = 0; polygon < polygons; polygon++) {
367
        PSDRV_WriteMoveTo(dev, pt->x, pt->y);
368
	pt++;
369
        for(line = 1; line < counts[polygon]; line++, pt++)
370 371
            PSDRV_WriteLineTo(dev, pt->x, pt->y);
	PSDRV_WriteClosePath(dev);
372
    }
373
    HeapFree( GetProcessHeap(), 0, dev_pts );
Alexandre Julliard's avatar
Alexandre Julliard committed
374

375 376
    if(GetPolyFillMode( dev->hdc ) == ALTERNATE)
        PSDRV_Brush(dev, 1);
377
    else /* WINDING */
378
        PSDRV_Brush(dev, 0);
379

380 381
    PSDRV_DrawLine(dev);
    PSDRV_ResetClip(dev);
Alexandre Julliard's avatar
Alexandre Julliard committed
382 383 384
    return TRUE;
}

385

386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439
/***********************************************************************
 *           PSDRV_PolyBezier
 */
BOOL PSDRV_PolyBezier( PHYSDEV dev, const POINT *pts, DWORD count )
{
    DWORD i;
    POINT *dev_pts;

    TRACE("\n");

    if (!(dev_pts = HeapAlloc( GetProcessHeap(), 0, count * sizeof(*dev_pts) ))) return FALSE;
    memcpy( dev_pts, pts, count * sizeof(*dev_pts) );
    LPtoDP( dev->hdc, dev_pts, count );

    PSDRV_WriteSpool(dev, "%PolyBezier\n",12);
    PSDRV_SetPen(dev);
    PSDRV_SetClip(dev);
    PSDRV_WriteMoveTo(dev, dev_pts[0].x, dev_pts[0].y );
    for (i = 1; i < count; i += 3) PSDRV_WriteCurveTo( dev, dev_pts + i );
    PSDRV_DrawLine(dev);
    PSDRV_ResetClip(dev);
    HeapFree( GetProcessHeap(), 0, dev_pts );
    return TRUE;
}


/***********************************************************************
 *           PSDRV_PolyBezierTo
 */
BOOL PSDRV_PolyBezierTo( PHYSDEV dev, const POINT *pts, DWORD count )
{
    DWORD i;
    POINT *dev_pts;

    TRACE("\n");

    count++;  /* add initial position */
    if (!(dev_pts = HeapAlloc( GetProcessHeap(), 0, count * sizeof(*dev_pts) ))) return FALSE;
    GetCurrentPositionEx( dev->hdc, dev_pts );
    memcpy( dev_pts + 1, pts, (count - 1) * sizeof(*dev_pts) );
    LPtoDP( dev->hdc, dev_pts, count );

    PSDRV_WriteSpool(dev, "%PolyBezier\n",12);
    PSDRV_SetPen(dev);
    PSDRV_SetClip(dev);
    PSDRV_WriteMoveTo(dev, dev_pts[0].x, dev_pts[0].y );
    for (i = 1; i < count; i += 3) PSDRV_WriteCurveTo( dev, dev_pts + i );
    PSDRV_DrawLine(dev);
    PSDRV_ResetClip(dev);
    HeapFree( GetProcessHeap(), 0, dev_pts );
    return TRUE;
}


440 441 442
/***********************************************************************
 *           PSDRV_SetPixel
 */
443
COLORREF PSDRV_SetPixel( PHYSDEV dev, INT x, INT y, COLORREF color )
444 445
{
    PSCOLOR pscolor;
446
    POINT pt;
447

448 449
    pt.x = x;
    pt.y = y;
450
    LPtoDP( dev->hdc, &pt, 1 );
451

452
    PSDRV_SetClip(dev);
453 454
    /* we bracket the setcolor in gsave/grestore so that we don't trash
       the current pen colour */
455 456 457 458 459 460 461
    PSDRV_WriteGSave(dev);
    PSDRV_WriteRectangle( dev, pt.x, pt.y, 0, 0 );
    PSDRV_CreateColor( dev, &pscolor, color );
    PSDRV_WriteSetColor( dev, &pscolor );
    PSDRV_WriteFill( dev );
    PSDRV_WriteGRestore(dev);
    PSDRV_ResetClip(dev);
462 463
    return color;
}
464 465 466 467

/***********************************************************************
 *           PSDRV_PaintRgn
 */
468
BOOL PSDRV_PaintRgn( PHYSDEV dev, HRGN hrgn )
469 470 471 472 473
{
    RGNDATA *rgndata = NULL;
    RECT *pRect;
    DWORD size, i;

474
    TRACE("hdc=%p\n", dev->hdc);
475 476 477 478 479 480 481 482 483 484 485 486

    size = GetRegionData(hrgn, 0, NULL);
    rgndata = HeapAlloc( GetProcessHeap(), 0, size );
    if(!rgndata) {
        ERR("Can't allocate buffer\n");
        return FALSE;
    }
    
    GetRegionData(hrgn, size, rgndata);
    if (rgndata->rdh.nCount == 0)
        goto end;

487
    LPtoDP(dev->hdc, (POINT*)rgndata->Buffer, rgndata->rdh.nCount * 2);
488

489
    PSDRV_SetClip(dev);
490
    for(i = 0, pRect = (RECT*)rgndata->Buffer; i < rgndata->rdh.nCount; i++, pRect++)
491
        PSDRV_WriteRectangle(dev, pRect->left, pRect->top, pRect->right - pRect->left, pRect->bottom - pRect->top);
492

493
    PSDRV_Brush(dev, 0);
494
    PSDRV_WriteNewPath(dev);
495
    PSDRV_ResetClip(dev);
496 497 498 499 500

 end:
    HeapFree(GetProcessHeap(), 0, rgndata);
    return TRUE;
}
501 502 503 504 505 506 507 508 509

static BOOL paint_path( PHYSDEV dev, BOOL stroke, BOOL fill )
{
    POINT *points;
    BYTE *types;
    BOOL ret = FALSE;
    int i, size = GetPath( dev->hdc, NULL, NULL, 0 );

    if (size == -1) return FALSE;
510 511 512 513 514
    if (!size)
    {
        AbortPath( dev->hdc );
        return TRUE;
    }
515 516 517 518
    points = HeapAlloc( GetProcessHeap(), 0, size * sizeof(*points) );
    types = HeapAlloc( GetProcessHeap(), 0, size * sizeof(*types) );
    if (!points || !types) goto done;
    if (GetPath( dev->hdc, points, types, size ) == -1) goto done;
519
    LPtoDP( dev->hdc, points, size );
520

521
    if (stroke) PSDRV_SetPen(dev);
522 523 524
    PSDRV_SetClip(dev);
    for (i = 0; i < size; i++)
    {
525
        switch (types[i])
526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546
        {
        case PT_MOVETO:
            PSDRV_WriteMoveTo( dev, points[i].x, points[i].y );
            break;
        case PT_LINETO:
        case PT_LINETO | PT_CLOSEFIGURE:
            PSDRV_WriteLineTo( dev, points[i].x, points[i].y );
            if (types[i] & PT_CLOSEFIGURE) PSDRV_WriteClosePath( dev );
            break;
        case PT_BEZIERTO:
        case PT_BEZIERTO | PT_CLOSEFIGURE:
            PSDRV_WriteCurveTo( dev, points + i );
            if (types[i] & PT_CLOSEFIGURE) PSDRV_WriteClosePath( dev );
            i += 2;
            break;
        }
    }
    if (fill) PSDRV_Brush( dev, GetPolyFillMode(dev->hdc) == ALTERNATE );
    if (stroke) PSDRV_DrawLine(dev);
    else PSDRV_WriteNewPath(dev);
    PSDRV_ResetClip(dev);
547
    AbortPath( dev->hdc );
548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577

done:
    HeapFree( GetProcessHeap(), 0, points );
    HeapFree( GetProcessHeap(), 0, types );
    return ret;
}

/***********************************************************************
 *           PSDRV_FillPath
 */
BOOL PSDRV_FillPath( PHYSDEV dev )
{
    return paint_path( dev, FALSE, TRUE );
}

/***********************************************************************
 *           PSDRV_StrokeAndFillPath
 */
BOOL PSDRV_StrokeAndFillPath( PHYSDEV dev )
{
    return paint_path( dev, TRUE, TRUE );
}

/***********************************************************************
 *           PSDRV_StrokePath
 */
BOOL PSDRV_StrokePath( PHYSDEV dev )
{
    return paint_path( dev, TRUE, FALSE );
}