painting.c 39 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 = get_dc_ptr( hdc );
46
    BOOL ret;
Alexandre Julliard's avatar
Alexandre Julliard committed
47

48 49
    if(!dc) return FALSE;

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


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

72 73 74
    if(!dc) return FALSE;

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

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


/***********************************************************************
89
 *           Arc    (GDI32.@)
Alexandre Julliard's avatar
Alexandre Julliard committed
90
 */
91 92 93
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
94
{
95
    BOOL ret = FALSE;
96 97
    DC * dc = get_dc_ptr( hdc );

98 99
    if (dc)
    {
100 101
        update_dc( dc );
        if(PATH_IsPathOpen(dc->path))
102
            ret = PATH_Arc(dc, left, top, right, bottom, xstart, ystart, xend, yend,0);
103
        else if (dc->funcs->pArc)
104
            ret = dc->funcs->pArc(dc->physDev,left,top,right,bottom,xstart,ystart,xend,yend);
105
        release_dc_ptr( dc );
106
    }
107
    return ret;
Alexandre Julliard's avatar
Alexandre Julliard committed
108 109
}

110
/***********************************************************************
111
 *           ArcTo    (GDI32.@)
112
 */
113 114
BOOL WINAPI ArcTo( HDC hdc,
                     INT left,   INT top,
115 116 117
                     INT right,  INT bottom,
                     INT xstart, INT ystart,
                     INT xend,   INT yend )
