painting.c 33.5 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 42 43
/***********************************************************************
 *           null driver fallback implementations
 */

44
BOOL nulldrv_AngleArc( PHYSDEV dev, INT x, INT y, DWORD radius, FLOAT start, FLOAT sweep )
45 46 47 48 49 50 51 52 53 54 55
{
    INT x1 = GDI_ROUND( x + cos( start * M_PI / 180 ) * radius );
    INT y1 = GDI_ROUND( y - sin( start * M_PI / 180 ) * radius );
    INT x2 = GDI_ROUND( x + cos( (start + sweep) * M_PI / 180) * radius );
    INT y2 = GDI_ROUND( y - sin( (start + sweep) * M_PI / 180) * radius );
    INT arcdir = SetArcDirection( dev->hdc, sweep >= 0 ? AD_COUNTERCLOCKWISE : AD_CLOCKWISE );
    BOOL ret = ArcTo( dev->hdc, x - radius, y - radius, x + radius, y + radius, x1, y1, x2, y2 );
    SetArcDirection( dev->hdc, arcdir );
    return ret;
}

56 57
BOOL nulldrv_ArcTo( PHYSDEV dev, INT left, INT top, INT right, INT bottom,
                    INT xstart, INT ystart, INT xend, INT yend )
58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74
{
    INT width = abs( right - left );
    INT height = abs( bottom - top );
    double xradius = width / 2.0;
    double yradius = height / 2.0;
    double xcenter = right > left ? left + xradius : right + xradius;
    double ycenter = bottom > top ? top + yradius : bottom + yradius;
    double angle;

    if (!height || !width) return FALSE;
    /* draw a line from the current position to the starting point of the arc, then draw the arc */
    angle = atan2( (ystart - ycenter) / height, (xstart - xcenter) / width );
    LineTo( dev->hdc, GDI_ROUND( xcenter + cos(angle) * xradius ),
            GDI_ROUND( ycenter + sin(angle) * yradius ));
    return Arc( dev->hdc, left, top, right, bottom, xstart, ystart, xend, yend );
}

75
BOOL nulldrv_FillRgn( PHYSDEV dev, HRGN rgn, HBRUSH brush )
76 77 78 79 80 81 82 83 84 85 86 87
{
    BOOL ret = FALSE;
    HBRUSH prev;

    if ((prev = SelectObject( dev->hdc, brush )))
    {
        ret = PaintRgn( dev->hdc, rgn );
        SelectObject( dev->hdc, prev );
    }
    return ret;
}

88
BOOL nulldrv_FrameRgn( PHYSDEV dev, HRGN rgn, HBRUSH brush, INT width, INT height )
89 90 91 92 93 94 95 96 97 98 99 100
{
    BOOL ret = FALSE;
    HRGN tmp = CreateRectRgn( 0, 0, 0, 0 );

    if (tmp)
    {
        if (REGION_FrameRgn( tmp, rgn, width, height )) ret = FillRgn( dev->hdc, tmp, brush );
        DeleteObject( tmp );
    }
    return ret;
}

101
BOOL nulldrv_InvertRgn( PHYSDEV dev, HRGN rgn )
102 103 104 105 106 107 108 109 110
{
    HBRUSH prev_brush = SelectObject( dev->hdc, GetStockObject(BLACK_BRUSH) );
    INT prev_rop = SetROP2( dev->hdc, R2_NOT );
    BOOL ret = PaintRgn( dev->hdc, rgn );
    SelectObject( dev->hdc, prev_brush );
    SetROP2( dev->hdc, prev_rop );
    return ret;
}

111
BOOL nulldrv_PolyBezier( PHYSDEV dev, const POINT *points, DWORD count )
112 113 114 115 116 117 118 119 120 121 122 123 124
{
    BOOL ret = FALSE;
    POINT *pts;
    INT n;

    if ((pts = GDI_Bezier( points, count, &n )))
    {
        ret = Polyline( dev->hdc, pts, n );
        HeapFree( GetProcessHeap(), 0, pts );
    }
    return ret;
}

125
BOOL nulldrv_PolyBezierTo( PHYSDEV dev, const POINT *points, DWORD count )
126
{
127
    DC *dc = get_nulldrv_dc( dev );
128 129 130 131 132
    BOOL ret = FALSE;
    POINT *pts = HeapAlloc( GetProcessHeap(), 0, sizeof(POINT) * (count + 1) );

    if (pts)
    {
133
        pts[0] = dc->cur_pos;
134 135 136 137 138 139 140
        memcpy( pts + 1, points, sizeof(POINT) * count );
        ret = PolyBezier( dev->hdc, pts, count + 1 );
        HeapFree( GetProcessHeap(), 0, pts );
    }
    return ret;
}

