graphics.c 14 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 18
 * 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
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  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"
34
#include "winspool.h"
Alexandre Julliard's avatar
Alexandre Julliard committed
35

36
WINE_DEFAULT_DEBUG_CHANNEL(psdrv);
37

38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71
/***********************************************************************
 *           PSDRV_XWStoDS
 *
 * Performs a world-to-viewport transformation on the specified width.
 */
INT PSDRV_XWStoDS( PSDRV_PDEVICE *physDev, INT width )
{
    POINT pt[2];

    pt[0].x = 0;
    pt[0].y = 0;
    pt[1].x = width;
    pt[1].y = 0;
    LPtoDP( physDev->hdc, pt, 2 );
    return pt[1].x - pt[0].x;
}

/***********************************************************************
 *           PSDRV_YWStoDS
 *
 * Performs a world-to-viewport transformation on the specified height.
 */
INT PSDRV_YWStoDS( PSDRV_PDEVICE *physDev, INT height )
{
    POINT pt[2];

    pt[0].x = 0;
    pt[0].y = 0;
    pt[1].x = 0;
    pt[1].y = height;
    LPtoDP( physDev->hdc, pt, 2 );
    return pt[1].y - pt[0].y;
}

72 73 74 75 76 77 78 79 80 81 82 83 84
/***********************************************************************
 *           PSDRV_DrawLine
 */
static void PSDRV_DrawLine( PSDRV_PDEVICE *physDev )
{
    if(physDev->pathdepth)
        return;

    if (physDev->pen.style == PS_NULL)
	PSDRV_WriteNewPath(physDev);
    else
	PSDRV_WriteStroke(physDev);
}
85

Alexandre Julliard's avatar
Alexandre Julliard committed
86 87 88
/***********************************************************************
 *           PSDRV_LineTo
 */
89
BOOL PSDRV_LineTo(PSDRV_PDEVICE *physDev, INT x, INT y)
Alexandre Julliard's avatar
Alexandre Julliard committed
90
{
91
    POINT pt[2];
92

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

95 96 97 98 99
    GetCurrentPositionEx( physDev->hdc, pt );
    pt[1].x = x;
    pt[1].y = y;
    LPtoDP( physDev->hdc, pt, 2 );

100
    PSDRV_SetPen(physDev);
101 102

    PSDRV_SetClip(physDev);
103 104
    PSDRV_WriteMoveTo(physDev, pt[0].x, pt[0].y );
    PSDRV_WriteLineTo(physDev, pt[1].x, pt[1].y );
105
    PSDRV_DrawLine(physDev);
106
    PSDRV_ResetClip(physDev);
Alexandre Julliard's avatar
Alexandre Julliard committed
107 108 109 110

    return TRUE;
}

111

Alexandre Julliard's avatar
Alexandre Julliard committed
112 113 114
/***********************************************************************
 *           PSDRV_Rectangle
 */
115
BOOL PSDRV_Rectangle( PSDRV_PDEVICE *physDev, INT left, INT top, INT right, INT bottom )
Alexandre Julliard's avatar
Alexandre Julliard committed
116
{
117
    RECT rect;
Alexandre Julliard's avatar
Alexandre Julliard committed
118

119
    TRACE("%d %d - %d %d\n", left, top, right, bottom);
120 121 122 123 124 125 126

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

127
    /* Windows does something truly hacky here.  If we're in passthrough mode
128 129 130
       and our rop is R2_NOP, then we output the string below.  This is used in
       Office 2k when inserting eps files */
    if(physDev->job.in_passthrough && !physDev->job.had_passthrough_rect && GetROP2(physDev->hdc) == R2_NOP) {
131
      char buf[256];
132 133 134
      sprintf(buf, "N %ld %ld %ld %ld B\n", rect.right - rect.left, rect.bottom - rect.top, rect.left, rect.top);
      WriteSpool16(physDev->job.hJob, buf, strlen(buf));
      physDev->job.had_passthrough_rect = TRUE;
135 136 137 138 139 140
      return TRUE;
    }

    PSDRV_SetPen(physDev);

    PSDRV_SetClip(physDev);
141 142
    PSDRV_WriteRectangle(physDev, rect.left, rect.top, rect.right - rect.left,
                         rect.bottom - rect.top );
143 144
    PSDRV_Brush(physDev,0);
    PSDRV_DrawLine(physDev);
145
    PSDRV_ResetClip(physDev);
Alexandre Julliard's avatar
Alexandre Julliard committed
146 147 148 149
    return TRUE;
}