118
{
119 120 121 122 123 124 125
    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;
126
    BOOL result;
127
    DC * dc = get_dc_ptr( hdc );
128 129
    if(!dc) return FALSE;

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


/***********************************************************************
156
 *           Pie   (GDI32.@)
Alexandre Julliard's avatar
Alexandre Julliard committed
157
 */
158 159 160
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
161
{
162
    BOOL ret = FALSE;
163
    DC * dc = get_dc_ptr( hdc );
164 165
    if (!dc) return FALSE;

166
    update_dc( dc );
167
    if(PATH_IsPathOpen(dc->path))
168
        ret = PATH_Arc(dc,left,top,right,bottom,xstart,ystart,xend,yend,2);
169
    else if(dc->funcs->pPie)
170
        ret = dc->funcs->pPie(dc->physDev,left,top,right,bottom,xstart,ystart,xend,yend);
171

172
    release_dc_ptr( dc );
173
    return ret;
Alexandre Julliard's avatar
Alexandre Julliard committed
174 175 176 177
}


/***********************************************************************
178
 *           Chord    (GDI32.@)
Alexandre Julliard's avatar
Alexandre Julliard committed
179
 */
180 181 182
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
183
{
184
    BOOL ret = FALSE;
185
    DC * dc = get_dc_ptr( hdc );
186 187
    if (!dc) return FALSE;

188
    update_dc( dc );
189
    if(PATH_IsPathOpen(dc->path))
190 191
	ret = PATH_Arc(dc,left,top,right,bottom,xstart,ystart,xend,yend,1);
    else if(dc->funcs->pChord)
192
        ret = dc->funcs->pChord(dc->physDev,left,top,right,bottom,xstart,ystart,xend,yend);
193

194
    release_dc_ptr( dc );
195
    return ret;
Alexandre Julliard's avatar
Alexandre Julliard committed
196 197 198 199
}


/***********************************************************************
200
 *           Ellipse    (GDI32.@)
Alexandre Julliard's avatar
Alexandre Julliard committed
201
 */
202 203
BOOL WINAPI Ellipse( HDC hdc, INT left, INT top,
                         INT right, INT bottom )
Alexandre Julliard's avatar
Alexandre Julliard committed
204
{
205
    BOOL ret = FALSE;
206
    DC * dc = get_dc_ptr( hdc );
207 208
    if (!dc) return FALSE;

209
    update_dc( dc );
210
    if(PATH_IsPathOpen(dc->path))
211 212
	ret = PATH_Ellipse(dc,left,top,right,bottom);
    else if (dc->funcs->pEllipse)
213
        ret = dc->funcs->pEllipse(dc->physDev,left,top,right,bottom);
214

215
    release_dc_ptr( dc );
216
    return ret;
Alexandre Julliard's avatar
Alexandre Julliard committed
217 218 219 220
}


/***********************************************************************
221
 *           Rectangle    (GDI32.@)
Alexandre Julliard's avatar
Alexandre Julliard committed
222
 */
223 224
BOOL WINAPI Rectangle( HDC hdc, INT left, INT top,
                           INT right, INT bottom )
Alexandre Julliard's avatar
Alexandre Julliard committed
225
{
226
    BOOL ret = FALSE;
227 228
    DC * dc = get_dc_ptr( hdc );

229
    if (dc)
230
    {
231 232
        update_dc( dc );
        if(PATH_IsPathOpen(dc->path))
233 234
            ret = PATH_Rectangle(dc, left, top, right, bottom);
        else if (dc->funcs->pRectangle)
235
            ret = dc->funcs->pRectangle(dc->physDev,left,top,right,bottom);
236
        release_dc_ptr( dc );
237
    }
238
    return ret;
Alexandre Julliard's avatar
Alexandre Julliard committed
239 240 241 242
}


/***********************************************************************
243
 *           RoundRect    (GDI32.@)
Alexandre Julliard's avatar
Alexandre Julliard committed
244
 */
245 246
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
247
{
248
    BOOL ret = FALSE;
249
    DC *dc = get_dc_ptr( hdc );
250

251 252
    if (dc)
    {
253
        update_dc( dc );
254
        if(PATH_IsPathOpen(dc->path))
255
	    ret = PATH_RoundRect(dc,left,top,right,bottom,ell_width,ell_height);
256
        else if (dc->funcs->pRoundRect)
257
            ret = dc->funcs->pRoundRect(dc->physDev,left,top,right,bottom,ell_width,ell_height);
258
        release_dc_ptr( dc );
259
    }
260
    return ret;
Alexandre Julliard's avatar
Alexandre Julliard committed
261 262 263
}

/***********************************************************************
264
 *           SetPixel    (GDI32.@)
Alexandre Julliard's avatar
Alexandre Julliard committed
265
 */
266
COLORREF WINAPI SetPixel( HDC hdc, INT x, INT y, COLORREF color )
Alexandre Julliard's avatar
Alexandre Julliard committed
267
{
268
    COLORREF ret = 0;
269 270
    DC * dc = get_dc_ptr( hdc );

271 272
    if (dc)
    {
273
        update_dc( dc );
274
        if (dc->funcs->pSetPixel) ret = dc->funcs->pSetPixel(dc->physDev,x,y,color);
275
        release_dc_ptr( dc );
276 277
    }
    return ret;
Alexandre Julliard's avatar
Alexandre Julliard committed
278 279
}

Alexandre Julliard's avatar
Alexandre Julliard committed
280
/***********************************************************************
281
 *           SetPixelV    (GDI32.@)
Alexandre Julliard's avatar
Alexandre Julliard committed
282
 */
283
BOOL WINAPI SetPixelV( HDC hdc, INT x, INT y, COLORREF color )
Alexandre Julliard's avatar
Alexandre Julliard committed
284
{
285
    BOOL ret = FALSE;
286 287
    DC * dc = get_dc_ptr( hdc );

288 289
    if (dc)
    {
290
        update_dc( dc );
291 292
        if (dc->funcs->pSetPixel)
        {
293
            dc->funcs->pSetPixel(dc->physDev,x,y,color);
294
            ret = TRUE;
295
        }
296
        release_dc_ptr( dc );
297 298
    }
    return ret;
Alexandre Julliard's avatar
Alexandre Julliard committed
299
}
Alexandre Julliard's avatar
Alexandre Julliard committed
300 301

/***********************************************************************
302
 *           GetPixel    (GDI32.@)
Alexandre Julliard's avatar
Alexandre Julliard committed
303
 */
304
COLORREF WINAPI GetPixel( HDC hdc, INT x, INT y )
Alexandre Julliard's avatar
Alexandre Julliard committed
305
{
306
    COLORREF ret = CLR_INVALID;
307
    DC * dc = get_dc_ptr( hdc );
Alexandre Julliard's avatar
Alexandre Julliard committed
308

309 310
    if (dc)
    {
311 312
        update_dc( dc );
        /* FIXME: should this be in the graphics driver? */
313 314
        if (PtVisible( hdc, x, y ))
        {
315
            if (dc->funcs->pGetPixel) ret = dc->funcs->pGetPixel(dc->physDev,x,y);
316
        }
317
        release_dc_ptr( dc );
318 319
    }
    return ret;
Alexandre Julliard's avatar
Alexandre Julliard committed
320 321 322
}


Alexandre Julliard's avatar
Alexandre Julliard committed
323
/******************************************************************************
324
 * ChoosePixelFormat [GDI32.@]
Alexandre Julliard's avatar
Alexandre Julliard committed
325 326 327 328 329 330 331 332 333 334
 * 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
 */
335
INT WINAPI ChoosePixelFormat( HDC hdc, const PIXELFORMATDESCRIPTOR* ppfd )
Alexandre Julliard's avatar
Alexandre Julliard committed
336
{
337
    INT ret = 0;
338
    DC * dc = get_dc_ptr( hdc );
Lionel Ulmer's avatar
Lionel Ulmer committed
339

340
    TRACE("(%p,%p)\n",hdc,ppfd);
341

342 343 344
    if (!dc) return 0;

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

347
    release_dc_ptr( dc );
348
    return ret;
Alexandre Julliard's avatar
Alexandre Julliard committed
349 350 351 352
}


/******************************************************************************
353
 * SetPixelFormat [GDI32.@]
Alexandre Julliard's avatar
Alexandre Julliard committed
354 355 356 357 358 359 360
 * 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
 *
361 362 363
 * RETURNS
 *    Success: TRUE
 *    Failure: FALSE
Alexandre Julliard's avatar
Alexandre Julliard committed
364
 */
365 366
BOOL WINAPI SetPixelFormat( HDC hdc, INT iPixelFormat,
                            const PIXELFORMATDESCRIPTOR *ppfd)
Alexandre Julliard's avatar
Alexandre Julliard committed
367
{
368
    INT bRet = FALSE;
369
    DC * dc = get_dc_ptr( hdc );
370

371
    TRACE("(%p,%d,%p)\n",hdc,iPixelFormat,ppfd);
372 373

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

375
    update_dc( dc );
376
    if (!dc->funcs->pSetPixelFormat) FIXME(" :stub\n");
377
    else bRet = dc->funcs->pSetPixelFormat(dc->physDev,iPixelFormat,ppfd);
Lionel Ulmer's avatar
Lionel Ulmer committed
378

379
    release_dc_ptr( dc );
380
    return bRet;
Alexandre Julliard's avatar
Alexandre Julliard committed
381 382 383 384
}


/******************************************************************************
385
 * GetPixelFormat [GDI32.@]
Alexandre Julliard's avatar
Alexandre Julliard committed
386 387 388 389 390 391 392 393 394
 * 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
 */
395
INT WINAPI GetPixelFormat( HDC hdc )
Alexandre Julliard's avatar
Alexandre Julliard committed
396
{
397
    INT ret = 0;
398
    DC * dc = get_dc_ptr( hdc );
399

400
    TRACE("(%p)\n",hdc);
401 402

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

404
    update_dc( dc );
405
    if (!dc->funcs->pGetPixelFormat) FIXME(" :stub\n");
406
    else ret = dc->funcs->pGetPixelFormat(dc->physDev);
Lionel Ulmer's avatar
Lionel Ulmer committed
407

408
    release_dc_ptr( dc );
409
    return ret;
Alexandre Julliard's avatar
Alexandre Julliard committed
410 411 412 413
}


/******************************************************************************
414
 * DescribePixelFormat [GDI32.@]
Alexandre Julliard's avatar
Alexandre Julliard committed
415 416 417 418 419 420 421 422 423 424 425 426
 * 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
 */
427
INT WINAPI DescribePixelFormat( HDC hdc, INT iPixelFormat, UINT nBytes,
Alexandre Julliard's avatar
Alexandre Julliard committed
428 429
                                LPPIXELFORMATDESCRIPTOR ppfd )
{
430
    INT ret = 0;
431
    DC * dc = get_dc_ptr( hdc );
432

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

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

437
    update_dc( dc );
438 439 440 441 442 443 444
    if (!dc->funcs->pDescribePixelFormat)
    {
        FIXME(" :stub\n");
        ppfd->nSize = nBytes;
        ppfd->nVersion = 1;
	ret = 3;
    }
445
    else ret = dc->funcs->pDescribePixelFormat(dc->physDev,iPixelFormat,nBytes,ppfd);
446

447
    release_dc_ptr( dc );
448
    return ret;
Alexandre Julliard's avatar
Alexandre Julliard committed
449 450 451 452
}


/******************************************************************************
453
 * SwapBuffers [GDI32.@]
Alexandre Julliard's avatar
Alexandre Julliard committed
454 455 456 457 458
 * Exchanges front and back buffers of window
 *
 * PARAMS
 *    hdc [I] Device context whose buffers get swapped
 *
459 460 461
 * RETURNS
 *    Success: TRUE
 *    Failure: FALSE
Alexandre Julliard's avatar
Alexandre Julliard committed
462
 */
463
BOOL WINAPI SwapBuffers( HDC hdc )
Alexandre Julliard's avatar
Alexandre Julliard committed
464
{
465
    INT bRet = FALSE;
466
    DC * dc = get_dc_ptr( hdc );
Lionel Ulmer's avatar
Lionel Ulmer committed
467

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

470 471
    if (!dc) return TRUE;

472
    update_dc( dc );
473 474 475 476 477
    if (!dc->funcs->pSwapBuffers)
    {
        FIXME(" :stub\n");
	bRet = TRUE;
    }
478
    else bRet = dc->funcs->pSwapBuffers(dc->physDev);
479

480
    release_dc_ptr( dc );
481
    return bRet;
Alexandre Julliard's avatar
Alexandre Julliard committed
482 483 484
}


Alexandre Julliard's avatar
Alexandre Julliard committed
485
/***********************************************************************
486
 *           PaintRgn    (GDI32.@)
Alexandre Julliard's avatar
Alexandre Julliard committed
487
 */
488
BOOL WINAPI PaintRgn( HDC hdc, HRGN hrgn )
Alexandre Julliard's avatar
Alexandre Julliard committed
489
{
490
    BOOL ret = FALSE;
491 492
    DC * dc = get_dc_ptr( hdc );

493 494
    if (dc)
    {
495
        update_dc( dc );
496
        if (dc->funcs->pPaintRgn) ret = dc->funcs->pPaintRgn(dc->physDev,hrgn);
497
        release_dc_ptr( dc );
498 499
    }
    return ret;
Alexandre Julliard's avatar
Alexandre Julliard committed
500 501 502 503
}


/***********************************************************************
504
 *           FillRgn    (GDI32.@)
Alexandre Julliard's avatar
Alexandre Julliard committed
505
 */
506
BOOL WINAPI FillRgn( HDC hdc, HRGN hrgn, HBRUSH hbrush )
Alexandre Julliard's avatar
Alexandre Julliard committed
507
{
508
    BOOL retval = FALSE;
509
    HBRUSH prevBrush;
510
    DC * dc = get_dc_ptr( hdc );
511

512
    if (!dc) return FALSE;
513
    if(dc->funcs->pFillRgn)
514 515
    {
        update_dc( dc );
516
        retval = dc->funcs->pFillRgn(dc->physDev, hrgn, hbrush);
517
    }
518 519
    else if ((prevBrush = SelectObject( hdc, hbrush )))
    {
520 521
        retval = PaintRgn( hdc, hrgn );
        SelectObject( hdc, prevBrush );
522
    }
523
    release_dc_ptr( dc );
Alexandre Julliard's avatar
Alexandre Julliard committed
524 525 526 527 528
    return retval;
}


/***********************************************************************
529
 *           FrameRgn     (GDI32.@)
Alexandre Julliard's avatar
Alexandre Julliard committed
530
 */
531 532
BOOL WINAPI FrameRgn( HDC hdc, HRGN hrgn, HBRUSH hbrush,
                          INT nWidth, INT nHeight )
Alexandre Julliard's avatar
Alexandre Julliard committed
533
{
534
    BOOL ret = FALSE;
535
    DC *dc = get_dc_ptr( hdc );
536

537
    if (!dc) return FALSE;
538

539
    if(dc->funcs->pFrameRgn)
540 541
    {
        update_dc( dc );
542
        ret = dc->funcs->pFrameRgn( dc->physDev, hrgn, hbrush, nWidth, nHeight );
543
    }
544 545 546 547 548 549 550
    else
    {
        HRGN tmp = CreateRectRgn( 0, 0, 0, 0 );
        if (tmp)
        {
            if (REGION_FrameRgn( tmp, hrgn, nWidth, nHeight ))
            {
551
                FillRgn( hdc, tmp, hbrush );
552 553
                ret = TRUE;
            }
554 555
            DeleteObject( tmp );
        }
556
    }
557
    release_dc_ptr( dc );
558
    return ret;
Alexandre Julliard's avatar
Alexandre Julliard committed
559 560 561 562
}


/***********************************************************************
563
 *           InvertRgn    (GDI32.@)
Alexandre Julliard's avatar
Alexandre Julliard committed
564
 */
565
BOOL WINAPI InvertRgn( HDC hdc, HRGN hrgn )
Alexandre Julliard's avatar
Alexandre Julliard committed
566
{
567 568 569
    HBRUSH prevBrush;
    INT prevROP;
    BOOL retval;
570
    DC *dc = get_dc_ptr( hdc );
571
    if (!dc) return FALSE;
572 573

    if(dc->funcs->pInvertRgn)
574 575
    {
        update_dc( dc );
576
        retval = dc->funcs->pInvertRgn( dc->physDev, hrgn );
577
    }
578 579
    else
    {
580 581 582 583 584
        prevBrush = SelectObject( hdc, GetStockObject(BLACK_BRUSH) );
        prevROP = SetROP2( hdc, R2_NOT );
        retval = PaintRgn( hdc, hrgn );
        SelectObject( hdc, prevBrush );
        SetROP2( hdc, prevROP );
585
    }
586
    release_dc_ptr( dc );
Alexandre Julliard's avatar
Alexandre Julliard committed
587 588 589 590 591
    return retval;
}


/**********************************************************************
592
 *          Polyline   (GDI32.@)
Alexandre Julliard's avatar
Alexandre Julliard committed
593
 */
594
BOOL WINAPI Polyline( HDC hdc, const POINT* pt, INT count )
Alexandre Julliard's avatar
Alexandre Julliard committed
595
{
596
    BOOL ret = FALSE;
597 598
    DC * dc = get_dc_ptr( hdc );

599 600
    if (dc)
    {
601
        update_dc( dc );
602
        if (PATH_IsPathOpen(dc->path)) ret = PATH_Polyline(dc, pt, count);
603
        else if (dc->funcs->pPolyline) ret = dc->funcs->pPolyline(dc->physDev,pt,count);
604
        release_dc_ptr( dc );
605 606
    }
    return ret;
Alexandre Julliard's avatar
Alexandre Julliard committed
607 608
}

609
/**********************************************************************
610
 *          PolylineTo   (GDI32.@)
611
 */
612
BOOL WINAPI PolylineTo( HDC hdc, const POINT* pt, DWORD cCount )
613
{
614
    DC * dc = get_dc_ptr( hdc );
615
    BOOL ret = FALSE;
Huw D M Davies's avatar
Huw D M Davies committed
616

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

619
    if(PATH_IsPathOpen(dc->path))
620 621
    {
        update_dc( dc );
622
        ret = PATH_PolylineTo(dc, pt, cCount);
623
    }
624
    else if(dc->funcs->pPolylineTo)
625 626
    {
        update_dc( dc );
627
        ret = dc->funcs->pPolylineTo(dc->physDev, pt, cCount);
628 629 630
    }
    else /* do it using Polyline */
    {
631 632
        POINT *pts = HeapAlloc( GetProcessHeap(), 0,
				sizeof(POINT) * (cCount + 1) );
633 634
	if (pts)
        {
635 636 637 638 639 640
            pts[0].x = dc->CursPosX;
            pts[0].y = dc->CursPosY;
            memcpy( pts + 1, pt, sizeof(POINT) * cCount );
            ret = Polyline( hdc, pts, cCount + 1 );
            HeapFree( GetProcessHeap(), 0, pts );
        }
641
    }
642
    if(ret) {
643 644
        dc->CursPosX = pt[cCount-1].x;
	dc->CursPosY = pt[cCount-1].y;
645
    }
646
    release_dc_ptr( dc );
647
    return ret;
648
}
Alexandre Julliard's avatar
Alexandre Julliard committed
649 650 651


/**********************************************************************
652
 *          Polygon  (GDI32.@)
Alexandre Julliard's avatar
Alexandre Julliard committed
653
 */
654
BOOL WINAPI Polygon( HDC hdc, const POINT* pt, INT count )
Alexandre Julliard's avatar
Alexandre Julliard committed
655
{
656
    BOOL ret = FALSE;
657 658
    DC * dc = get_dc_ptr( hdc );

659 660
    if (dc)
    {
661
        update_dc( dc );
662
        if (PATH_IsPathOpen(dc->path)) ret = PATH_Polygon(dc, pt, count);
663
        else if (dc->funcs->pPolygon) ret = dc->funcs->pPolygon(dc->physDev,pt,count);
664
        release_dc_ptr( dc );
665
    }
666
    return ret;
Alexandre Julliard's avatar
Alexandre Julliard committed
667 668 669 670
}


/**********************************************************************
671
 *          PolyPolygon  (GDI32.@)
Alexandre Julliard's avatar
Alexandre Julliard committed
672
 */
673 674
BOOL WINAPI PolyPolygon( HDC hdc, const POINT* pt, const INT* counts,
                             UINT polygons )
Alexandre Julliard's avatar
Alexandre Julliard committed
675
{
676
    BOOL ret = FALSE;
677 678
    DC * dc = get_dc_ptr( hdc );

679 680
    if (dc)
    {
681
        update_dc( dc );
682
        if (PATH_IsPathOpen(dc->path)) ret = PATH_PolyPolygon(dc, pt, counts, polygons);
683
        else if (dc->funcs->pPolyPolygon) ret = dc->funcs->pPolyPolygon(dc->physDev,pt,counts,polygons);
684
        release_dc_ptr( dc );
685 686
    }
    return ret;
Alexandre Julliard's avatar
Alexandre Julliard committed
687 688
}

Alexandre Julliard's avatar
Alexandre Julliard committed
689
/**********************************************************************
690
 *          PolyPolyline  (GDI32.@)
Alexandre Julliard's avatar
Alexandre Julliard committed
691
 */
692
BOOL WINAPI PolyPolyline( HDC hdc, const POINT* pt, const DWORD* counts,
693
                            DWORD polylines )
Alexandre Julliard's avatar
Alexandre Julliard committed
694
{
695
    BOOL ret = FALSE;
696 697
    DC * dc = get_dc_ptr( hdc );

698 699
    if (dc)
    {
700
        update_dc( dc );
701
        if (PATH_IsPathOpen(dc->path)) ret = PATH_PolyPolyline(dc, pt, counts, polylines);
702
        else if (dc->funcs->pPolyPolyline) ret = dc->funcs->pPolyPolyline(dc->physDev,pt,counts,polylines);
703
        release_dc_ptr( dc );
704
    }
705
    return ret;
Alexandre Julliard's avatar
Alexandre Julliard committed
706 707
}

Alexandre Julliard's avatar
Alexandre Julliard committed
708
/**********************************************************************
709
 *          ExtFloodFill   (GDI32.@)
Alexandre Julliard's avatar
Alexandre Julliard committed
710
 */
711 712
BOOL WINAPI ExtFloodFill( HDC hdc, INT x, INT y, COLORREF color,
                              UINT fillType )
Alexandre Julliard's avatar
Alexandre Julliard committed
713
{
714
    BOOL ret = FALSE;
715 716
    DC * dc = get_dc_ptr( hdc );

717 718
    if (dc)
    {
719
        update_dc( dc );
720
        if (dc->funcs->pExtFloodFill) ret = dc->funcs->pExtFloodFill(dc->physDev,x,y,color,fillType);
721
        release_dc_ptr( dc );
722
    }
723
    return ret;
Alexandre Julliard's avatar
Alexandre Julliard committed
724 725 726 727
}


/**********************************************************************
728
 *          FloodFill   (GDI32.@)
Alexandre Julliard's avatar
Alexandre Julliard committed
729
 */
730
BOOL WINAPI FloodFill( HDC hdc, INT x, INT y, COLORREF color )
Alexandre Julliard's avatar
Alexandre Julliard committed
731
{
732
    return ExtFloodFill( hdc, x, y, color, FLOODFILLBORDER );
Alexandre Julliard's avatar
Alexandre Julliard committed
733 734 735
}


Alexandre Julliard's avatar
Alexandre Julliard committed
736
/******************************************************************************
737
 * PolyBezier [GDI32.@]
Alexandre Julliard's avatar
Alexandre Julliard committed
738 739 740 741 742 743 744
 * 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
 *
745 746 747
 * RETURNS
 *    Success: TRUE
 *    Failure: FALSE
Alexandre Julliard's avatar
Alexandre Julliard committed
748
 */
749
BOOL WINAPI PolyBezier( HDC hdc, const POINT* lppt, DWORD cPoints )
Alexandre Julliard's avatar
Alexandre Julliard committed
750
{
751
    BOOL ret = FALSE;
752 753 754 755
    DC * dc;

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

757
    dc = get_dc_ptr( hdc );
758 759
    if(!dc) return FALSE;

760
    if(PATH_IsPathOpen(dc->path))
761 762
    {
        update_dc( dc );
763
	ret = PATH_PolyBezier(dc, lppt, cPoints);
764
    }
765
    else if (dc->funcs->pPolyBezier)
766 767
    {
        update_dc( dc );
768
        ret = dc->funcs->pPolyBezier(dc->physDev, lppt, cPoints);
769
    }
770
    else  /* We'll convert it into line segments and draw them using Polyline */
771 772 773 774
    {
        POINT *Pts;
	INT nOut;

775 776
	if ((Pts = GDI_Bezier( lppt, cPoints, &nOut )))
        {
777
	    TRACE("Pts = %p, no = %d\n", Pts, nOut);
778
	    ret = Polyline( hdc, Pts, nOut );
779 780
	    HeapFree( GetProcessHeap(), 0, Pts );
	}
781
    }
782

783
    release_dc_ptr( dc );
784 785 786
    return ret;
}

Alexandre Julliard's avatar
Alexandre Julliard committed
787
/******************************************************************************
788
 * PolyBezierTo [GDI32.@]
Alexandre Julliard's avatar
Alexandre Julliard committed
789 790 791 792 793 794 795
 * 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
 *
796 797 798
 * RETURNS
 *    Success: TRUE
 *    Failure: FALSE
Alexandre Julliard's avatar
Alexandre Julliard committed
799
 */
800
BOOL WINAPI PolyBezierTo( HDC hdc, const POINT* lppt, DWORD cPoints )
Alexandre Julliard's avatar
Alexandre Julliard committed
801
{
802
    DC * dc;
803
    BOOL ret = FALSE;
804

805 806 807
    /* cbPoints must be 3 * n (where n>=1) */
    if (!cPoints || (cPoints % 3) != 0) return FALSE;

808
    dc = get_dc_ptr( hdc );
Alexandre Julliard's avatar
Alexandre Julliard committed
809
    if(!dc) return FALSE;
810

811
    if(PATH_IsPathOpen(dc->path))
812 813
    {
        update_dc( dc );
814
        ret = PATH_PolyBezierTo(dc, lppt, cPoints);
815
    }
816
    else if(dc->funcs->pPolyBezierTo)
817 818
    {
        update_dc( dc );
819
        ret = dc->funcs->pPolyBezierTo(dc->physDev, lppt, cPoints);
820 821 822 823 824 825 826 827 828 829 830 831
    }
    else  /* We'll do it using PolyBezier */
    {
        POINT *pt = HeapAlloc( GetProcessHeap(), 0, sizeof(POINT) * (cPoints + 1) );
	if(pt)
        {
            pt[0].x = dc->CursPosX;
            pt[0].y = dc->CursPosY;
            memcpy(pt + 1, lppt, sizeof(POINT) * cPoints);
            ret = PolyBezier(hdc, pt, cPoints+1);
            HeapFree( GetProcessHeap(), 0, pt );
        }
832
    }
833
    if(ret) {
834 835
        dc->CursPosX = lppt[cPoints-1].x;
        dc->CursPosY = lppt[cPoints-1].y;
836
    }
837
    release_dc_ptr( dc );
Alexandre Julliard's avatar
Alexandre Julliard committed
838 839
    return ret;
}
840

841
/***********************************************************************
842
 *      AngleArc (GDI32.@)
843
 */
844
BOOL WINAPI AngleArc(HDC hdc, INT x, INT y, DWORD dwRadius, FLOAT eStartAngle, FLOAT eSweepAngle)
845
{
846
    INT x1,y1,x2,y2, arcdir;
847 848 849
    BOOL result;
    DC *dc;

850
    if( (signed int)dwRadius < 0 )
851 852
	return FALSE;

853
    dc = get_dc_ptr( hdc );
854 855
    if(!dc) return FALSE;

856
    /* Calculate the end point */
857
    x2 = x + cos((eStartAngle+eSweepAngle)*M_PI/180) * dwRadius;
858
    y2 = y - sin((eStartAngle+eSweepAngle)*M_PI/180) * dwRadius;
859

860
    if(!PATH_IsPathOpen(dc->path) && dc->funcs->pAngleArc)
861 862
    {
        update_dc( dc );
863
        result = dc->funcs->pAngleArc( dc->physDev, x, y, dwRadius, eStartAngle, eSweepAngle );
864
    }
865 866 867 868 869 870 871 872 873 874 875 876 877
    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;
    }
878
    release_dc_ptr( dc );
879
    return result;
880
}
881

