painting.c 38.1 KB
Newer Older
Alexandre Julliard's avatar
Alexandre Julliard committed
1
/*
2
 * GDI drawing functions.
Alexandre Julliard's avatar
Alexandre Julliard committed
3 4
 *
 * Copyright 1993, 1994 Alexandre Julliard
Alexandre Julliard's avatar
Alexandre Julliard committed
5
 * Copyright 1997 Bertho A. Stultiens
6
 *           1999 Huw D M Davies
7 8 9 10 11 12 13 14 15 16 17 18 19
 *
 * 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
20
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
Alexandre Julliard's avatar
Alexandre Julliard committed
21 22
 */

23 24 25
#include "config.h"
#include "wine/port.h"

26
#include <stdarg.h>
27
#include <string.h>
28 29
#include <stdlib.h>

30
#include "windef.h"
31
#include "winbase.h"
32 33
#include "wingdi.h"
#include "winerror.h"
34
#include "gdi_private.h"
35
#include "wine/debug.h"
36

37
WINE_DEFAULT_DEBUG_CHANNEL(gdi);
38

Alexandre Julliard's avatar
Alexandre Julliard committed
39 40

/***********************************************************************
41
 *           LineTo    (GDI32.@)
Alexandre Julliard's avatar
Alexandre Julliard committed
42
 */
43
BOOL WINAPI LineTo( HDC hdc, INT x, INT y )
Alexandre Julliard's avatar
Alexandre Julliard committed
44
{
45
    DC * dc = DC_GetDCUpdate( hdc );
46
    BOOL ret;
Alexandre Julliard's avatar
Alexandre Julliard committed
47

48 49
    if(!dc) return FALSE;

50
    if(PATH_IsPathOpen(dc->path))
51
        ret = PATH_LineTo(dc, x, y);
52
    else
53
        ret = dc->funcs->pLineTo && dc->funcs->pLineTo(dc->physDev,x,y);
54
    if(ret) {
55 56
        dc->CursPosX = x;
        dc->CursPosY = y;
57
    }
58
    DC_ReleaseDCPtr( dc );
59
    return ret;
Alexandre Julliard's avatar
Alexandre Julliard committed
60 61 62 63
}


/***********************************************************************
64
 *           MoveToEx    (GDI32.@)
Alexandre Julliard's avatar
Alexandre Julliard committed
65
 */
66
BOOL WINAPI MoveToEx( HDC hdc, INT x, INT y, LPPOINT pt )
Alexandre Julliard's avatar
Alexandre Julliard committed
67
{
68
    BOOL ret = TRUE;
69
    DC * dc = DC_GetDCPtr( hdc );
Alexandre Julliard's avatar
Alexandre Julliard committed
70

71 72 73
    if(!dc) return FALSE;

    if(pt) {
74 75
        pt->x = dc->CursPosX;
        pt->y = dc->CursPosY;
76
    }
77 78
    dc->CursPosX = x;
    dc->CursPosY = y;
79

80
    if(PATH_IsPathOpen(dc->path)) ret = PATH_MoveTo(dc);
81
    else if (dc->funcs->pMoveTo) ret = dc->funcs->pMoveTo(dc->physDev,x,y);
82
    DC_ReleaseDCPtr( dc );
83
    return ret;
Alexandre Julliard's avatar
Alexandre Julliard committed
84 85 86 87
}


/***********************************************************************
88
 *           Arc    (GDI32.@)
Alexandre Julliard's avatar
Alexandre Julliard committed
89
 */
90 91 92
BOOL WINAPI Arc( HDC hdc, INT left, INT top, INT right,
                     INT bottom, INT xstart, INT ystart,
                     INT xend, INT yend )
Alexandre Julliard's avatar
Alexandre Julliard committed
93
{
94 95 96 97
    BOOL ret = FALSE;
    DC * dc = DC_GetDCUpdate( hdc );
    if (dc)
    {
98
    if(PATH_IsPathOpen(dc->path))
99
            ret = PATH_Arc(dc, left, top, right, bottom, xstart, ystart, xend, yend,0);
100
        else if (dc->funcs->pArc)
101
            ret = dc->funcs->pArc(dc->physDev,left,top,right,bottom,xstart,ystart,xend,yend);
102
        DC_ReleaseDCPtr( dc );
103
    }
104
    return ret;
Alexandre Julliard's avatar
Alexandre Julliard committed
105 106
}

107
/***********************************************************************
108
 *           ArcTo    (GDI32.@)
109
 */
110 111
BOOL WINAPI ArcTo( HDC hdc,
                     INT left,   INT top,
112 113 114
                     INT right,  INT bottom,
                     INT xstart, INT ystart,
                     INT xend,   INT yend )
115
{
116 117 118 119 120 121 122
    double width = fabs(right-left),
        height = fabs(bottom-top),
        xradius = width/2,
        yradius = height/2,
        xcenter = right > left ? left+xradius : right+xradius,
        ycenter = bottom > top ? top+yradius : bottom+yradius,
        angle;
123
    BOOL result;
124
    DC * dc = DC_GetDCUpdate( hdc );
125 126
    if(!dc) return FALSE;

127 128 129
    if(PATH_IsPathOpen(dc->path))
        result = PATH_Arc(dc,left,top,right,bottom,xstart,ystart,xend,yend,-1);
    else if(dc->funcs->pArcTo)
130
        result = dc->funcs->pArcTo( dc->physDev, left, top, right, bottom,
131
				  xstart, ystart, xend, yend );
132
    else /* We'll draw a line from the current position to the starting point of the arc, then draw the arc */
133
    {
134 135
        angle = atan2(((ystart-ycenter)/height),
                      ((xstart-xcenter)/width));
136 137 138
        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);
139 140 141 142 143 144
    }
    if (result) {
        angle = atan2(((yend-ycenter)/height),
                      ((xend-xcenter)/width));
        dc->CursPosX = GDI_ROUND(xcenter+(cos(angle)*xradius));
        dc->CursPosY = GDI_ROUND(ycenter+(sin(angle)*yradius));
145
    }
146
    DC_ReleaseDCPtr( dc );
147 148
    return result;
}
Alexandre Julliard's avatar
Alexandre Julliard committed
149 150 151


/***********************************************************************
152
 *           Pie   (GDI32.@)
Alexandre Julliard's avatar
Alexandre Julliard committed
153
 */
154 155 156
BOOL WINAPI Pie( HDC hdc, INT left, INT top,
                     INT right, INT bottom, INT xstart, INT ystart,
                     INT xend, INT yend )
Alexandre Julliard's avatar
Alexandre Julliard committed
157
{
158 159
    BOOL ret = FALSE;
    DC * dc = DC_GetDCUpdate( hdc );
160 161
    if (!dc) return FALSE;

162
    if(PATH_IsPathOpen(dc->path))
163
        ret = PATH_Arc(dc,left,top,right,bottom,xstart,ystart,xend,yend,2);
164
    else if(dc->funcs->pPie)
165
        ret = dc->funcs->pPie(dc->physDev,left,top,right,bottom,xstart,ystart,xend,yend);
166

167
    DC_ReleaseDCPtr( dc );
168
    return ret;
Alexandre Julliard's avatar
Alexandre Julliard committed
169 170 171 172
}