150 151 152
/***********************************************************************
 *           PSDRV_RoundRect
 */
153 154
BOOL PSDRV_RoundRect( PSDRV_PDEVICE *physDev, INT left, INT top, INT right,
                      INT bottom, INT ell_width, INT ell_height )
155
{
156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178
    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;
    LPtoDP( physDev->hdc, (POINT *)rect, 4 );

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

180 181 182 183
    PSDRV_WriteSpool(physDev, "%RoundRect\n",11);
    PSDRV_SetPen(physDev);

    PSDRV_SetClip(physDev);
184 185
    PSDRV_WriteMoveTo( physDev, left, top + ell_height/2 );
    PSDRV_WriteArc( physDev, left + ell_width/2, top + ell_height/2, ell_width,
186
		    ell_height, 90.0, 180.0);
187 188
    PSDRV_WriteLineTo( physDev, right - ell_width/2, top );
    PSDRV_WriteArc( physDev, right - ell_width/2, top + ell_height/2, ell_width,
189
		    ell_height, 0.0, 90.0);
190 191
    PSDRV_WriteLineTo( physDev, right, bottom - ell_height/2 );
    PSDRV_WriteArc( physDev, right - ell_width/2, bottom - ell_height/2, ell_width,
192
		    ell_height, -90.0, 0.0);
193 194
    PSDRV_WriteLineTo( physDev, right - ell_width/2, bottom);
    PSDRV_WriteArc( physDev, left + ell_width/2, bottom - ell_height/2, ell_width,
195
		    ell_height, 180.0, -90.0);
196
    PSDRV_WriteClosePath( physDev );
197

198 199
    PSDRV_Brush(physDev,0);
    PSDRV_DrawLine(physDev);
200
    PSDRV_ResetClip(physDev);
201 202 203 204 205 206 207 208
    return TRUE;
}

/***********************************************************************
 *           PSDRV_DrawArc
 *
 * Does the work of Arc, Chord and Pie. lines is 0, 1 or 2 respectively.
 */
209 210 211
static BOOL PSDRV_DrawArc( PSDRV_PDEVICE *physDev, INT left, INT top,
                           INT right, INT bottom, INT xstart, INT ystart,
                           INT xend, INT yend, int lines )
212
{
213
    INT x, y, h, w;
214
    double start_angle, end_angle, ratio;
215
    RECT rect;
216
    POINT start, end;
217

218 219 220 221 222
    rect.left = left;
    rect.top = top;
    rect.right = right;
    rect.bottom = bottom;
    LPtoDP( physDev->hdc, (POINT *)&rect, 2 );
223 224 225 226 227 228
    start.x = xstart;
    start.y = ystart;
    end.x = xend;
    end.y = yend;
    LPtoDP( physDev->hdc, &start, 1 );
    LPtoDP( physDev->hdc, &end, 1 );
229

230 231 232 233
    x = (rect.left + rect.right) / 2;
    y = (rect.top + rect.bottom) / 2;
    w = rect.right - rect.left;
    h = rect.bottom - rect.top;
234 235 236 237 238 239 240 241

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

242 243
    start_angle = atan2((double)(y - start.y) * ratio, (double)(start.x - x));
    end_angle = atan2((double)(y - end.y) * ratio, (double)(end.x - x));
244 245 246 247

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

248 249 250 251
    PSDRV_WriteSpool(physDev,"%DrawArc\n", 9);
    PSDRV_SetPen(physDev);

    PSDRV_SetClip(physDev);
252
    if(lines == 2) /* pie */
253
        PSDRV_WriteMoveTo(physDev, x, y);
254
    else
255
        PSDRV_WriteNewPath( physDev );
256

257
    PSDRV_WriteArc(physDev, x, y, w, h, start_angle, end_angle);
258
    if(lines == 1 || lines == 2) { /* chord or pie */
259 260
        PSDRV_WriteClosePath(physDev);
	PSDRV_Brush(physDev,0);
261
    }
262
    PSDRV_DrawLine(physDev);
263 264
    PSDRV_ResetClip(physDev);

265 266 267 268 269 270 271
    return TRUE;
}


/***********************************************************************
 *           PSDRV_Arc
 */