882
/***********************************************************************
883
 *      PolyDraw (GDI32.@)
884
 */
885
BOOL WINAPI PolyDraw(HDC hdc, const POINT *lppt, const BYTE *lpbTypes,
886
                       DWORD cCount)
887
{
888
    DC *dc;
889
    BOOL result = FALSE;
890 891
    POINT * line_pts = NULL, * bzr_pts = NULL, bzr[4];
    INT i, num_pts, num_bzr_pts, space, size;
892

893
    dc = get_dc_ptr( hdc );
894
    if(!dc) return FALSE;
895

Evan Stade's avatar
Evan Stade committed
896
    if( PATH_IsPathOpen( dc->path ) )
897 898
    {
        update_dc( dc );
Evan Stade's avatar
Evan Stade committed
899
        result = PATH_PolyDraw(dc, lppt, lpbTypes, cCount);
900
    }
Evan Stade's avatar
Evan Stade committed
901
    else if(dc->funcs->pPolyDraw)
902 903
    {
        update_dc( dc );
904
        result = dc->funcs->pPolyDraw( dc->physDev, lppt, lpbTypes, cCount );
905
    }
Evan Stade's avatar
Evan Stade committed
906
    else {
907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923
        /* 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;
            }
        }
924

925 926 927 928 929 930 931 932 933 934 935
        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)
936
                        Polyline(hdc, line_pts, num_pts);
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
                    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;
            }
966

967 968 969
            if(lpbTypes[i] & PT_CLOSEFIGURE)
                line_pts[num_pts++] = line_pts[0];
        }
970

971
        if(num_pts >= 2)
972
            Polyline(hdc, line_pts, num_pts);
973

974
        MoveToEx(hdc, line_pts[num_pts - 1].x, line_pts[num_pts - 1].y, NULL);
975
        HeapFree(GetProcessHeap(), 0, line_pts);
976
        result = TRUE;
Evan Stade's avatar
Evan Stade committed
977 978
    }

979
end:
980
    release_dc_ptr( dc );
981
    return result;
982
}
983

984 985 986 987 988 989 990 991 992 993 994 995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009

/**********************************************************************
 *           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;
1010
        for(cnt = 0;cnt < dx; cnt++)
1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024
        {
            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;
1025
        for(cnt = 0;cnt < dy; cnt++)
1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040
        {
            callback(nXStart,nYStart,lParam);
            if (err > 0)
            {
                nXStart += xadd;
                err += erradd;
            }
            else err += 2*dx;
            nYStart += yadd;
        }
    }
    return TRUE;
}


1041
/******************************************************************
1042 1043
 *
 *   *Very* simple bezier drawing code,
1044 1045
 *
 *   It uses a recursive algorithm to divide the curve in a series
1046
 *   of straight line segments. Not ideal but sufficient for me.
1047 1048 1049 1050 1051 1052
 *   If you are in need for something better look for some incremental
 *   algorithm.
 *
 *   7 July 1998 Rein Klazes
 */

1053
 /*
1054 1055
  * some macro definitions for bezier drawing
  *
1056
  * to avoid truncation errors the coordinates are
1057 1058
  * shifted upwards. When used in drawing they are
  * shifted down again, including correct rounding
1059
  * and avoiding floating point arithmetic
1060
  * 4 bits should allow 27 bits coordinates which I saw
1061
  * somewhere in the win32 doc's
1062
  *
1063 1064 1065 1066
  */

#define BEZIERSHIFTBITS 4
#define BEZIERSHIFTUP(x)    ((x)<<BEZIERSHIFTBITS)
1067
#define BEZIERPIXEL        BEZIERSHIFTUP(1)
1068 1069 1070 1071 1072 1073 1074 1075
#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)

1076
/* calculate Bezier average, in this case the middle
1077 1078 1079 1080 1081 1082
 * correctly rounded...
 * */

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

1084 1085 1086 1087 1088 1089
/**********************************************************
* 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
Austin English's avatar
Austin English committed
1090
*       returns true if the recursion can be terminated
1091 1092
*/
static BOOL BezierCheck( int level, POINT *Points)
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 1118 1119 1120 1121 1122 1123 1124 1125 1126 1127 1128 1129 1130 1131 1132 1133 1134 1135 1136 1137 1138 1139 1140 1141 1142 1143 1144
    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;
    }
}
1145