/***********************************************************************
173
 *           Chord    (GDI32.@)
Alexandre Julliard's avatar
Alexandre Julliard committed
174
 */
175 176 177
BOOL WINAPI Chord( HDC hdc, INT left, INT top,
                       INT right, INT bottom, INT xstart, INT ystart,
                       INT xend, INT yend )
Alexandre Julliard's avatar
Alexandre Julliard committed
178
{
179 180
    BOOL ret = FALSE;
    DC * dc = DC_GetDCUpdate( hdc );
181 182
    if (!dc) return FALSE;

183
    if(PATH_IsPathOpen(dc->path))
184 185
	ret = PATH_Arc(dc,left,top,right,bottom,xstart,ystart,xend,yend,1);
    else if(dc->funcs->pChord)
186
        ret = dc->funcs->pChord(dc->physDev,left,top,right,bottom,xstart,ystart,xend,yend);
187

188
    DC_ReleaseDCPtr( dc );
189
    return ret;
Alexandre Julliard's avatar
Alexandre Julliard committed
190 191 192 193
}


/***********************************************************************
194
 *           Ellipse    (GDI32.@)
Alexandre Julliard's avatar
Alexandre Julliard committed
195
 */
196 197
BOOL WINAPI Ellipse( HDC hdc, INT left, INT top,
                         INT right, INT bottom )
Alexandre Julliard's avatar
Alexandre Julliard committed
198
{
199 200
    BOOL ret = FALSE;
    DC * dc = DC_GetDCUpdate( hdc );
201 202
    if (!dc) return FALSE;

203
    if(PATH_IsPathOpen(dc->path))
204 205
	ret = PATH_Ellipse(dc,left,top,right,bottom);
    else if (dc->funcs->pEllipse)
206
        ret = dc->funcs->pEllipse(dc->physDev,left,top,right,bottom);
207

208
    DC_ReleaseDCPtr( dc );
209
    return ret;
Alexandre Julliard's avatar
Alexandre Julliard committed
210 211 212 213
}


/***********************************************************************
214
 *           Rectangle    (GDI32.@)
Alexandre Julliard's avatar
Alexandre Julliard committed
215
 */
216 217
BOOL WINAPI Rectangle( HDC hdc, INT left, INT top,
                           INT right, INT bottom )
Alexandre Julliard's avatar
Alexandre Julliard committed
218
{
219 220 221
    BOOL ret = FALSE;
    DC * dc = DC_GetDCUpdate( hdc );
    if (dc)
222
    {
223
    if(PATH_IsPathOpen(dc->path))
224 225
            ret = PATH_Rectangle(dc, left, top, right, bottom);
        else if (dc->funcs->pRectangle)
226
            ret = dc->funcs->pRectangle(dc->physDev,left,top,right,bottom);
227
        DC_ReleaseDCPtr( dc );
228
    }
229
    return ret;
Alexandre Julliard's avatar
Alexandre Julliard committed
230 231 232 233
}


/***********************************************************************
234
 *           RoundRect    (GDI32.@)
Alexandre Julliard's avatar
Alexandre Julliard committed
235
 */
236 237
BOOL WINAPI RoundRect( HDC hdc, INT left, INT top, INT right,
                           INT bottom, INT ell_width, INT ell_height )
Alexandre Julliard's avatar
Alexandre Julliard committed
238
{
239 240
    BOOL ret = FALSE;
    DC *dc = DC_GetDCUpdate( hdc );
241

242 243
    if (dc)
    {
244
        if(PATH_IsPathOpen(dc->path))
245
	    ret = PATH_RoundRect(dc,left,top,right,bottom,ell_width,ell_height);
246
        else if (dc->funcs->pRoundRect)
247
            ret = dc->funcs->pRoundRect(dc->physDev,left,top,right,bottom,ell_width,ell_height);
248
        DC_ReleaseDCPtr( dc );
249
    }
250
    return ret;
Alexandre Julliard's avatar
Alexandre Julliard committed
251 252 253
}

/***********************************************************************
254
 *           SetPixel    (GDI32.@)
Alexandre Julliard's avatar
Alexandre Julliard committed
255
 */
256
COLORREF WINAPI SetPixel( HDC hdc, INT x, INT y, COLORREF color )
Alexandre Julliard's avatar
Alexandre Julliard committed
257
{
258 259 260 261
    COLORREF ret = 0;
    DC * dc = DC_GetDCUpdate( hdc );
    if (dc)
    {
262
        if (dc->funcs->pSetPixel) ret = dc->funcs->pSetPixel(dc->physDev,x,y,color);
263
        DC_ReleaseDCPtr( dc );
264 265
    }
    return ret;
Alexandre Julliard's avatar
Alexandre Julliard committed
266 267
}

Alexandre Julliard's avatar
Alexandre Julliard committed
268
/***********************************************************************
269
 *           SetPixelV    (GDI32.@)
Alexandre Julliard's avatar
Alexandre Julliard committed
270
 */
271
BOOL WINAPI SetPixelV( HDC hdc, INT x, INT y, COLORREF color )
Alexandre Julliard's avatar
Alexandre Julliard committed
272
{
273 274 275 276 277 278
    BOOL ret = FALSE;
    DC * dc = DC_GetDCUpdate( hdc );
    if (dc)
    {
        if (dc->funcs->pSetPixel)
        {
279
            dc->funcs->pSetPixel(dc->physDev,x,y,color);
280
            ret = TRUE;
281
        }
282
        DC_ReleaseDCPtr( dc );
283 284
    }
    return ret;
Alexandre Julliard's avatar
Alexandre Julliard committed
285
}
Alexandre Julliard's avatar
Alexandre Julliard committed
286 287

/***********************************************************************
288
 *           GetPixel    (GDI32.@)
Alexandre Julliard's avatar
Alexandre Julliard committed
289
 */
290
COLORREF WINAPI GetPixel( HDC hdc, INT x, INT y )
Alexandre Julliard's avatar
Alexandre Julliard committed
291
{
292
    COLORREF ret = CLR_INVALID;
293
    DC * dc = DC_GetDCUpdate( hdc );
Alexandre Julliard's avatar
Alexandre Julliard committed
294

295 296
    if (dc)
    {
Alexandre Julliard's avatar
Alexandre Julliard committed
297
    /* FIXME: should this be in the graphics driver? */
298 299
        if (PtVisible( hdc, x, y ))
        {
300
            if (dc->funcs->pGetPixel) ret = dc->funcs->pGetPixel(dc->physDev,x,y);
301
        }
302
        DC_ReleaseDCPtr( dc );
303 304
    }
    return ret;
Alexandre Julliard's avatar
Alexandre Julliard committed
305 306 307
}


Alexandre Julliard's avatar
Alexandre Julliard committed
308
/******************************************************************************
309
 * ChoosePixelFormat [GDI32.@]
Alexandre Julliard's avatar
Alexandre Julliard committed
310 311 312 313 314 315 316 317 318 319
 * Matches a pixel format to given format
 *
 * PARAMS
 *    hdc  [I] Device context to search for best pixel match
 *    ppfd [I] Pixel format for which a match is sought
 *
 * RETURNS
 *    Success: Pixel format index closest to given format
 *    Failure: 0
 */