141
BOOL nulldrv_PolyDraw( PHYSDEV dev, const POINT *points, const BYTE *types, DWORD count )
142
{
143
    DC *dc = get_nulldrv_dc( dev );
144
    POINT *line_pts = NULL, *bzr_pts = NULL, bzr[4];
145 146
    DWORD i;
    INT num_pts, num_bzr_pts, space, size;
147 148 149 150 151 152 153 154 155 156 157

    /* check for valid point types */
    for (i = 0; i < count; i++)
    {
        switch (types[i])
        {
        case PT_MOVETO:
        case PT_LINETO | PT_CLOSEFIGURE:
        case PT_LINETO:
            break;
        case PT_BEZIERTO:
158 159 160 161 162
            if (i + 2 >= count) return FALSE;
            if (types[i + 1] != PT_BEZIERTO) return FALSE;
            if ((types[i + 2] & ~PT_CLOSEFIGURE) != PT_BEZIERTO) return FALSE;
            i += 2;
            break;
163 164 165 166 167 168 169 170 171
        default:
            return FALSE;
        }
    }

    space = count + 300;
    line_pts = HeapAlloc( GetProcessHeap(), 0, space * sizeof(POINT) );
    num_pts = 1;

172
    line_pts[0] = dc->cur_pos;
173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213
    for (i = 0; i < count; i++)
    {
        switch (types[i])
        {
        case PT_MOVETO:
            if (num_pts >= 2) Polyline( dev->hdc, line_pts, num_pts );
            num_pts = 0;
            line_pts[num_pts++] = points[i];
            break;
        case PT_LINETO:
        case (PT_LINETO | PT_CLOSEFIGURE):
            line_pts[num_pts++] = points[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], &points[i], 3 * sizeof(POINT) );

            if ((bzr_pts = GDI_Bezier( bzr, 4, &num_bzr_pts )))
            {
                size = num_pts + (count - 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;
        }
        if (types[i] & PT_CLOSEFIGURE) line_pts[num_pts++] = line_pts[0];
    }

    if (num_pts >= 2) Polyline( dev->hdc, line_pts, num_pts );
    HeapFree( GetProcessHeap(), 0, line_pts );
    return TRUE;
}

214
BOOL nulldrv_PolylineTo( PHYSDEV dev, const POINT *points, INT count )
215
{
216
    DC *dc = get_nulldrv_dc( dev );
217 218 219 220 221 222
    BOOL ret = FALSE;
    POINT *pts;

    if (!count) return FALSE;
    if ((pts = HeapAlloc( GetProcessHeap(), 0, sizeof(POINT) * (count + 1) )))
    {
223
        pts[0] = dc->cur_pos;
224 225 226 227 228 229 230
        memcpy( pts + 1, points, sizeof(POINT) * count );
        ret = Polyline( dev->hdc, pts, count + 1 );
        HeapFree( GetProcessHeap(), 0, pts );
    }
    return ret;
}

Alexandre Julliard's avatar
Alexandre Julliard committed
231
/***********************************************************************
232
 *           LineTo    (GDI32.@)
Alexandre Julliard's avatar
Alexandre Julliard committed
233
 */
234
BOOL WINAPI LineTo( HDC hdc, INT x, INT y )
Alexandre Julliard's avatar
Alexandre Julliard committed
235
{
236
    DC * dc = get_dc_ptr( hdc );
237
    PHYSDEV physdev;
238
    BOOL ret;
Alexandre Julliard's avatar
Alexandre Julliard committed
239

240 241
    TRACE( "%p, (%d, %d)\n", hdc, x, y );

242 243
    if(!dc) return FALSE;

244
    update_dc( dc );
245 246 247
    physdev = GET_DC_PHYSDEV( dc, pLineTo );
    ret = physdev->funcs->pLineTo( physdev, x, y );

248 249 250 251
    if(ret)
    {
        dc->cur_pos.x = x;
        dc->cur_pos.y = y;
252
    }
253
    release_dc_ptr( dc );
254
    return ret;
Alexandre Julliard's avatar
Alexandre Julliard committed
255 256 257 258
}


/***********************************************************************
259
 *           MoveToEx    (GDI32.@)
Alexandre Julliard's avatar
Alexandre Julliard committed
260
 */
261
BOOL WINAPI MoveToEx( HDC hdc, INT x, INT y, LPPOINT pt )
Alexandre Julliard's avatar
Alexandre Julliard committed
262
{
263 264
    BOOL ret;
    PHYSDEV physdev;
265
    DC * dc = get_dc_ptr( hdc );
Alexandre Julliard's avatar
Alexandre Julliard committed
266

267 268
    TRACE( "%p, (%d, %d), %p\n", hdc, x, y, pt );

269 270
    if(!dc) return FALSE;

271 272 273 274 275
    if(pt)
        *pt = dc->cur_pos;

    dc->cur_pos.x = x;
    dc->cur_pos.y = y;
276

277 278
    physdev = GET_DC_PHYSDEV( dc, pMoveTo );
    ret = physdev->funcs->pMoveTo( physdev, x, y );
279
    release_dc_ptr( dc );
280
    return ret;
Alexandre Julliard's avatar
Alexandre Julliard committed
281 282 283 284
}


/***********************************************************************
285
 *           Arc    (GDI32.@)
Alexandre Julliard's avatar
Alexandre Julliard committed
286
 */
287 288 289
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
290
{
291 292
    PHYSDEV physdev;
    BOOL ret;
293 294
    DC * dc = get_dc_ptr( hdc );

295 296
    TRACE( "%p, (%d, %d)-(%d, %d), (%d, %d), (%d, %d)\n", hdc, left, top, right, bottom, xstart, ystart, xend, yend );

297 298 299 300 301
    if (!dc) return FALSE;
    update_dc( dc );
    physdev = GET_DC_PHYSDEV( dc, pArc );
    ret = physdev->funcs->pArc( physdev, left, top, right, bottom, xstart, ystart, xend, yend );
    release_dc_ptr( dc );
302
    return ret;
Alexandre Julliard's avatar
Alexandre Julliard committed
303 304
}

305
/***********************************************************************
306
 *           ArcTo    (GDI32.@)
307
 */
308 309
BOOL WINAPI ArcTo( HDC hdc,
                     INT left,   INT top,
310 311 312
                     INT right,  INT bottom,
                     INT xstart, INT ystart,
                     INT xend,   INT yend )
313
{
314 315
    double width = abs( right - left ),
        height = abs( bottom - top ),
316 317 318 319 320
        xradius = width/2,
        yradius = height/2,
        xcenter = right > left ? left+xradius : right+xradius,
        ycenter = bottom > top ? top+yradius : bottom+yradius,
        angle;
321
    PHYSDEV physdev;
322
    BOOL result;
323
    DC * dc = get_dc_ptr( hdc );
324

325 326 327
    TRACE( "%p, (%d, %d)-(%d, %d), (%d, %d), (%d, %d)\n", hdc, left, top, right, bottom, xstart, ystart, xend, yend );

    if(!dc) return FALSE;
328
    update_dc( dc );
329 330 331
    physdev = GET_DC_PHYSDEV( dc, pArcTo );
    result = physdev->funcs->pArcTo( physdev, left, top, right, bottom, xstart, ystart, xend, yend );

332 333
    if (result)
    {
334 335
        angle = atan2(((yend-ycenter)/height),
                      ((xend-xcenter)/width));
336 337
        dc->cur_pos.x = GDI_ROUND( xcenter + (cos( angle ) * xradius) );
        dc->cur_pos.y = GDI_ROUND( ycenter + (sin( angle ) * yradius) );
338
    }
339
    release_dc_ptr( dc );
340 341
    return result;
}
Alexandre Julliard's avatar
Alexandre Julliard committed
342 343 344


/***********************************************************************
345
 *           Pie   (GDI32.@)
Alexandre Julliard's avatar
Alexandre Julliard committed
346
 */
347 348 349
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
350
{
351 352
    BOOL ret;
    PHYSDEV physdev;
353
    DC * dc = get_dc_ptr( hdc );
354

355 356 357
    TRACE( "%p, (%d, %d)-(%d, %d), (%d, %d), (%d, %d)\n", hdc, left, top, right, bottom, xstart, ystart, xend, yend );

    if (!dc) return FALSE;
358
    update_dc( dc );
359 360
    physdev = GET_DC_PHYSDEV( dc, pPie );
    ret = physdev->funcs->pPie( physdev, left, top, right, bottom, xstart, ystart, xend, yend );
361
    release_dc_ptr( dc );
362
    return ret;
Alexandre Julliard's avatar
Alexandre Julliard committed
363 364 365 366
}


/***********************************************************************
367
 *           Chord    (GDI32.@)
Alexandre Julliard's avatar
Alexandre Julliard committed
368
 */
369 370 371
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
372
{
373 374
    BOOL ret;
    PHYSDEV physdev;
375
    DC * dc = get_dc_ptr( hdc );
376

377 378 379
    TRACE( "%p, (%d, %d)-(%d, %d), (%d, %d), (%d, %d)\n", hdc, left, top, right, bottom, xstart, ystart, xend, yend );

    if (!dc) return FALSE;
380
    update_dc( dc );
381 382
    physdev = GET_DC_PHYSDEV( dc, pChord );
    ret = physdev->funcs->pChord( physdev, left, top, right, bottom, xstart, ystart, xend, yend );
383
    release_dc_ptr( dc );
384
    return ret;
Alexandre Julliard's avatar
Alexandre Julliard committed
385 386 387 388
}


/***********************************************************************
389
 *           Ellipse    (GDI32.@)
Alexandre Julliard's avatar
Alexandre Julliard committed
390
 */
391 392
BOOL WINAPI Ellipse( HDC hdc, INT left, INT top,
                         INT right, INT bottom )
Alexandre Julliard's avatar
Alexandre Julliard committed
393
{
394 395
    BOOL ret;
    PHYSDEV physdev;
396
    DC * dc = get_dc_ptr( hdc );
397

398 399 400
    TRACE( "%p, (%d, %d)-(%d, %d)\n", hdc, left, top, right, bottom );

    if (!dc) return FALSE;
401
    update_dc( dc );
402 403
    physdev = GET_DC_PHYSDEV( dc, pEllipse );
    ret = physdev->funcs->pEllipse( physdev, left, top, right, bottom );
404
    release_dc_ptr( dc );
405
    return ret;
Alexandre Julliard's avatar
Alexandre Julliard committed
406 407 408 409
}


/***********************************************************************
410
 *           Rectangle    (GDI32.@)
Alexandre Julliard's avatar
Alexandre Julliard committed
411
 */
412 413
BOOL WINAPI Rectangle( HDC hdc, INT left, INT top,
                           INT right, INT bottom )
Alexandre Julliard's avatar
Alexandre Julliard committed
414
{
415 416
    PHYSDEV physdev;
    BOOL ret;
417 418
    DC * dc = get_dc_ptr( hdc );

419 420
    TRACE( "%p, (%d, %d)-(%d, %d)\n", hdc, left, top, right, bottom );

421 422 423 424 425
    if (!dc) return FALSE;
    update_dc( dc );
    physdev = GET_DC_PHYSDEV( dc, pRectangle );
    ret = physdev->funcs->pRectangle( physdev, left, top, right, bottom );
    release_dc_ptr( dc );
426
    return ret;
Alexandre Julliard's avatar
Alexandre Julliard committed
427 428 429 430
}


/***********************************************************************
431
 *           RoundRect    (GDI32.@)
Alexandre Julliard's avatar
Alexandre Julliard committed
432
 */
433 434
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
435
{
436 437
    PHYSDEV physdev;
    BOOL ret;
438
    DC *dc = get_dc_ptr( hdc );
439

440 441
    TRACE( "%p, (%d, %d)-(%d, %d), %dx%d\n", hdc, left, top, right, bottom, ell_width, ell_height );

442 443 444 445 446
    if (!dc) return FALSE;
    update_dc( dc );
    physdev = GET_DC_PHYSDEV( dc, pRoundRect );
    ret = physdev->funcs->pRoundRect( physdev, left, top, right, bottom, ell_width, ell_height );
    release_dc_ptr( dc );
447
    return ret;
Alexandre Julliard's avatar
Alexandre Julliard committed
448 449 450
}

/***********************************************************************
451
 *           SetPixel    (GDI32.@)
Alexandre Julliard's avatar
Alexandre Julliard committed
452
 */
453
COLORREF WINAPI SetPixel( HDC hdc, INT x, INT y, COLORREF color )
Alexandre Julliard's avatar
Alexandre Julliard committed
454
{
455 456
    PHYSDEV physdev;
    COLORREF ret;
457 458
    DC * dc = get_dc_ptr( hdc );

459 460 461 462 463
    if (!dc) return 0;
    update_dc( dc );
    physdev = GET_DC_PHYSDEV( dc, pSetPixel );
    ret = physdev->funcs->pSetPixel( physdev, x, y, color );
    release_dc_ptr( dc );
464
    return ret;
Alexandre Julliard's avatar
Alexandre Julliard committed
465 466
}

Alexandre Julliard's avatar
Alexandre Julliard committed
467
/***********************************************************************
468
 *           SetPixelV    (GDI32.@)
Alexandre Julliard's avatar
Alexandre Julliard committed
469
 */
470
BOOL WINAPI SetPixelV( HDC hdc, INT x, INT y, COLORREF color )
Alexandre Julliard's avatar
Alexandre Julliard committed
471
{
472
    PHYSDEV physdev;
473 474
    DC * dc = get_dc_ptr( hdc );

475 476 477 478 479 480
    if (!dc) return FALSE;
    update_dc( dc );
    physdev = GET_DC_PHYSDEV( dc, pSetPixel );
    physdev->funcs->pSetPixel( physdev, x, y, color );
    release_dc_ptr( dc );
    return TRUE;
Alexandre Julliard's avatar
Alexandre Julliard committed
481
}
Alexandre Julliard's avatar
Alexandre Julliard committed
482 483

/***********************************************************************
484
 *           GetPixel    (GDI32.@)
Alexandre Julliard's avatar
Alexandre Julliard committed
485
 */
486
COLORREF WINAPI GetPixel( HDC hdc, INT x, INT y )
Alexandre Julliard's avatar
Alexandre Julliard committed
487
{
488 489
    PHYSDEV physdev;
    COLORREF ret;
490
    DC * dc = get_dc_ptr( hdc );
Alexandre Julliard's avatar
Alexandre Julliard committed
491

492 493 494 495 496
    if (!dc) return CLR_INVALID;
    update_dc( dc );
    physdev = GET_DC_PHYSDEV( dc, pGetPixel );
    ret = physdev->funcs->pGetPixel( physdev, x, y );
    release_dc_ptr( dc );
497
    return ret;
Alexandre Julliard's avatar
Alexandre Julliard committed
498 499 500
}


Alexandre Julliard's avatar
Alexandre Julliard committed
501
/******************************************************************************
502
 * GdiSetPixelFormat [GDI32.@]
Alexandre Julliard's avatar
Alexandre Julliard committed
503
 *
504
 * Probably not the correct semantics, it's supposed to be an internal backend for SetPixelFormat.
Alexandre Julliard's avatar
Alexandre Julliard committed
505
 */
506
BOOL WINAPI GdiSetPixelFormat( HDC hdc, INT format, const PIXELFORMATDESCRIPTOR *descr )
Alexandre Julliard's avatar
Alexandre Julliard committed
507
{
508 509
    DC *dc;
    BOOL ret = TRUE;
510

511
    TRACE("(%p,%d,%p)\n", hdc, format, descr);
512

513 514 515 516 517 518
    if (!(dc = get_dc_ptr( hdc ))) return FALSE;

    if (!dc->pixel_format) dc->pixel_format = format;
    else ret = (dc->pixel_format == format);
    release_dc_ptr( dc );
    return ret;
Alexandre Julliard's avatar
Alexandre Julliard committed
519 520 521 522
}


/******************************************************************************
523
 * GdiDescribePixelFormat [GDI32.@]
Alexandre Julliard's avatar
Alexandre Julliard committed
524
 *
525
 * Probably not the correct semantics, it's supposed to be an internal backend for DescribePixelFormat.
Alexandre Julliard's avatar
Alexandre Julliard committed
526
 */
527
INT WINAPI GdiDescribePixelFormat( HDC hdc, INT format, UINT size, PIXELFORMATDESCRIPTOR *descr )
Alexandre Julliard's avatar
Alexandre Julliard committed
528
{
529 530
    FIXME( "(%p,%d,%d,%p): stub\n", hdc, format, size, descr );
    return 0;
Alexandre Julliard's avatar
Alexandre Julliard committed
531 532 533 534
}


/******************************************************************************
535
 * GdiSwapBuffers [GDI32.@]
Alexandre Julliard's avatar
Alexandre Julliard committed
536
 *
537
 * Probably not the correct semantics, it's supposed to be an internal backend for SwapBuffers.
Alexandre Julliard's avatar
Alexandre Julliard committed
538
 */
539
BOOL WINAPI GdiSwapBuffers( HDC hdc )
Alexandre Julliard's avatar
Alexandre Julliard committed
540
{
541 542
    FIXME( "(%p): stub\n", hdc );
    return FALSE;
Alexandre Julliard's avatar
Alexandre Julliard committed
543 544 545
}


Alexandre Julliard's avatar
Alexandre Julliard committed
546
/***********************************************************************
547
 *           PaintRgn    (GDI32.@)
Alexandre Julliard's avatar
Alexandre Julliard committed
548
 */
549
BOOL WINAPI PaintRgn( HDC hdc, HRGN hrgn )
Alexandre Julliard's avatar
Alexandre Julliard committed
550
{
551 552
    PHYSDEV physdev;
    BOOL ret;
553 554
    DC * dc = get_dc_ptr( hdc );

555 556
    TRACE( "%p, %p\n", hdc, hrgn );

557 558 559 560 561
    if (!dc) return FALSE;
    update_dc( dc );
    physdev = GET_DC_PHYSDEV( dc, pPaintRgn );
    ret = physdev->funcs->pPaintRgn( physdev, hrgn );
    release_dc_ptr( dc );
562
    return ret;
Alexandre Julliard's avatar
Alexandre Julliard committed
563 564 565 566
}


/***********************************************************************
567
 *           FillRgn    (GDI32.@)
Alexandre Julliard's avatar
Alexandre Julliard committed
568
 */
569
BOOL WINAPI FillRgn( HDC hdc, HRGN hrgn, HBRUSH hbrush )
Alexandre Julliard's avatar
Alexandre Julliard committed
570
{
571 572
    PHYSDEV physdev;
    BOOL retval;
573
    DC * dc = get_dc_ptr( hdc );
574

575 576
    TRACE( "%p, %p, %p\n", hdc, hrgn, hbrush );

577 578 579 580 581
    if (!dc) return FALSE;
    update_dc( dc );
    physdev = GET_DC_PHYSDEV( dc, pFillRgn );
    retval = physdev->funcs->pFillRgn( physdev, hrgn, hbrush );
    release_dc_ptr( dc );
Alexandre Julliard's avatar
Alexandre Julliard committed
582 583 584 585 586
    return retval;
}


/***********************************************************************
587
 *           FrameRgn     (GDI32.@)
Alexandre Julliard's avatar
Alexandre Julliard committed
588
 */
589 590
BOOL WINAPI FrameRgn( HDC hdc, HRGN hrgn, HBRUSH hbrush,
                          INT nWidth, INT nHeight )
Alexandre Julliard's avatar
Alexandre Julliard committed
591
{
592 593
    PHYSDEV physdev;
    BOOL ret;
594
    DC *dc = get_dc_ptr( hdc );
595

596 597
    TRACE( "%p, %p, %p, %dx%d\n", hdc, hrgn, hbrush, nWidth, nHeight );

598 599 600 601 602
    if (!dc) return FALSE;
    update_dc( dc );
    physdev = GET_DC_PHYSDEV( dc, pFrameRgn );
    ret = physdev->funcs->pFrameRgn( physdev, hrgn, hbrush, nWidth, nHeight );
    release_dc_ptr( dc );
603
    return ret;
Alexandre Julliard's avatar
Alexandre Julliard committed
604 605 606 607
}


/***********************************************************************
608
 *           InvertRgn    (GDI32.@)
Alexandre Julliard's avatar
Alexandre Julliard committed
609
 */
610
BOOL WINAPI InvertRgn( HDC hdc, HRGN hrgn )
Alexandre Julliard's avatar
Alexandre Julliard committed
611
{
612 613
    PHYSDEV physdev;
    BOOL ret;
614
    DC *dc = get_dc_ptr( hdc );
615

616 617
    TRACE( "%p, %p\n", hdc, hrgn );

618 619 620 621 622
    if (!dc) return FALSE;
    update_dc( dc );
    physdev = GET_DC_PHYSDEV( dc, pInvertRgn );
    ret = physdev->funcs->pInvertRgn( physdev, hrgn );
    release_dc_ptr( dc );
623
    return ret;
Alexandre Julliard's avatar
Alexandre Julliard committed
624 625 626 627
}


/**********************************************************************
628
 *          Polyline   (GDI32.@)
Alexandre Julliard's avatar
Alexandre Julliard committed
629
 */
630
BOOL WINAPI Polyline( HDC hdc, const POINT* pt, INT count )
Alexandre Julliard's avatar
Alexandre Julliard committed
631
{
632 633
    PHYSDEV physdev;
    BOOL ret;
634 635
    DC * dc = get_dc_ptr( hdc );

636 637
    TRACE( "%p, %p, %d\n", hdc, pt, count );

638 639 640 641 642
    if (!dc) return FALSE;
    update_dc( dc );
    physdev = GET_DC_PHYSDEV( dc, pPolyline );
    ret = physdev->funcs->pPolyline( physdev, pt, count );
    release_dc_ptr( dc );
643
    return ret;
Alexandre Julliard's avatar
Alexandre Julliard committed
644 645
}

646
/**********************************************************************
647
 *          PolylineTo   (GDI32.@)
648
 */
649
BOOL WINAPI PolylineTo( HDC hdc, const POINT* pt, DWORD cCount )
650
{
651
    DC * dc = get_dc_ptr( hdc );
652 653
    PHYSDEV physdev;
    BOOL ret;
Huw D M Davies's avatar
Huw D M Davies committed
654

655 656
    TRACE( "%p, %p, %u\n", hdc, pt, cCount );

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

659
    update_dc( dc );
660 661 662
    physdev = GET_DC_PHYSDEV( dc, pPolylineTo );
    ret = physdev->funcs->pPolylineTo( physdev, pt, cCount );

663
    if (ret && cCount)
664 665
        dc->cur_pos = pt[cCount - 1];

666
    release_dc_ptr( dc );
667
    return ret;
668
}
Alexandre Julliard's avatar
Alexandre Julliard committed
669 670 671


/**********************************************************************
672
 *          Polygon  (GDI32.@)
Alexandre Julliard's avatar
Alexandre Julliard committed
673
 */
674
BOOL WINAPI Polygon( HDC hdc, const POINT* pt, INT count )
Alexandre Julliard's avatar
Alexandre Julliard committed
675
{
676 677
    PHYSDEV physdev;
    BOOL ret;
678 679
    DC * dc = get_dc_ptr( hdc );

680 681
    TRACE( "%p, %p, %d\n", hdc, pt, count );

682 683 684 685 686
    if (!dc) return FALSE;
    update_dc( dc );
    physdev = GET_DC_PHYSDEV( dc, pPolygon );
    ret = physdev->funcs->pPolygon( physdev, pt, count );
    release_dc_ptr( dc );
687
    return ret;
Alexandre Julliard's avatar
Alexandre Julliard committed
688 689 690 691
}


/**********************************************************************
692
 *          PolyPolygon  (GDI32.@)
Alexandre Julliard's avatar
Alexandre Julliard committed
693
 */
694 695
BOOL WINAPI PolyPolygon( HDC hdc, const POINT* pt, const INT* counts,
                             UINT polygons )
Alexandre Julliard's avatar
Alexandre Julliard committed
696
{
697 698
    PHYSDEV physdev;
    BOOL ret;
699 700
    DC * dc = get_dc_ptr( hdc );

701 702
    TRACE( "%p, %p, %p, %u\n", hdc, pt, counts, polygons );

703 704 705 706 707
    if (!dc) return FALSE;
    update_dc( dc );
    physdev = GET_DC_PHYSDEV( dc, pPolyPolygon );
    ret = physdev->funcs->pPolyPolygon( physdev, pt, counts, polygons );
    release_dc_ptr( dc );
708
    return ret;
Alexandre Julliard's avatar
Alexandre Julliard committed
709 710
}

Alexandre Julliard's avatar
Alexandre Julliard committed
711
/**********************************************************************
712
 *          PolyPolyline  (GDI32.@)
Alexandre Julliard's avatar
Alexandre Julliard committed
713
 */
714
BOOL WINAPI PolyPolyline( HDC hdc, const POINT* pt, const DWORD* counts,
715
                            DWORD polylines )
Alexandre Julliard's avatar
Alexandre Julliard committed
716
{
717 718
    PHYSDEV physdev;
    BOOL ret;
719 720
    DC * dc = get_dc_ptr( hdc );

721 722
    TRACE( "%p, %p, %p, %u\n", hdc, pt, counts, polylines );

723 724 725 726 727
    if (!dc) return FALSE;
    update_dc( dc );
    physdev = GET_DC_PHYSDEV( dc, pPolyPolyline );
    ret = physdev->funcs->pPolyPolyline( physdev, pt, counts, polylines );
    release_dc_ptr( dc );
728
    return ret;
Alexandre Julliard's avatar
Alexandre Julliard committed
729 730
}

Alexandre Julliard's avatar
Alexandre Julliard committed
731
/**********************************************************************
732
 *          ExtFloodFill   (GDI32.@)
Alexandre Julliard's avatar
Alexandre Julliard committed
733
 */
734 735
BOOL WINAPI ExtFloodFill( HDC hdc, INT x, INT y, COLORREF color,
                              UINT fillType )
Alexandre Julliard's avatar
Alexandre Julliard committed
736
{
737 738
    PHYSDEV physdev;
    BOOL ret;
739 740
    DC * dc = get_dc_ptr( hdc );

741 742
    TRACE( "%p, (%d, %d), %08x, %x\n", hdc, x, y, color, fillType );

743 744 745 746 747
    if (!dc) return FALSE;
    update_dc( dc );
    physdev = GET_DC_PHYSDEV( dc, pExtFloodFill );
    ret = physdev->funcs->pExtFloodFill( physdev, x, y, color, fillType );
    release_dc_ptr( dc );
748
    return ret;
Alexandre Julliard's avatar
Alexandre Julliard committed
749 750 751 752
}


/**********************************************************************
753
 *          FloodFill   (GDI32.@)
Alexandre Julliard's avatar
Alexandre Julliard committed
754
 */
755
BOOL WINAPI FloodFill( HDC hdc, INT x, INT y, COLORREF color )
Alexandre Julliard's avatar
Alexandre Julliard committed
756
{
757
    return ExtFloodFill( hdc, x, y, color, FLOODFILLBORDER );
Alexandre Julliard's avatar
Alexandre Julliard committed
758 759 760
}


Alexandre Julliard's avatar
Alexandre Julliard committed
761
/******************************************************************************
762
 * PolyBezier [GDI32.@]
Alexandre Julliard's avatar
Alexandre Julliard committed
763 764 765 766 767 768 769
 * 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
 *
770 771 772
 * RETURNS
 *    Success: TRUE
 *    Failure: FALSE
Alexandre Julliard's avatar
Alexandre Julliard committed
773
 */
774
BOOL WINAPI PolyBezier( HDC hdc, const POINT* lppt, DWORD cPoints )
Alexandre Julliard's avatar
Alexandre Julliard committed
775
{
776 777
    PHYSDEV physdev;
    BOOL ret;
778 779
    DC * dc;

780 781
    TRACE( "%p, %p, %u\n", hdc, lppt, cPoints );

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

785
    dc = get_dc_ptr( hdc );
786 787
    if(!dc) return FALSE;

788
    update_dc( dc );
789 790
    physdev = GET_DC_PHYSDEV( dc, pPolyBezier );
    ret = physdev->funcs->pPolyBezier( physdev, lppt, cPoints );
791
    release_dc_ptr( dc );
792 793 794
    return ret;
}

Alexandre Julliard's avatar
Alexandre Julliard committed
795
/******************************************************************************
796
 * PolyBezierTo [GDI32.@]
Alexandre Julliard's avatar
Alexandre Julliard committed
797 798 799 800 801 802 803
 * 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
 *
804 805 806
 * RETURNS
 *    Success: TRUE
 *    Failure: FALSE
Alexandre Julliard's avatar
Alexandre Julliard committed
807
 */
808
BOOL WINAPI PolyBezierTo( HDC hdc, const POINT* lppt, DWORD cPoints )
Alexandre Julliard's avatar
Alexandre Julliard committed
809
{
810
    DC * dc;
811 812
    BOOL ret;
    PHYSDEV physdev;
813

814 815
    TRACE( "%p, %p, %u\n", hdc, lppt, cPoints );

816 817 818
    /* cbPoints must be 3 * n (where n>=1) */
    if (!cPoints || (cPoints % 3) != 0) return FALSE;

819
    dc = get_dc_ptr( hdc );
Alexandre Julliard's avatar
Alexandre Julliard committed
820
    if(!dc) return FALSE;
821

822
    update_dc( dc );
823 824 825
    physdev = GET_DC_PHYSDEV( dc, pPolyBezierTo );
    ret = physdev->funcs->pPolyBezierTo( physdev, lppt, cPoints );

826 827 828
    if(ret)
        dc->cur_pos = lppt[cPoints - 1];

829
    release_dc_ptr( dc );
Alexandre Julliard's avatar
Alexandre Julliard committed
830 831
    return ret;
}
832

833
/***********************************************************************
834
 *      AngleArc (GDI32.@)
835
 */
836
BOOL WINAPI AngleArc(HDC hdc, INT x, INT y, DWORD dwRadius, FLOAT eStartAngle, FLOAT eSweepAngle)
837
{
838
    PHYSDEV physdev;
839 840 841
    BOOL result;
    DC *dc;

842 843
    TRACE( "%p, (%d, %d), %u, %f, %f\n", hdc, x, y, dwRadius, eStartAngle, eSweepAngle );

844
    if( (signed int)dwRadius < 0 )
845 846
	return FALSE;

847
    dc = get_dc_ptr( hdc );
848 849
    if(!dc) return FALSE;

850
    update_dc( dc );
851 852 853
    physdev = GET_DC_PHYSDEV( dc, pAngleArc );
    result = physdev->funcs->pAngleArc( physdev, x, y, dwRadius, eStartAngle, eSweepAngle );

854 855 856 857
    if (result)
    {
        dc->cur_pos.x = GDI_ROUND( x + cos( (eStartAngle + eSweepAngle) * M_PI / 180 ) * dwRadius );
        dc->cur_pos.y = GDI_ROUND( y - sin( (eStartAngle + eSweepAngle) * M_PI / 180 ) * dwRadius );
858
    }
859
    release_dc_ptr( dc );
860
    return result;
861
}
862

863
/***********************************************************************
864
 *      PolyDraw (GDI32.@)
865
 */
866
BOOL WINAPI PolyDraw(HDC hdc, const POINT *lppt, const BYTE *lpbTypes,
867
                       DWORD cCount)
868
{
869
    DC *dc = get_dc_ptr( hdc );
870 871
    PHYSDEV physdev;
    BOOL result;
872

873 874
    TRACE( "%p, %p, %p, %u\n", hdc, lppt, lpbTypes, cCount );

875
    if(!dc) return FALSE;
876

877
    update_dc( dc );
878 879
    physdev = GET_DC_PHYSDEV( dc, pPolyDraw );
    result = physdev->funcs->pPolyDraw( physdev, lppt, lpbTypes, cCount );
880
    if (result && cCount)
881 882
        dc->cur_pos = lppt[cCount - 1];

883
    release_dc_ptr( dc );
884
    return result;
885
}
886

887 888 889 890 891 892 893 894 895 896 897 898 899

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

900 901
    TRACE( "(%d, %d), (%d, %d), %p, %lx\n", nXStart, nYStart, nXEnd, nYEnd, callback, lParam );

902 903 904 905 906 907 908 909 910 911 912 913 914
    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;
915
        for(cnt = 0;cnt < dx; cnt++)
916 917 918 919 920 921 922 923 924 925 926 927 928 929
        {
            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;
930
        for(cnt = 0;cnt < dy; cnt++)
931 932 933 934 935 936 937 938 939 940 941 942 943 944 945
        {
            callback(nXStart,nYStart,lParam);
            if (err > 0)
            {
                nXStart += xadd;
                err += erradd;
            }
            else err += 2*dx;
            nYStart += yadd;
        }
    }
    return TRUE;
}


