graphics.c 16.3 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 <stdio.h>
Alexandre Julliard's avatar
Alexandre Julliard committed
24
#include <string.h>
25
#include <math.h>
26
#if defined(HAVE_FLOAT_H)
27
# include <float.h>
28 29
#endif
#if !defined(PI)
30
# define PI M_PI
31
#endif
Alexandre Julliard's avatar
Alexandre Julliard committed
32
#include "psdrv.h"
33
#include "wine/debug.h"
Alexandre Julliard's avatar
Alexandre Julliard committed
34

35
WINE_DEFAULT_DEBUG_CHANNEL(psdrv);
36

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

    pt[0].x = 0;
    pt[0].y = 0;
    pt[1].x = width;
    pt[1].y = 0;
50
    LPtoDP( dev->hdc, pt, 2 );
51 52 53
    return pt[1].x - pt[0].x;
}

54 55 56
/***********************************************************************
 *           PSDRV_DrawLine
 */
57
static void PSDRV_DrawLine( PHYSDEV dev )
58
{
59 60
    PSDRV_PDEVICE *physDev = get_psdrv_dev( dev );

61 62 63 64
    if(physDev->pathdepth)
        return;

    if (physDev->pen.style == PS_NULL)
65
	PSDRV_WriteNewPath(dev);
66
    else
67
	PSDRV_WriteStroke(dev);
68
}
69

Alexandre Julliard's avatar
Alexandre Julliard committed
70 71 72
/***********************************************************************
 *           PSDRV_LineTo
 */
73
BOOL PSDRV_LineTo(PHYSDEV dev, INT x, INT y)
Alexandre Julliard's avatar
Alexandre Julliard committed
74
{
75
    POINT pt[2];
76

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

79
    GetCurrentPositionEx( dev->hdc, pt );
80 81
    pt[1].x = x;
    pt[1].y = y;
82
    LPtoDP( dev->hdc, pt, 2 );
83

84
    PSDRV_SetPen(dev);
85

86 87 88 89 90
    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
91 92 93 94

    return TRUE;
}

95

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

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

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

112
    /* Windows does something truly hacky here.  If we're in passthrough mode
113 114
       and our rop is R2_NOP, then we output the string below.  This is used in
       Office 2k when inserting eps files */
115
    if(physDev->job.in_passthrough && !physDev->job.had_passthrough_rect && GetROP2(dev->hdc) == R2_NOP) {
116
      char buf[256];
117
      sprintf(buf, "N %d %d %d %d B\n", rect.right - rect.left, rect.bottom - rect.top, rect.left, rect.top);
118
      write_spool(dev, buf, strlen(buf));
119
      physDev->job.had_passthrough_rect = TRUE;
120 121 122
      return TRUE;
    }

123
    PSDRV_SetPen(dev);
124

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


135 136 137
/***********************************************************************
 *           PSDRV_RoundRect
 */
138 139
BOOL PSDRV_RoundRect( PHYSDEV dev, INT left, INT top, INT right,
                      INT bottom, INT ell_width, INT ell_height )
140
{
141 142 143 144 145 146 147 148 149 150
    RECT rect[2];

    rect[0].left   = left;
    rect[0].top    = top;
    rect[0].right  = right;
    rect[0].bottom = bottom;
    rect[1].left   = 0;
    rect[1].top    = 0;
    rect[1].right  = ell_width;
    rect[1].bottom = ell_height;
151
    LPtoDP( dev->hdc, (POINT *)rect, 4 );
152 153 154 155 156 157 158 159 160 161 162 163

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

165 166
    PSDRV_WriteSpool(dev, "%RoundRect\n",11);
    PSDRV_SetPen(dev);
167

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

183 184 185
    PSDRV_Brush(dev,0);
    PSDRV_DrawLine(dev);
    PSDRV_ResetClip(dev);
186 187 188 189 190 191 192 193
    return TRUE;
}

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

203 204 205 206
    rect.left = left;
    rect.top = top;
    rect.right = right;
    rect.bottom = bottom;
207
    LPtoDP( dev->hdc, (POINT *)&rect, 2 );
208 209 210 211
    start.x = xstart;
    start.y = ystart;
    end.x = xend;
    end.y = yend;