320
INT WINAPI ChoosePixelFormat( HDC hdc, const PIXELFORMATDESCRIPTOR* ppfd )
Alexandre Julliard's avatar
Alexandre Julliard committed
321
{
322 323
    INT ret = 0;
    DC * dc = DC_GetDCPtr( hdc );
Lionel Ulmer's avatar
Lionel Ulmer committed
324

325
    TRACE("(%p,%p)\n",hdc,ppfd);
326

327 328 329
    if (!dc) return 0;

    if (!dc->funcs->pChoosePixelFormat) FIXME(" :stub\n");
330
    else ret = dc->funcs->pChoosePixelFormat(dc->physDev,ppfd);
331

332
    DC_ReleaseDCPtr( dc );
333
    return ret;
Alexandre Julliard's avatar
Alexandre Julliard committed
334 335 336 337
}


/******************************************************************************
338
 * SetPixelFormat [GDI32.@]
Alexandre Julliard's avatar
Alexandre Julliard committed
339 340 341 342 343 344 345
 * Sets pixel format of device context
 *
 * PARAMS
 *    hdc          [I] Device context to search for best pixel match
 *    iPixelFormat [I] Pixel format index
 *    ppfd         [I] Pixel format for which a match is sought
 *
346 347 348
 * RETURNS
 *    Success: TRUE
 *    Failure: FALSE
Alexandre Julliard's avatar
Alexandre Julliard committed
349
 */
350 351
BOOL WINAPI SetPixelFormat( HDC hdc, INT iPixelFormat,
                            const PIXELFORMATDESCRIPTOR *ppfd)
Alexandre Julliard's avatar
Alexandre Julliard committed
352
{
353 354 355
    INT bRet = FALSE;
    DC * dc = DC_GetDCPtr( hdc );

356
    TRACE("(%p,%d,%p)\n",hdc,iPixelFormat,ppfd);
357 358

    if (!dc) return 0;
Lionel Ulmer's avatar
Lionel Ulmer committed
359

360
    if (!dc->funcs->pSetPixelFormat) FIXME(" :stub\n");
361
    else bRet = dc->funcs->pSetPixelFormat(dc->physDev,iPixelFormat,ppfd);
Lionel Ulmer's avatar
Lionel Ulmer committed
362

363
    DC_ReleaseDCPtr( dc );
364
    return bRet;
Alexandre Julliard's avatar
Alexandre Julliard committed
365 366 367 368
}


/******************************************************************************
369
 * GetPixelFormat [GDI32.@]
Alexandre Julliard's avatar
Alexandre Julliard committed
370 371 372 373 374 375 376 377 378
 * Gets index of pixel format of DC
 *
 * PARAMETERS
 *    hdc [I] Device context whose pixel format index is sought
 *
 * RETURNS
 *    Success: Currently selected pixel format
 *    Failure: 0
 */
379
INT WINAPI GetPixelFormat( HDC hdc )
Alexandre Julliard's avatar
Alexandre Julliard committed
380
{
381 382 383
    INT ret = 0;
    DC * dc = DC_GetDCPtr( hdc );

384
    TRACE("(%p)\n",hdc);
385 386

    if (!dc) return 0;
Lionel Ulmer's avatar
Lionel Ulmer committed
387

388
    if (!dc->funcs->pGetPixelFormat) FIXME(" :stub\n");
389
    else ret = dc->funcs->pGetPixelFormat(dc->physDev);
Lionel Ulmer's avatar
Lionel Ulmer committed
390

391
    DC_ReleaseDCPtr( dc );
392
    return ret;
Alexandre Julliard's avatar
Alexandre Julliard committed
393 394 395 396
}


/******************************************************************************
397
 * DescribePixelFormat [GDI32.@]
Alexandre Julliard's avatar
Alexandre Julliard committed
398 399 400 401 402 403 404 405 406 407 408 409
 * Gets info about pixel format from DC
 *
 * PARAMS
 *    hdc          [I] Device context
 *    iPixelFormat [I] Pixel format selector
 *    nBytes       [I] Size of buffer
 *    ppfd         [O] Pointer to structure to receive pixel format data
 *
 * RETURNS
 *    Success: Maximum pixel format index of the device context
 *    Failure: 0
 */
410
INT WINAPI DescribePixelFormat( HDC hdc, INT iPixelFormat, UINT nBytes,
Alexandre Julliard's avatar
Alexandre Julliard committed
411 412
                                LPPIXELFORMATDESCRIPTOR ppfd )
{
413 414 415
    INT ret = 0;
    DC * dc = DC_GetDCPtr( hdc );

416
    TRACE("(%p,%d,%d,%p): stub\n",hdc,iPixelFormat,nBytes,ppfd);
Lionel Ulmer's avatar
Lionel Ulmer committed
417

418
    if (!dc) return 0;
Lionel Ulmer's avatar
Lionel Ulmer committed
419

420 421 422 423 424 425 426
    if (!dc->funcs->pDescribePixelFormat)
    {
        FIXME(" :stub\n");
        ppfd->nSize = nBytes;
        ppfd->nVersion = 1;
	ret = 3;
    }
427
    else ret = dc->funcs->pDescribePixelFormat(dc->physDev,iPixelFormat,nBytes,ppfd);
428

429
    DC_ReleaseDCPtr( dc );
430
    return ret;
Alexandre Julliard's avatar
Alexandre Julliard committed
431 432 433 434
}


/******************************************************************************
435
 * SwapBuffers [GDI32.@]
Alexandre Julliard's avatar
Alexandre Julliard committed
436 437 438 439 440
 * Exchanges front and back buffers of window
 *
 * PARAMS
 *    hdc [I] Device context whose buffers get swapped
 *
441 442 443
 * RETURNS
 *    Success: TRUE
 *    Failure: FALSE
Alexandre Julliard's avatar
Alexandre Julliard committed
444
 */
445
BOOL WINAPI SwapBuffers( HDC hdc )
Alexandre Julliard's avatar
Alexandre Julliard committed
446
{
447 448
    INT bRet = FALSE;
    DC * dc = DC_GetDCPtr( hdc );
Lionel Ulmer's avatar
Lionel Ulmer committed
449

450
    TRACE("(%p)\n",hdc);
Lionel Ulmer's avatar
Lionel Ulmer committed
451

452 453 454 455 456 457 458
    if (!dc) return TRUE;

    if (!dc->funcs->pSwapBuffers)
    {
        FIXME(" :stub\n");
	bRet = TRUE;
    }
459
    else bRet = dc->funcs->pSwapBuffers(dc->physDev);
460

461
    DC_ReleaseDCPtr( dc );
462
    return bRet;
Alexandre Julliard's avatar
Alexandre Julliard committed
463 464 465
}


Alexandre Julliard's avatar
Alexandre Julliard committed
466
/***********************************************************************
467
 *           PaintRgn    (GDI32.@)
Alexandre Julliard's avatar
Alexandre Julliard committed
468
 */
469
BOOL WINAPI PaintRgn( HDC hdc, HRGN hrgn )
Alexandre Julliard's avatar
Alexandre Julliard committed
470
{
471 472 473 474
    BOOL ret = FALSE;
    DC * dc = DC_GetDCUpdate( hdc );
    if (dc)
    {
475
        if (dc->funcs->pPaintRgn) ret = dc->funcs->pPaintRgn(dc->physDev,hrgn);
476
        DC_ReleaseDCPtr( dc );
477 478
    }
    return ret;
Alexandre Julliard's avatar
Alexandre Julliard committed
479 480 481 482
}