272 273
BOOL PSDRV_Arc( PSDRV_PDEVICE *physDev, INT left, INT top, INT right, INT bottom,
                INT xstart, INT ystart, INT xend, INT yend )
274
{
275
    return PSDRV_DrawArc( physDev, left, top, right, bottom, xstart, ystart, xend, yend, 0 );
276 277 278 279 280
}

/***********************************************************************
 *           PSDRV_Chord
 */
281 282
BOOL PSDRV_Chord( PSDRV_PDEVICE *physDev, INT left, INT top, INT right, INT bottom,
                  INT xstart, INT ystart, INT xend, INT yend )
283
{
284
    return PSDRV_DrawArc( physDev, left, top, right, bottom, xstart, ystart, xend, yend, 1 );
285 286 287 288 289 290
}


/***********************************************************************
 *           PSDRV_Pie
 */
291 292
BOOL PSDRV_Pie( PSDRV_PDEVICE *physDev, INT left, INT top, INT right, INT bottom,
                INT xstart, INT ystart, INT xend, INT yend )
293
{
294
    return PSDRV_DrawArc( physDev, left, top, right, bottom, xstart, ystart, xend, yend, 2 );
295 296 297
}


Alexandre Julliard's avatar
Alexandre Julliard committed
298 299 300
/***********************************************************************
 *           PSDRV_Ellipse
 */
301
BOOL PSDRV_Ellipse( PSDRV_PDEVICE *physDev, INT left, INT top, INT right, INT bottom)
Alexandre Julliard's avatar
Alexandre Julliard committed
302
{
303
    INT x, y, w, h;
304
    RECT rect;
Alexandre Julliard's avatar
Alexandre Julliard committed
305

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

308 309 310 311 312
    rect.left   = left;
    rect.top    = top;
    rect.right  = right;
    rect.bottom = bottom;
    LPtoDP( physDev->hdc, (POINT *)&rect, 2 );
Alexandre Julliard's avatar
Alexandre Julliard committed
313

314 315 316 317
    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
318

319 320 321 322
    PSDRV_WriteSpool(physDev, "%Ellipse\n", 9);
    PSDRV_SetPen(physDev);

    PSDRV_SetClip(physDev);
323 324 325 326 327
    PSDRV_WriteNewPath(physDev);
    PSDRV_WriteArc(physDev, x, y, w, h, 0.0, 360.0);
    PSDRV_WriteClosePath(physDev);
    PSDRV_Brush(physDev,0);
    PSDRV_DrawLine(physDev);
328
    PSDRV_ResetClip(physDev);
Alexandre Julliard's avatar
Alexandre Julliard committed
329 330
    return TRUE;
}
Alexandre Julliard's avatar
Alexandre Julliard committed
331 332 333


/***********************************************************************
334
 *           PSDRV_PolyPolyline
Alexandre Julliard's avatar
Alexandre Julliard committed
335
 */
336
BOOL PSDRV_PolyPolyline( PSDRV_PDEVICE *physDev, const POINT* pts, const DWORD* counts,
337
                         DWORD polylines )
Alexandre Julliard's avatar
Alexandre Julliard committed
338
{
339 340
    DWORD polyline, line, total;
    POINT *dev_pts, *pt;
341

342
    TRACE("\n");
343

344 345 346 347 348 349
    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) );
    LPtoDP( physDev->hdc, dev_pts, total );

    pt = dev_pts;
350 351 352 353 354

    PSDRV_WriteSpool(physDev, "%PolyPolyline\n",14);
    PSDRV_SetPen(physDev);
    PSDRV_SetClip(physDev);

355
    for(polyline = 0; polyline < polylines; polyline++) {
356
        PSDRV_WriteMoveTo(physDev, pt->x, pt->y);
357
	pt++;
358 359
        for(line = 1; line < counts[polyline]; line++, pt++)
            PSDRV_WriteLineTo(physDev, pt->x, pt->y);
360
    }
361
    HeapFree( GetProcessHeap(), 0, dev_pts );
362

363
    PSDRV_DrawLine(physDev);
364
    PSDRV_ResetClip(physDev);
Alexandre Julliard's avatar
Alexandre Julliard committed
365
    return TRUE;
366
}
367 368 369 370 371


/***********************************************************************
 *           PSDRV_Polyline
 */