946
/******************************************************************
947 948
 *
 *   *Very* simple bezier drawing code,
949 950
 *
 *   It uses a recursive algorithm to divide the curve in a series
951
 *   of straight line segments. Not ideal but sufficient for me.
952 953 954 955 956 957
 *   If you are in need for something better look for some incremental
 *   algorithm.
 *
 *   7 July 1998 Rein Klazes
 */

958
 /*
959 960
  * some macro definitions for bezier drawing
  *
961
  * to avoid truncation errors the coordinates are
962 963
  * shifted upwards. When used in drawing they are
  * shifted down again, including correct rounding
964
  * and avoiding floating point arithmetic
965
  * 4 bits should allow 27 bits coordinates which I saw
966
  * somewhere in the win32 doc's
967
  *
968 969 970 971
  */

#define BEZIERSHIFTBITS 4
#define BEZIERSHIFTUP(x)    ((x)<<BEZIERSHIFTBITS)
972
#define BEZIERPIXEL        BEZIERSHIFTUP(1)
973 974 975 976 977 978 979 980
#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)

981
/* calculate Bezier average, in this case the middle
982 983 984 985 986 987
 * correctly rounded...
 * */

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

989 990 991 992 993 994
/**********************************************************
* 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
995
*       returns true if the recursion can be terminated
996 997
*/
static BOOL BezierCheck( int level, POINT *Points)
998
{
999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 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
    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;
    }
}
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 1076 1077 1078 1079 1080 1081 1082 1083 1084 1085 1086 1087 1088 1089 1090 1091
/* 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);
    }
}


1092

1093 1094 1095 1096 1097 1098 1099 1100 1101 1102 1103 1104 1105 1106
/***********************************************************************
 *           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).
1107
 *
1108 1109
 *  RETURNS
 *
Austin English's avatar
Austin English committed
1110
 *  Ptr to an array of POINTs that contain the lines that approximate the
1111 1112
 *  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
1113
 *  but since we can't know in advance how many points we will generate, the
1114 1115 1116 1117 1118 1119 1120 1121
 *  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;

1122 1123
    if (count == 1 || (count - 1) % 3 != 0) {
        ERR("Invalid no. of points %d\n", count);
1124 1125 1126 1127 1128 1129 1130 1131 1132 1133 1134 1135 1136 1137 1138 1139
	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;
}
1140 1141

/******************************************************************************
1142
 *           GdiGradientFill   (GDI32.@)
1143 1144
 */