/***********************************************************************
483
 *           FillRgn    (GDI32.@)
Alexandre Julliard's avatar
Alexandre Julliard committed
484
 */
485
BOOL WINAPI FillRgn( HDC hdc, HRGN hrgn, HBRUSH hbrush )
Alexandre Julliard's avatar
Alexandre Julliard committed
486
{
487
    BOOL retval = FALSE;
488
    HBRUSH prevBrush;
489
    DC * dc = DC_GetDCUpdate( hdc );
490

491
    if (!dc) return FALSE;
492
    if(dc->funcs->pFillRgn)
493
        retval = dc->funcs->pFillRgn(dc->physDev, hrgn, hbrush);
494 495
    else if ((prevBrush = SelectObject( hdc, hbrush )))
    {
496 497
    retval = PaintRgn( hdc, hrgn );
    SelectObject( hdc, prevBrush );
498
    }
499
    DC_ReleaseDCPtr( dc );
Alexandre Julliard's avatar
Alexandre Julliard committed
500 501 502 503 504
    return retval;
}


/***********************************************************************
505
 *           FrameRgn     (GDI32.@)
Alexandre Julliard's avatar
Alexandre Julliard committed
506
 */
507 508
BOOL WINAPI FrameRgn( HDC hdc, HRGN hrgn, HBRUSH hbrush,
                          INT nWidth, INT nHeight )
Alexandre Julliard's avatar
Alexandre Julliard committed
509
{
510 511
    BOOL ret = FALSE;
    DC *dc = DC_GetDCUpdate( hdc );
512

513
    if (!dc) return FALSE;
514
    if(dc->funcs->pFrameRgn)
515
        ret = dc->funcs->pFrameRgn( dc->physDev, hrgn, hbrush, nWidth, nHeight );
516 517 518 519 520 521 522
    else
    {
        HRGN tmp = CreateRectRgn( 0, 0, 0, 0 );
        if (tmp)
        {
            if (REGION_FrameRgn( tmp, hrgn, nWidth, nHeight ))
            {
523
                FillRgn( hdc, tmp, hbrush );
524 525
                ret = TRUE;
            }
526 527
            DeleteObject( tmp );
        }
528
    }
529
    DC_ReleaseDCPtr( dc );
530
    return ret;
Alexandre Julliard's avatar
Alexandre Julliard committed
531 532 533 534
}


/***********************************************************************
535
 *           InvertRgn    (GDI32.@)
Alexandre Julliard's avatar
Alexandre Julliard committed
536
 */
537
BOOL WINAPI InvertRgn( HDC hdc, HRGN hrgn )
Alexandre Julliard's avatar
Alexandre Julliard committed
538
{
539 540 541
    HBRUSH prevBrush;
    INT prevROP;
    BOOL retval;
542 543
    DC *dc = DC_GetDCUpdate( hdc );
    if (!dc) return FALSE;
544 545

    if(dc->funcs->pInvertRgn)
546
        retval = dc->funcs->pInvertRgn( dc->physDev, hrgn );
547 548
    else
    {
549 550 551
    prevBrush = SelectObject( hdc, GetStockObject(BLACK_BRUSH) );
    prevROP = SetROP2( hdc, R2_NOT );
    retval = PaintRgn( hdc, hrgn );
552 553
    SelectObject( hdc, prevBrush );
    SetROP2( hdc, prevROP );
554
    }
555
    DC_ReleaseDCPtr( dc );
Alexandre Julliard's avatar
Alexandre Julliard committed
556 557 558 559 560
    return retval;
}


/**********************************************************************
561
 *          Polyline   (GDI32.@)
Alexandre Julliard's avatar
Alexandre Julliard committed
562
 */
563
BOOL WINAPI Polyline( HDC hdc, const POINT* pt, INT count )
Alexandre Julliard's avatar
Alexandre Julliard committed
564
{
565 566 567 568
    BOOL ret = FALSE;
    DC * dc = DC_GetDCUpdate( hdc );
    if (dc)
    {
569
        if (PATH_IsPathOpen(dc->path)) ret = PATH_Polyline(dc, pt, count);
570
        else if (dc->funcs->pPolyline) ret = dc->funcs->pPolyline(dc->physDev,pt,count);
571
        DC_ReleaseDCPtr( dc );
572 573
    }
    return ret;
Alexandre Julliard's avatar
Alexandre Julliard committed
574 575
}

576
/**********************************************************************
577
 *          PolylineTo   (GDI32.@)
578
 */
579
BOOL WINAPI PolylineTo( HDC hdc, const POINT* pt, DWORD cCount )
580
{
581 582
    DC * dc = DC_GetDCUpdate( hdc );
    BOOL ret = FALSE;
Huw D M Davies's avatar
Huw D M Davies committed
583

584
    if(!dc) return FALSE;
Huw D M Davies's avatar
Huw D M Davies committed
585

586
    if(PATH_IsPathOpen(dc->path))
587
        ret = PATH_PolylineTo(dc, pt, cCount);
588 589

    else if(dc->funcs->pPolylineTo)
590
        ret = dc->funcs->pPolylineTo(dc->physDev, pt, cCount);
Huw D M Davies's avatar
Huw D M Davies committed
591

592 593 594
    else { /* do it using Polyline */
        POINT *pts = HeapAlloc( GetProcessHeap(), 0,
				sizeof(POINT) * (cCount + 1) );
595 596
	if (pts)
        {
597 598
	pts[0].x = dc->CursPosX;
	pts[0].y = dc->CursPosY;
599 600 601 602
	memcpy( pts + 1, pt, sizeof(POINT) * cCount );
	ret = Polyline( hdc, pts, cCount + 1 );
	HeapFree( GetProcessHeap(), 0, pts );
    }
603
    }
604
    if(ret) {
605 606
        dc->CursPosX = pt[cCount-1].x;
	dc->CursPosY = pt[cCount-1].y;
607
    }
608
    DC_ReleaseDCPtr( dc );
609
    return ret;
610
}
Alexandre Julliard's avatar
Alexandre Julliard committed
611 612 613


/**********************************************************************
614
 *          Polygon  (GDI32.@)
Alexandre Julliard's avatar
Alexandre Julliard committed
615
 */
616
BOOL WINAPI Polygon( HDC hdc, const POINT* pt, INT count )
Alexandre Julliard's avatar
Alexandre Julliard committed
617
{
618 619 620 621
    BOOL ret = FALSE;
    DC * dc = DC_GetDCUpdate( hdc );
    if (dc)
    {
622
        if (PATH_IsPathOpen(dc->path)) ret = PATH_Polygon(dc, pt, count);
623
        else if (dc->funcs->pPolygon) ret = dc->funcs->pPolygon(dc->physDev,pt,count);
624
        DC_ReleaseDCPtr( dc );
625
    }
626
    return ret;
Alexandre Julliard's avatar
Alexandre Julliard committed
627 628 629 630
}


/**********************************************************************
631
 *          PolyPolygon  (GDI32.@)
Alexandre Julliard's avatar
Alexandre Julliard committed
632
 */