212 213
    LPtoDP( dev->hdc, &start, 1 );
    LPtoDP( dev->hdc, &end, 1 );
214

215 216 217 218
    x = (rect.left + rect.right) / 2;
    y = (rect.top + rect.bottom) / 2;
    w = rect.right - rect.left;
    h = rect.bottom - rect.top;
219 220 221 222 223 224 225 226

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

227 228
    start_angle = atan2((double)(y - start.y) * ratio, (double)(start.x - x));
    end_angle = atan2((double)(y - end.y) * ratio, (double)(end.x - x));
229 230 231 232

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

233 234
    PSDRV_WriteSpool(dev,"%DrawArc\n", 9);
    PSDRV_SetPen(dev);
235

236
    PSDRV_SetClip(dev);
237
    if(lines == 2) /* pie */
238
        PSDRV_WriteMoveTo(dev, x, y);
239
    else
240
        PSDRV_WriteNewPath( dev );
241

242
    PSDRV_WriteArc(dev, x, y, w, h, start_angle, end_angle);
243
    if(lines == 1 || lines == 2) { /* chord or pie */
244 245
        PSDRV_WriteClosePath(dev);
	PSDRV_Brush(dev,0);
246
    }
247 248
    PSDRV_DrawLine(dev);
    PSDRV_ResetClip(dev);
249

250 251 252 253 254 255 256
    return TRUE;
}


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

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


/***********************************************************************
 *           PSDRV_Pie
 */
276 277
BOOL PSDRV_Pie( PHYSDEV dev, INT left, INT top, INT right, INT bottom,
                INT xstart, INT ystart, INT xend, INT yend )
278
{
279
    return PSDRV_DrawArc( dev, left, top, right, bottom, xstart, ystart, xend, yend, 2 );
280 281 282
}


Alexandre Julliard's avatar
Alexandre Julliard committed
283 284 285
/***********************************************************************
 *           PSDRV_Ellipse
 */
286
BOOL PSDRV_Ellipse( PHYSDEV dev, INT left, INT top, INT right, INT bottom)
Alexandre Julliard's avatar
Alexandre Julliard committed
287
{
288
    INT x, y, w, h;
289
    RECT rect;
Alexandre Julliard's avatar
Alexandre Julliard committed
290

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

293 294 295 296
    rect.left   = left;
    rect.top    = top;
    rect.right  = right;
    rect.bottom = bottom;
297
    LPtoDP( dev->hdc, (POINT *)&rect, 2 );
Alexandre Julliard's avatar
Alexandre Julliard committed
298

299 300 301 302
    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
303

304 305
    PSDRV_WriteSpool(dev, "%Ellipse\n", 9);
    PSDRV_SetPen(dev);
306

307 308 309 310 311 312 313
    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
314 315
    return TRUE;
}
Alexandre Julliard's avatar
Alexandre Julliard committed
316 317 318


/***********************************************************************
319
 *           PSDRV_PolyPolyline
Alexandre Julliard's avatar
Alexandre Julliard committed
320
 */
321
BOOL PSDRV_PolyPolyline( PHYSDEV dev, const POINT* pts, const DWORD* counts, DWORD polylines )
Alexandre Julliard's avatar
Alexandre Julliard committed
322
{
323 324
    DWORD polyline, line, total;
    POINT *dev_pts, *pt;
325

326
    TRACE("\n");
327

328 329 330
    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) );
331
    LPtoDP( dev->hdc, dev_pts, total );
332 333

    pt = dev_pts;
334

335 336 337
    PSDRV_WriteSpool(dev, "%PolyPolyline\n",14);
    PSDRV_SetPen(dev);
    PSDRV_SetClip(dev);
338

339
    for(polyline = 0; polyline < polylines; polyline++) {
340
        PSDRV_WriteMoveTo(dev, pt->x, pt->y);
341
	pt++;
342
        for(line = 1; line < counts[polyline]; line++, pt++)
343
            PSDRV_WriteLineTo(dev, pt->x, pt->y);
344
    }
345
    HeapFree( GetProcessHeap(), 0, dev_pts );
346

347 348
    PSDRV_DrawLine(dev);
    PSDRV_ResetClip(dev);