BOOL WINAPI GdiGradientFill( HDC hdc, TRIVERTEX *vert_array, ULONG nvert,
1145
                             void *grad_array, ULONG ngrad, ULONG mode )
1146
{
1147
    DC *dc;
1148 1149
    PHYSDEV physdev;
    BOOL ret;
1150
    ULONG i;
1151

1152
    TRACE("%p vert_array:%p nvert:%d grad_array:%p ngrad:%d\n", hdc, vert_array, nvert, grad_array, ngrad);
1153

1154 1155 1156 1157 1158
    if (!vert_array || !nvert || !grad_array || !ngrad || mode > GRADIENT_FILL_TRIANGLE)
    {
        SetLastError( ERROR_INVALID_PARAMETER );
        return FALSE;
    }
1159 1160 1161
    for (i = 0; i < ngrad * (mode == GRADIENT_FILL_TRIANGLE ? 3 : 2); i++)
        if (((ULONG *)grad_array)[i] >= nvert) return FALSE;

1162 1163 1164 1165 1166
    if (!(dc = get_dc_ptr( hdc )))
    {
        SetLastError( ERROR_INVALID_PARAMETER );
        return FALSE;
    }
1167 1168 1169 1170 1171
    update_dc( dc );
    physdev = GET_DC_PHYSDEV( dc, pGradientFill );
    ret = physdev->funcs->pGradientFill( physdev, vert_array, nvert, grad_array, ngrad, mode );
    release_dc_ptr( dc );
    return ret;
1172
}
1173 1174 1175 1176 1177 1178 1179 1180 1181 1182

/******************************************************************************
 *           GdiDrawStream   (GDI32.@)
 *
 */
BOOL WINAPI GdiDrawStream( HDC hdc, ULONG in, void * pvin )
{
    FIXME("stub: %p, %d, %p\n", hdc, in, pvin);
    return FALSE;
}