633 634
BOOL WINAPI PolyPolygon( HDC hdc, const POINT* pt, const INT* counts,
                             UINT polygons )
Alexandre Julliard's avatar
Alexandre Julliard committed
635
{
636 637 638 639
    BOOL ret = FALSE;
    DC * dc = DC_GetDCUpdate( hdc );
    if (dc)
    {
640
        if (PATH_IsPathOpen(dc->path)) ret = PATH_PolyPolygon(dc, pt, counts, polygons);
641
        else if (dc->funcs->pPolyPolygon) ret = dc->funcs->pPolyPolygon(dc->physDev,pt,counts,polygons);
642
        DC_ReleaseDCPtr( dc );
643 644
    }
    return ret;
Alexandre Julliard's avatar
Alexandre Julliard committed
645 646
}

Alexandre Julliard's avatar
Alexandre Julliard committed
647
/**********************************************************************
648
 *          PolyPolyline  (GDI32.@)
Alexandre Julliard's avatar
Alexandre Julliard committed
649
 */
650
BOOL WINAPI PolyPolyline( HDC hdc, const POINT* pt, const DWORD* counts,
651
                            DWORD polylines )
Alexandre Julliard's avatar
Alexandre Julliard committed
652
{
653 654 655 656
    BOOL ret = FALSE;
    DC * dc = DC_GetDCUpdate( hdc );
    if (dc)
    {
657
        if (PATH_IsPathOpen(dc->path)) ret = PATH_PolyPolyline(dc, pt, counts, polylines);
658
        else if (dc->funcs->pPolyPolyline) ret = dc->funcs->pPolyPolyline(dc->physDev,pt,counts,polylines);
659
        DC_ReleaseDCPtr( dc );
660
    }
661
    return ret;
Alexandre Julliard's avatar
Alexandre Julliard committed
662 663
}

Alexandre Julliard's avatar
Alexandre Julliard committed
664
/**********************************************************************
665
 *          ExtFloodFill   (GDI32.@)
Alexandre Julliard's avatar
Alexandre Julliard committed
666
 */
667 668
BOOL WINAPI ExtFloodFill( HDC hdc, INT x, INT y, COLORREF color,
                              UINT fillType )
Alexandre Julliard's avatar
Alexandre Julliard committed
669
{
670 671 672 673
    BOOL ret = FALSE;
    DC * dc = DC_GetDCUpdate( hdc );
    if (dc)
    {
674
        if (dc->funcs->pExtFloodFill) ret = dc->funcs->pExtFloodFill(dc->physDev,x,y,color,fillType);
675
        DC_ReleaseDCPtr( dc );
676
    }
677
    return ret;
Alexandre Julliard's avatar
Alexandre Julliard committed
678 679 680 681
}


/**********************************************************************
682
 *          FloodFill   (GDI32.@)
Alexandre Julliard's avatar
Alexandre Julliard committed
683
 */
684
BOOL WINAPI FloodFill( HDC hdc, INT x, INT y, COLORREF color )
Alexandre Julliard's avatar
Alexandre Julliard committed
685
{
686
    return ExtFloodFill( hdc, x, y, color, FLOODFILLBORDER );
Alexandre Julliard's avatar
Alexandre Julliard committed
687 688 689
}


Alexandre Julliard's avatar
Alexandre Julliard committed
690
/******************************************************************************
691
 * PolyBezier [GDI32.@]
Alexandre Julliard's avatar
Alexandre Julliard committed
692 693 694 695 696 697 698
 * Draws one or more Bezier curves
 *
 * PARAMS
 *    hDc     [I] Handle to device context
 *    lppt    [I] Pointer to endpoints and control points
 *    cPoints [I] Count of endpoints and control points
 *
699 700 701
 * RETURNS
 *    Success: TRUE
 *    Failure: FALSE
Alexandre Julliard's avatar
Alexandre Julliard committed
702
 */
703
BOOL WINAPI PolyBezier( HDC hdc, const POINT* lppt, DWORD cPoints )
Alexandre Julliard's avatar
Alexandre Julliard committed
704
{
705
    BOOL ret = FALSE;
706 707 708 709
    DC * dc;

    /* cPoints must be 3 * n + 1 (where n>=1) */
    if (cPoints == 1 || (cPoints % 3) != 1) return FALSE;
710

711
    dc = DC_GetDCUpdate( hdc );
712 713
    if(!dc) return FALSE;

714
    if(PATH_IsPathOpen(dc->path))
715 716
	ret = PATH_PolyBezier(dc, lppt, cPoints);
    else if (dc->funcs->pPolyBezier)
717
        ret = dc->funcs->pPolyBezier(dc->physDev, lppt, cPoints);
718
    else  /* We'll convert it into line segments and draw them using Polyline */
719 720 721 722
    {
        POINT *Pts;
	INT nOut;

723 724
	if ((Pts = GDI_Bezier( lppt, cPoints, &nOut )))
        {
725 726 727 728
	    TRACE("Pts = %p, no = %d\n", Pts, nOut);
	    ret = Polyline( dc->hSelf, Pts, nOut );
	    HeapFree( GetProcessHeap(), 0, Pts );
	}
729
    }
730

731
    DC_ReleaseDCPtr( dc );
732 733 734
    return ret;
}

Alexandre Julliard's avatar
Alexandre Julliard committed
735
/******************************************************************************
736
 * PolyBezierTo [GDI32.@]
Alexandre Julliard's avatar
Alexandre Julliard committed
737 738 739 740 741 742 743
 * Draws one or more Bezier curves
 *
 * PARAMS
 *    hDc     [I] Handle to device context
 *    lppt    [I] Pointer to endpoints and control points
 *    cPoints [I] Count of endpoints and control points
 *
744 745 746
 * RETURNS
 *    Success: TRUE
 *    Failure: FALSE
Alexandre Julliard's avatar
Alexandre Julliard committed
747
 */
748
BOOL WINAPI PolyBezierTo( HDC hdc, const POINT* lppt, DWORD cPoints )
Alexandre Julliard's avatar
Alexandre Julliard committed
749
{
750
    DC * dc;
751
    BOOL ret;
752

753 754 755 756
    /* cbPoints must be 3 * n (where n>=1) */
    if (!cPoints || (cPoints % 3) != 0) return FALSE;

    dc = DC_GetDCUpdate( hdc );
Alexandre Julliard's avatar
Alexandre Julliard committed
757
    if(!dc) return FALSE;
758

759
    if(PATH_IsPathOpen(dc->path))
760
        ret = PATH_PolyBezierTo(dc, lppt, cPoints);
761
    else if(dc->funcs->pPolyBezierTo)
762
        ret = dc->funcs->pPolyBezierTo(dc->physDev, lppt, cPoints);
763 764 765 766
    else { /* We'll do it using PolyBezier */
        POINT *pt;
	pt = HeapAlloc( GetProcessHeap(), 0, sizeof(POINT) * (cPoints + 1) );
	if(!pt) return FALSE;
767 768
	pt[0].x = dc->CursPosX;
	pt[0].y = dc->CursPosY;
769 770 771 772
	memcpy(pt + 1, lppt, sizeof(POINT) * cPoints);
	ret = PolyBezier(dc->hSelf, pt, cPoints+1);
	HeapFree( GetProcessHeap(), 0, pt );
    }
773
    if(ret) {
774 775
        dc->CursPosX = lppt[cPoints-1].x;
        dc->CursPosY = lppt[cPoints-1].y;
776
    }
777
    DC_ReleaseDCPtr( dc );
Alexandre Julliard's avatar
Alexandre Julliard committed
778 779
    return ret;
}
780