Alexandre Julliard's avatar
Alexandre Julliard committed
349
    return TRUE;
350
}
351 352


Alexandre Julliard's avatar
Alexandre Julliard committed
353
/***********************************************************************
354
 *           PSDRV_PolyPolygon
Alexandre Julliard's avatar
Alexandre Julliard committed
355
 */
356
BOOL PSDRV_PolyPolygon( PHYSDEV dev, const POINT* pts, const INT* counts, UINT polygons )
Alexandre Julliard's avatar
Alexandre Julliard committed
357
{
358 359
    DWORD polygon, total;
    INT line;
360
    POINT *dev_pts, *pt;
361

362
    TRACE("\n");
Alexandre Julliard's avatar
Alexandre Julliard committed
363

364 365 366
    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) );
367
    LPtoDP( dev->hdc, dev_pts, total );
368 369

    pt = dev_pts;
370

371 372 373
    PSDRV_WriteSpool(dev, "%PolyPolygon\n",13);
    PSDRV_SetPen(dev);
    PSDRV_SetClip(dev);
374

375
    for(polygon = 0; polygon < polygons; polygon++) {
376
        PSDRV_WriteMoveTo(dev, pt->x, pt->y);
377
	pt++;
378
        for(line = 1; line < counts[polygon]; line++, pt++)
379 380
            PSDRV_WriteLineTo(dev, pt->x, pt->y);
	PSDRV_WriteClosePath(dev);
381
    }
382
    HeapFree( GetProcessHeap(), 0, dev_pts );
Alexandre Julliard's avatar
Alexandre Julliard committed
383

384 385
    if(GetPolyFillMode( dev->hdc ) == ALTERNATE)
        PSDRV_Brush(dev, 1);
386
    else /* WINDING */
387
        PSDRV_Brush(dev, 0);
388

389 390
    PSDRV_DrawLine(dev);
    PSDRV_ResetClip(dev);
Alexandre Julliard's avatar
Alexandre Julliard committed
391 392 393
    return TRUE;
}

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 440 441 442 443 444 445 446 447 448
/***********************************************************************
 *           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;
}


449 450 451
/***********************************************************************
 *           PSDRV_SetPixel
 */
452
COLORREF PSDRV_SetPixel( PHYSDEV dev, INT x, INT y, COLORREF color )
453 454
{
    PSCOLOR pscolor;
455
    POINT pt;
456

457 458
    pt.x = x;
    pt.y = y;
459
    LPtoDP( dev->hdc, &pt, 1 );
460

461
    PSDRV_SetClip(dev);
462 463
    /* we bracket the setcolor in gsave/grestore so that we don't trash
       the current pen colour */
464 465 466 467 468 469 470
    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);
471 472
    return color;
}
473 474 475 476

/***********************************************************************
 *           PSDRV_PaintRgn
 */
477
BOOL PSDRV_PaintRgn( PHYSDEV dev, HRGN hrgn )
478 479 480 481 482
{
    RGNDATA *rgndata = NULL;
    RECT *pRect;
    DWORD size, i;

483
    TRACE("hdc=%p\n", dev->hdc);
484 485 486 487 488 489 490 491 492 493 494 495

    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;

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

498
    PSDRV_SetClip(dev);
499
    for(i = 0, pRect = (RECT*)rgndata->Buffer; i < rgndata->rdh.nCount; i++, pRect++)
500
        PSDRV_WriteRectangle(dev, pRect->left, pRect->top, pRect->right - pRect->left, pRect->bottom - pRect->top);
501

502
    PSDRV_Brush(dev, 0);
503
    PSDRV_WriteNewPath(dev);
504
    PSDRV_ResetClip(dev);
505 506 507 508 509

 end:
    HeapFree(GetProcessHeap(), 0, rgndata);
    return TRUE;
}
510 511 512 513 514 515 516 517 518 519 520 521 522 523

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;
    if (!size) return TRUE;
    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;
524
    LPtoDP( dev->hdc, points, size );
525

526
    if (stroke) PSDRV_SetPen(dev);
527 528 529
    PSDRV_SetClip(dev);
    for (i = 0; i < size; i++)
    {
530
        switch (types[i])
531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 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 576 577 578 579 580 581
        {
        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);

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