1146 1147 1148 1149 1150 1151 1152 1153 1154 1155 1156 1157 1158 1159 1160 1161 1162 1163 1164 1165 1166 1167 1168 1169 1170 1171 1172 1173 1174 1175 1176 1177 1178 1179 1180 1181 1182 1183 1184 1185 1186
/* 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);
    }
}


1187

1188 1189 1190 1191 1192 1193 1194 1195 1196 1197 1198 1199 1200 1201
/***********************************************************************
 *           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).
1202
 *
1203 1204
 *  RETURNS
 *
Austin English's avatar
Austin English committed
1205
 *  Ptr to an array of POINTs that contain the lines that approximate the
1206 1207
 *  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
1208
 *  but since we can't know in advance how many points we will generate, the
1209 1210 1211 1212 1213 1214 1215 1216
 *  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;

1217 1218
    if (count == 1 || (count - 1) % 3 != 0) {
        ERR("Invalid no. of points %d\n", count);
1219 1220 1221 1222 1223 1224 1225 1226 1227 1228 1229 1230 1231 1232 1233 1234
	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;
}
1235 1236

/******************************************************************************
1237
 *           GdiGradientFill   (GDI32.@)
1238 1239
 *
 *  FIXME: we don't support the Alpha channel properly
1240 1241 1242 1243
 */