781
/***********************************************************************
782
 *      AngleArc (GDI32.@)
783
 */
784
BOOL WINAPI AngleArc(HDC hdc, INT x, INT y, DWORD dwRadius, FLOAT eStartAngle, FLOAT eSweepAngle)
785
{
786
    INT x1,y1,x2,y2, arcdir;
787 788 789
    BOOL result;
    DC *dc;

790
    if( (signed int)dwRadius < 0 )
791 792 793
	return FALSE;

    dc = DC_GetDCUpdate( hdc );
794 795
    if(!dc) return FALSE;

796
    /* Calculate the end point */
797
    x2 = x + cos((eStartAngle+eSweepAngle)*M_PI/180) * dwRadius;
798
    y2 = y - sin((eStartAngle+eSweepAngle)*M_PI/180) * dwRadius;
799

800 801 802 803 804 805 806 807 808 809 810 811 812 813 814
    if(!PATH_IsPathOpen(dc->path) && dc->funcs->pAngleArc)
        result = dc->funcs->pAngleArc( dc->physDev, x, y, dwRadius, eStartAngle, eSweepAngle );
    else { /* do it using ArcTo */
        x1 = x + cos(eStartAngle*M_PI/180) * dwRadius;
        y1 = y - sin(eStartAngle*M_PI/180) * dwRadius;

        arcdir = SetArcDirection( hdc, eSweepAngle >= 0 ? AD_COUNTERCLOCKWISE : AD_CLOCKWISE);
        result = ArcTo( hdc, x-dwRadius, y-dwRadius, x+dwRadius, y+dwRadius,
                        x1, y1, x2, y2 );
        SetArcDirection( hdc, arcdir );
    }
    if (result) {
        dc->CursPosX = x2;
        dc->CursPosY = y2;
    }
815
    DC_ReleaseDCPtr( dc );
816
    return result;
817
}
818

819
/***********************************************************************
820
 *      PolyDraw (GDI32.@)
821
 */
822
BOOL WINAPI PolyDraw(HDC hdc, const POINT *lppt, const BYTE *lpbTypes,
823
                       DWORD cCount)
