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
    if(physDev->job.in_passthrough && !physDev->job.had_passthrough_rect && GetROP2(dev->hdc) == R2_NOP) {
117
      char buf[256];
118
      sprintf(buf, "N %d %d %d %d B\n", rect.right - rect.left, rect.bottom - rect.top, rect.left, rect.top);
119
      write_spool(dev, buf, strlen(buf));
120
      physDev->job.had_passthrough_rect = TRUE;
121 122 123
      return TRUE;
    }

124
    PSDRV_SetPen(dev);
125

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


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

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

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

160 161
    PSDRV_WriteSpool(dev, "%RoundRect\n",11);
    PSDRV_SetPen(dev);
162

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

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

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

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

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

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

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

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

225 226
    PSDRV_WriteSpool(dev,"%DrawArc\n", 9);
    PSDRV_SetPen(dev);
227

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

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

242 243 244 245 246 247 248
    return TRUE;
}


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

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


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


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

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

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

288 289 290 291
    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
292

293 294
    PSDRV_WriteSpool(dev, "%Ellipse\n", 9);
    PSDRV_SetPen(dev);
295

296 297 298 299 300 301 302
    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
303 304
    return TRUE;
}
Alexandre Julliard's avatar
Alexandre Julliard committed
305 306 307


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

315
    TRACE("\n");
316

317 318 319
    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) );
320
    LPtoDP( dev->hdc, dev_pts, total );
321 322

    pt = dev_pts;
323

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

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

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


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

351
    TRACE("\n");
Alexandre Julliard's avatar
Alexandre Julliard committed
352

353 354 355
    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) );
356
    LPtoDP( dev->hdc, dev_pts, total );
357 358

    pt = dev_pts;
359

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

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

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

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

383

384 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
/***********************************************************************
 *           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;
}


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

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

450
    PSDRV_SetClip(dev);
451 452
    /* we bracket the setcolor in gsave/grestore so that we don't trash
       the current pen colour */
453 454 455 456 457 458 459
    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);
460 461
    return color;
}
462 463 464 465

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

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

    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;

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

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

491
    PSDRV_Brush(dev, 0);
492
    PSDRV_WriteNewPath(dev);
493
    PSDRV_ResetClip(dev);
494 495 496 497 498

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

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;
508 509 510 511 512
    if (!size)
    {
        AbortPath( dev->hdc );
        return TRUE;
    }
513 514 515 516
    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;
517
    LPtoDP( dev->hdc, points, size );
518

519
    if (stroke) PSDRV_SetPen(dev);
520 521 522
    PSDRV_SetClip(dev);
    for (i = 0; i < size; i++)
    {
523
        switch (types[i])
524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544
        {
        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);
545
    AbortPath( dev->hdc );
546 547 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

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