BOOL WINAPI GdiGradientFill( HDC hdc, TRIVERTEX *vert_array, ULONG nvert,
                          void * grad_array, ULONG ngrad, ULONG mode )
{
1244
  unsigned int i;
1245

1246 1247
  TRACE("vert_array:%p nvert:%d grad_array:%p ngrad:%d\n",
        vert_array, nvert, grad_array, ngrad);
1248 1249 1250 1251 1252 1253 1254 1255 1256 1257 1258

  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;
1259
          int x, dx;
1260 1261 1262 1263 1264 1265 1266 1267 1268
          if (v1->x > v2->x)
            {
              TRIVERTEX *t = v2;
              v2 = v1;
              v1 = t;
            }
          dx = v2->x - v1->x;
          for (x = 0; x < dx; x++)
            {
1269 1270 1271 1272
              POINT pts[2];
              HPEN hPen, hOldPen;
              
              hPen = CreatePen( PS_SOLID, 1, RGB(
1273 1274 1275
                  (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));
1276
              hOldPen = SelectObject( hdc, hPen );
1277
              pts[0].x = v1->x + x;
1278
              pts[0].y = y1;
1279
              pts[1].x = v1->x + x;
1280 1281 1282
              pts[1].y = y2;
              Polyline( hdc, &pts[0], 2 );
              DeleteObject( SelectObject(hdc, hOldPen ) );
1283 1284 1285 1286 1287 1288 1289 1290 1291 1292 1293
            }
        }
      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;
1294
          int y, dy;
1295 1296 1297 1298 1299 1300 1301 1302 1303
          if (v1->y > v2->y)
            {
              TRIVERTEX *t = v2;
              v2 = v1;
              v1 = t;
            }
          dy = v2->y - v1->y;
          for (y = 0; y < dy; y++)
            {
1304 1305 1306 1307
              POINT pts[2];
              HPEN hPen, hOldPen;
              
              hPen = CreatePen( PS_SOLID, 1, RGB(
1308 1309 1310
                  (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));
1311 1312
              hOldPen = SelectObject( hdc, hPen );
              pts[0].x = x1;
1313
              pts[0].y = v1->y + y;
1314
              pts[1].x = x2;
1315
              pts[1].y = v1->y + y;
1316 1317
              Polyline( hdc, &pts[0], 2 );
              DeleteObject( SelectObject(hdc, hOldPen ) );
1318 1319 1320 1321 1322 1323 1324 1325 1326 1327 1328 1329 1330 1331 1332 1333 1334 1335 1336 1337 1338 1339 1340 1341 1342 1343 1344 1345 1346 1347 1348 1349 1350 1351 1352 1353 1354 1355 1356 1357 1358 1359 1360 1361 1362 1363 1364 1365 1366 1367 1368 1369 1370 1371 1372 1373 1374 1375 1376 1377 1378 1379 1380 1381
            }
        }
      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;
1382 1383 1384 1385
  }

  return TRUE;
}