824
{
825
    DC *dc;
826
    BOOL result = FALSE;
827 828
    POINT * line_pts = NULL, * bzr_pts = NULL, bzr[4];
    INT i, num_pts, num_bzr_pts, space, size;
829 830

    dc = DC_GetDCUpdate( hdc );
831
    if(!dc) return FALSE;
832

Evan Stade's avatar
Evan Stade committed
833 834 835
    if( PATH_IsPathOpen( dc->path ) )
        result = PATH_PolyDraw(dc, lppt, lpbTypes, cCount);
    else if(dc->funcs->pPolyDraw)
836
        result = dc->funcs->pPolyDraw( dc->physDev, lppt, lpbTypes, cCount );
Evan Stade's avatar
Evan Stade committed
837
    else {
838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854
        /* 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;
            }
        }
855

856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896
        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(dc->hSelf, 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;
            }
897

898 899 900
            if(lpbTypes[i] & PT_CLOSEFIGURE)
                line_pts[num_pts++] = line_pts[0];
        }
901

902 903 904 905
        if(num_pts >= 2)
            Polyline(dc->hSelf, line_pts, num_pts);

        MoveToEx(dc->hSelf, line_pts[num_pts - 1].x, line_pts[num_pts - 1].y, NULL);
906

907
        result = TRUE;
Evan Stade's avatar
Evan Stade committed
908 909
    }

910
end:
911
    DC_ReleaseDCPtr( dc );
912
    return result;
913
}
914

915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965 966 967 968 969 970 971

/**********************************************************************
 *           LineDDA   (GDI32.@)
 */
BOOL WINAPI LineDDA(INT nXStart, INT nYStart, INT nXEnd, INT nYEnd,
                    LINEDDAPROC callback, LPARAM lParam )
{
    INT xadd = 1, yadd = 1;
    INT err,erradd;
    INT cnt;
    INT dx = nXEnd - nXStart;
    INT dy = nYEnd - nYStart;

    if (dx < 0)
    {
        dx = -dx;
        xadd = -1;
    }
    if (dy < 0)
    {
        dy = -dy;
        yadd = -1;
    }
    if (dx > dy)  /* line is "more horizontal" */
    {
        err = 2*dy - dx; erradd = 2*dy - 2*dx;
        for(cnt = 0;cnt <= dx; cnt++)
        {
            callback(nXStart,nYStart,lParam);
            if (err > 0)
            {
                nYStart += yadd;
                err += erradd;
            }
            else err += 2*dy;
            nXStart += xadd;
        }
    }
    else   /* line is "more vertical" */
    {
        err = 2*dx - dy; erradd = 2*dx - 2*dy;
        for(cnt = 0;cnt <= dy; cnt++)
        {
            callback(nXStart,nYStart,lParam);
            if (err > 0)
            {
                nXStart += xadd;
                err += erradd;
            }
            else err += 2*dx;
            nYStart += yadd;
        }
    }
    return TRUE;
}


972
/******************************************************************
973 974
 *
 *   *Very* simple bezier drawing code,
975 976 977 978 979 980 981 982 983
 *
 *   It uses a recursive algorithm to divide the curve in a series
 *   of straight line segements. Not ideal but for me sufficient.
 *   If you are in need for something better look for some incremental
 *   algorithm.
 *
 *   7 July 1998 Rein Klazes
 */

984
 /*
985 986
  * some macro definitions for bezier drawing
  *
987
  * to avoid truncation errors the coordinates are
988 989
  * shifted upwards. When used in drawing they are
  * shifted down again, including correct rounding
990
  * and avoiding floating point arithmetic
991
  * 4 bits should allow 27 bits coordinates which I saw
992
  * somewhere in the win32 doc's
993
  *
994 995 996 997
  */

#define BEZIERSHIFTBITS 4
#define BEZIERSHIFTUP(x)    ((x)<<BEZIERSHIFTBITS)
998
#define BEZIERPIXEL        BEZIERSHIFTUP(1)
999 1000 1001 1002 1003 1004 1005 1006
#define BEZIERSHIFTDOWN(x)  (((x)+(1<<(BEZIERSHIFTBITS-1)))>>BEZIERSHIFTBITS)
/* maximum depth of recursion */
#define BEZIERMAXDEPTH  8

/* size of array to store points on */
/* enough for one curve */
#define BEZIER_INITBUFSIZE    (150)

1007
/* calculate Bezier average, in this case the middle
1008 1009 1010 1011 1012 1013
 * correctly rounded...
 * */

#define BEZIERMIDDLE(Mid, P1, P2) \
    (Mid).x=((P1).x+(P2).x + 1)/2;\
    (Mid).y=((P1).y+(P2).y + 1)/2;
1014

1015 1016 1017 1018 1019 1020 1021 1022 1023
/**********************************************************
* BezierCheck helper function to check
* that recursion can be terminated
*       Points[0] and Points[3] are begin and endpoint
*       Points[1] and Points[2] are control points
*       level is the recursion depth
*       returns true if the recusion can be terminated
*/
static BOOL BezierCheck( int level, POINT *Points)
1024
{
1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 1072 1073 1074 1075
    INT dx, dy;
    dx=Points[3].x-Points[0].x;
    dy=Points[3].y-Points[0].y;
    if(abs(dy)<=abs(dx)){/* shallow line */
        /* check that control points are between begin and end */
        if(Points[1].x < Points[0].x){
            if(Points[1].x < Points[3].x)
                return FALSE;
        }else
            if(Points[1].x > Points[3].x)
                return FALSE;
        if(Points[2].x < Points[0].x){
            if(Points[2].x < Points[3].x)
                return FALSE;
        }else
            if(Points[2].x > Points[3].x)
                return FALSE;
        dx=BEZIERSHIFTDOWN(dx);
        if(!dx) return TRUE;
        if(abs(Points[1].y-Points[0].y-(dy/dx)*
                BEZIERSHIFTDOWN(Points[1].x-Points[0].x)) > BEZIERPIXEL ||
           abs(Points[2].y-Points[0].y-(dy/dx)*
                   BEZIERSHIFTDOWN(Points[2].x-Points[0].x)) > BEZIERPIXEL )
            return FALSE;
        else
            return TRUE;
    }else{ /* steep line */
        /* check that control points are between begin and end */
        if(Points[1].y < Points[0].y){
            if(Points[1].y < Points[3].y)
                return FALSE;
        }else
            if(Points[1].y > Points[3].y)
                return FALSE;
        if(Points[2].y < Points[0].y){
            if(Points[2].y < Points[3].y)
                return FALSE;
        }else
            if(Points[2].y > Points[3].y)
                return FALSE;
        dy=BEZIERSHIFTDOWN(dy);
        if(!dy) return TRUE;
        if(abs(Points[1].x-Points[0].x-(dx/dy)*
                BEZIERSHIFTDOWN(Points[1].y-Points[0].y)) > BEZIERPIXEL ||
           abs(Points[2].x-Points[0].x-(dx/dy)*
                   BEZIERSHIFTDOWN(Points[2].y-Points[0].y)) > BEZIERPIXEL )
            return FALSE;
        else
            return TRUE;
    }
}
1076

1077 1078 1079 1080 1081 1082 1083 1084 1085 1086 1087 1088 1089 1090 1091 1092 1093 1094 1095 1096 1097 1098 1099 1100 1101 1102 1103 1104 1105 1106 1107 1108 1109 1110 1111 1112 1113 1114 1115 1116 1117
/* Helper for GDI_Bezier.
 * Just handles one Bezier, so Points should point to four POINTs
 */
static void GDI_InternalBezier( POINT *Points, POINT **PtsOut, INT *dwOut,
				INT *nPtsOut, INT level )
{
    if(*nPtsOut == *dwOut) {
        *dwOut *= 2;
	*PtsOut = HeapReAlloc( GetProcessHeap(), 0, *PtsOut,
			       *dwOut * sizeof(POINT) );
    }

    if(!level || BezierCheck(level, Points)) {
        if(*nPtsOut == 0) {
            (*PtsOut)[0].x = BEZIERSHIFTDOWN(Points[0].x);
            (*PtsOut)[0].y = BEZIERSHIFTDOWN(Points[0].y);
            *nPtsOut = 1;
        }
	(*PtsOut)[*nPtsOut].x = BEZIERSHIFTDOWN(Points[3].x);
        (*PtsOut)[*nPtsOut].y = BEZIERSHIFTDOWN(Points[3].y);
        (*nPtsOut) ++;
    } else {
        POINT Points2[4]; /* for the second recursive call */
        Points2[3]=Points[3];
        BEZIERMIDDLE(Points2[2], Points[2], Points[3]);
        BEZIERMIDDLE(Points2[0], Points[1], Points[2]);
        BEZIERMIDDLE(Points2[1],Points2[0],Points2[2]);

        BEZIERMIDDLE(Points[1], Points[0],  Points[1]);
        BEZIERMIDDLE(Points[2], Points[1], Points2[0]);
        BEZIERMIDDLE(Points[3], Points[2], Points2[1]);

        Points2[0]=Points[3];

        /* do the two halves */
        GDI_InternalBezier(Points, PtsOut, dwOut, nPtsOut, level-1);
        GDI_InternalBezier(Points2, PtsOut, dwOut, nPtsOut, level-1);
    }
}


1118

1119 1120 1121 1122 1123 1124 1125 1126 1127 1128 1129 1130 1131 1132
/***********************************************************************
 *           GDI_Bezier   [INTERNAL]
 *   Calculate line segments that approximate -what microsoft calls- a bezier
 *   curve.
 *   The routine recursively divides the curve in two parts until a straight
 *   line can be drawn
 *
 *  PARAMS
 *
 *  Points  [I] Ptr to count POINTs which are the end and control points
 *              of the set of Bezier curves to flatten.
 *  count   [I] Number of Points.  Must be 3n+1.
 *  nPtsOut [O] Will contain no of points that have been produced (i.e. no. of
 *              lines+1).
1133
 *
1134 1135 1136 1137 1138 1139 1140 1141 1142 1143 1144 1145 1146 1147
 *  RETURNS
 *
 *  Ptr to an array of POINTs that contain the lines that approximinate the
 *  Beziers.  The array is allocated on the process heap and it is the caller's
 *  responsibility to HeapFree it. [this is not a particularly nice interface
 *  but since we can't know in advance how many points will generate, the
 *  alternative would be to call the function twice, once to determine the size
 *  and a second time to do the work - I decided this was too much of a pain].
 */
POINT *GDI_Bezier( const POINT *Points, INT count, INT *nPtsOut )
{
    POINT *out;
    INT Bezier, dwOut = BEZIER_INITBUFSIZE, i;

1148 1149
    if (count == 1 || (count - 1) % 3 != 0) {
        ERR("Invalid no. of points %d\n", count);
1150 1151 1152 1153 1154 1155 1156 1157 1158 1159 1160 1161 1162 1163 1164 1165
	return NULL;
    }
    *nPtsOut = 0;
    out = HeapAlloc( GetProcessHeap(), 0, dwOut * sizeof(POINT));
    for(Bezier = 0; Bezier < (count-1)/3; Bezier++) {
	POINT ptBuf[4];
	memcpy(ptBuf, Points + Bezier * 3, sizeof(POINT) * 4);
	for(i = 0; i < 4; i++) {
	    ptBuf[i].x = BEZIERSHIFTUP(ptBuf[i].x);
	    ptBuf[i].y = BEZIERSHIFTUP(ptBuf[i].y);
	}
        GDI_InternalBezier( ptBuf, &out, &dwOut, nPtsOut, BEZIERMAXDEPTH );
    }
    TRACE("Produced %d points\n", *nPtsOut);
    return out;
}
1166 1167

/******************************************************************************
1168
 *           GdiGradientFill   (GDI32.@)
1169 1170
 *
 *  FIXME: we don't support the Alpha channel properly
1171 1172 1173 1174
 */
BOOL WINAPI GdiGradientFill( HDC hdc, TRIVERTEX *vert_array, ULONG nvert,
                          void * grad_array, ULONG ngrad, ULONG mode )
{
1175
  unsigned int i;
1176

1177
  TRACE("vert_array:0x%08lx nvert:%d grad_array:0x%08lx ngrad:%d\n",
1178 1179 1180 1181 1182 1183 1184 1185 1186 1187 1188 1189
        (long)vert_array, nvert, (long)grad_array, ngrad);

  switch(mode) 
    {
    case GRADIENT_FILL_RECT_H:
      for(i = 0; i < ngrad; i++) 
        {
          GRADIENT_RECT *rect = ((GRADIENT_RECT *)grad_array) + i;
          TRIVERTEX *v1 = vert_array + rect->UpperLeft;
          TRIVERTEX *v2 = vert_array + rect->LowerRight;
          int y1 = v1->y < v2->y ? v1->y : v2->y;
          int y2 = v2->y > v1->y ? v2->y : v1->y;
1190
          int x, dx;
1191 1192 1193 1194 1195 1196 1197 1198 1199
          if (v1->x > v2->x)
            {
              TRIVERTEX *t = v2;
              v2 = v1;
              v1 = t;
            }
          dx = v2->x - v1->x;
          for (x = 0; x < dx; x++)
            {
1200 1201 1202 1203
              POINT pts[2];
              HPEN hPen, hOldPen;
              
              hPen = CreatePen( PS_SOLID, 1, RGB(
1204 1205 1206
                  (v1->Red   * (dx - x) + v2->Red   * x) / dx >> 8,
                  (v1->Green * (dx - x) + v2->Green * x) / dx >> 8,
                  (v1->Blue  * (dx - x) + v2->Blue  * x) / dx >> 8));
1207
              hOldPen = SelectObject( hdc, hPen );
1208
              pts[0].x = v1->x + x;
1209
              pts[0].y = y1;
1210
              pts[1].x = v1->x + x;
1211 1212 1213
              pts[1].y = y2;
              Polyline( hdc, &pts[0], 2 );
              DeleteObject( SelectObject(hdc, hOldPen ) );
1214 1215 1216 1217 1218 1219 1220 1221 1222 1223 1224
            }
        }
      break;
    case GRADIENT_FILL_RECT_V:
      for(i = 0; i < ngrad; i++) 
        {
          GRADIENT_RECT *rect = ((GRADIENT_RECT *)grad_array) + i;
          TRIVERTEX *v1 = vert_array + rect->UpperLeft;
          TRIVERTEX *v2 = vert_array + rect->LowerRight;
          int x1 = v1->x < v2->x ? v1->x : v2->x;
          int x2 = v2->x > v1->x ? v2->x : v1->x;
1225
          int y, dy;
1226 1227 1228 1229 1230 1231 1232 1233 1234
          if (v1->y > v2->y)
            {
              TRIVERTEX *t = v2;
              v2 = v1;
              v1 = t;
            }
          dy = v2->y - v1->y;
          for (y = 0; y < dy; y++)
            {
1235 1236 1237 1238
              POINT pts[2];
              HPEN hPen, hOldPen;
              
              hPen = CreatePen( PS_SOLID, 1, RGB(
1239 1240 1241
                  (v1->Red   * (dy - y) + v2->Red   * y) / dy >> 8,
                  (v1->Green * (dy - y) + v2->Green * y) / dy >> 8,
                  (v1->Blue  * (dy - y) + v2->Blue  * y) / dy >> 8));
1242 1243
              hOldPen = SelectObject( hdc, hPen );
              pts[0].x = x1;
1244
              pts[0].y = v1->y + y;
1245
              pts[1].x = x2;
1246
              pts[1].y = v1->y + y;
1247 1248
              Polyline( hdc, &pts[0], 2 );
              DeleteObject( SelectObject(hdc, hOldPen ) );
1249 1250 1251 1252 1253 1254 1255 1256 1257 1258 1259 1260 1261 1262 1263 1264 1265 1266 1267 1268 1269 1270 1271 1272 1273 1274 1275 1276 1277 1278 1279 1280 1281 1282 1283 1284 1285 1286 1287 1288 1289 1290 1291 1292 1293 1294 1295 1296 1297 1298 1299 1300 1301 1302 1303 1304 1305 1306 1307 1308 1309 1310 1311 1312
            }
        }
      break;
    case GRADIENT_FILL_TRIANGLE:
      for (i = 0; i < ngrad; i++)  
        {
          GRADIENT_TRIANGLE *tri = ((GRADIENT_TRIANGLE *)grad_array) + i;
          TRIVERTEX *v1 = vert_array + tri->Vertex1;
          TRIVERTEX *v2 = vert_array + tri->Vertex2;
          TRIVERTEX *v3 = vert_array + tri->Vertex3;
          int y, dy;
          
          if (v1->y > v2->y)
            { TRIVERTEX *t = v1; v1 = v2; v2 = t; }
          if (v2->y > v3->y)
            {
              TRIVERTEX *t = v2; v2 = v3; v3 = t;
              if (v1->y > v2->y)
                { t = v1; v1 = v2; v2 = t; }
            }
          /* v1->y <= v2->y <= v3->y */

          dy = v3->y - v1->y;
          for (y = 0; y < dy; y++)
            {
              /* v1->y <= y < v3->y */
              TRIVERTEX *v = y < (v2->y - v1->y) ? v1 : v3;
              /* (v->y <= y < v2->y) || (v2->y <= y < v->y) */
              int dy2 = v2->y - v->y;
              int y2 = y + v1->y - v->y;

              int x1 = (v3->x     * y  + v1->x     * (dy  - y )) / dy;
              int x2 = (v2->x     * y2 + v-> x     * (dy2 - y2)) / dy2;
              int r1 = (v3->Red   * y  + v1->Red   * (dy  - y )) / dy;
              int r2 = (v2->Red   * y2 + v-> Red   * (dy2 - y2)) / dy2;
              int g1 = (v3->Green * y  + v1->Green * (dy  - y )) / dy;
              int g2 = (v2->Green * y2 + v-> Green * (dy2 - y2)) / dy2;
              int b1 = (v3->Blue  * y  + v1->Blue  * (dy  - y )) / dy;
              int b2 = (v2->Blue  * y2 + v-> Blue  * (dy2 - y2)) / dy2;
               
              int x;
	      if (x1 < x2)
                {
                  int dx = x2 - x1;
                  for (x = 0; x < dx; x++)
                    SetPixel (hdc, x + x1, y + v1->y, RGB(
                      (r1 * (dx - x) + r2 * x) / dx >> 8,
                      (g1 * (dx - x) + g2 * x) / dx >> 8,
                      (b1 * (dx - x) + b2 * x) / dx >> 8));
                }
              else
                {
                  int dx = x1 - x2;
                  for (x = 0; x < dx; x++)
                    SetPixel (hdc, x + x2, y + v1->y, RGB(
                      (r2 * (dx - x) + r1 * x) / dx >> 8,
                      (g2 * (dx - x) + g1 * x) / dx >> 8,
                      (b2 * (dx - x) + b1 * x) / dx >> 8));
                }
            }
        }
      break;
    default:
      return FALSE;
1313 1314 1315 1316
  }

  return TRUE;
}