372
BOOL PSDRV_Polyline( PSDRV_PDEVICE *physDev, const POINT* pt, INT count )
373
{
374
    return PSDRV_PolyPolyline( physDev, pt, (LPDWORD) &count, 1 );
Alexandre Julliard's avatar
Alexandre Julliard committed
375 376 377 378
}


/***********************************************************************
379
 *           PSDRV_PolyPolygon
Alexandre Julliard's avatar
Alexandre Julliard committed
380
 */
381
BOOL PSDRV_PolyPolygon( PSDRV_PDEVICE *physDev, const POINT* pts, const INT* counts,
382
                        UINT polygons )
Alexandre Julliard's avatar
Alexandre Julliard committed
383
{
384 385
    DWORD polygon, total;
    INT line;
386
    POINT *dev_pts, *pt;
387

388
    TRACE("\n");
Alexandre Julliard's avatar
Alexandre Julliard committed
389

390 391 392 393 394 395
    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) );
    LPtoDP( physDev->hdc, dev_pts, total );

    pt = dev_pts;
396 397 398 399 400

    PSDRV_WriteSpool(physDev, "%PolyPolygon\n",13);
    PSDRV_SetPen(physDev);
    PSDRV_SetClip(physDev);

401
    for(polygon = 0; polygon < polygons; polygon++) {
402
        PSDRV_WriteMoveTo(physDev, pt->x, pt->y);
403
	pt++;
404 405
        for(line = 1; line < counts[polygon]; line++, pt++)
            PSDRV_WriteLineTo(physDev, pt->x, pt->y);
406
	PSDRV_WriteClosePath(physDev);
407
    }
408
    HeapFree( GetProcessHeap(), 0, dev_pts );
Alexandre Julliard's avatar
Alexandre Julliard committed
409

410 411
    if(GetPolyFillMode( physDev->hdc ) == ALTERNATE)
        PSDRV_Brush(physDev, 1);
412
    else /* WINDING */
413
        PSDRV_Brush(physDev, 0);
414

415
    PSDRV_DrawLine(physDev);
416
    PSDRV_ResetClip(physDev);
Alexandre Julliard's avatar
Alexandre Julliard committed
417 418 419
    return TRUE;
}

420

421 422 423
/***********************************************************************
 *           PSDRV_Polygon
 */
424
BOOL PSDRV_Polygon( PSDRV_PDEVICE *physDev, const POINT* pt, INT count )
425
{
426
     return PSDRV_PolyPolygon( physDev, pt, &count, 1 );
427 428 429 430 431 432
}


/***********************************************************************
 *           PSDRV_SetPixel
 */
433
COLORREF PSDRV_SetPixel( PSDRV_PDEVICE *physDev, INT x, INT y, COLORREF color )
434 435
{
    PSCOLOR pscolor;
436
    POINT pt;
437

438 439 440
    pt.x = x;
    pt.y = y;
    LPtoDP( physDev->hdc, &pt, 1 );
441

442 443 444 445
    PSDRV_SetClip(physDev);
    /* we bracket the setcolor in gsave/grestore so that we don't trash
       the current pen colour */
    PSDRV_WriteGSave(physDev);
446
    PSDRV_WriteRectangle( physDev, pt.x, pt.y, 0, 0 );
447
    PSDRV_CreateColor( physDev, &pscolor, color );
448 449
    PSDRV_WriteSetColor( physDev, &pscolor );
    PSDRV_WriteFill( physDev );
450 451
    PSDRV_WriteGRestore(physDev);
    PSDRV_ResetClip(physDev);
452 453
    return color;
}
454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491

/***********************************************************************
 *           PSDRV_PaintRgn
 */
BOOL PSDRV_PaintRgn( PSDRV_PDEVICE *physDev, HRGN hrgn )
{
    
    RGNDATA *rgndata = NULL;
    RECT *pRect;
    DWORD size, i;

    TRACE("hdc=%p\n", physDev->hdc);

    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;

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

    PSDRV_SetClip(physDev);
    PSDRV_WriteNewPath(physDev);
    for(i = 0, pRect = (RECT*)rgndata->Buffer; i < rgndata->rdh.nCount; i++, pRect++)
        PSDRV_WriteRectangle(physDev, pRect->left, pRect->top, pRect->right - pRect->left, pRect->bottom - pRect->top);

    PSDRV_Brush(physDev, 0);
    PSDRV_ResetClip(physDev);

 end:
    HeapFree(GetProcessHeap(), 0, rgndata);
    return TRUE;
}