painting.c 41.4 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 128 129 130 131 132 133 134 135 136 137 138 139
{
    BOOL ret = FALSE;
    POINT *pts = HeapAlloc( GetProcessHeap(), 0, sizeof(POINT) * (count + 1) );

    if (pts)
    {
        GetCurrentPositionEx( dev->hdc, &pts[0] );
        memcpy( pts + 1, points, sizeof(POINT) * count );
        ret = PolyBezier( dev->hdc, pts, count + 1 );
        HeapFree( GetProcessHeap(), 0, pts );
    }
    return ret;
}

140
BOOL nulldrv_PolyDraw( PHYSDEV dev, const POINT *points, const BYTE *types, DWORD count )
141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 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
{
    POINT *line_pts = NULL, *bzr_pts = NULL, bzr[4];
    INT i, num_pts, num_bzr_pts, space, size;

    /* 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:
            if((i + 2 < count) && (types[i + 1] == PT_BEZIERTO) &&
               ((types[i + 2] & ~PT_CLOSEFIGURE) == PT_BEZIERTO))
            {
                i += 2;
                break;
            }
        default:
            return FALSE;
        }
    }

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

    GetCurrentPositionEx( dev->hdc, &line_pts[0] );
    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 );
    MoveToEx( dev->hdc, line_pts[num_pts - 1].x, line_pts[num_pts - 1].y, NULL );
    HeapFree( GetProcessHeap(), 0, line_pts );
    return TRUE;
}

213
BOOL nulldrv_PolylineTo( PHYSDEV dev, const POINT *points, INT count )
214 215 216 217 218 219 220 221 222 223 224 225 226 227 228
{
    BOOL ret = FALSE;
    POINT *pts;

    if (!count) return FALSE;
    if ((pts = HeapAlloc( GetProcessHeap(), 0, sizeof(POINT) * (count + 1) )))
    {
        GetCurrentPositionEx( dev->hdc, &pts[0] );
        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
229
/***********************************************************************
230
 *           LineTo    (GDI32.@)
Alexandre Julliard's avatar
Alexandre Julliard committed
231
 */
232
BOOL WINAPI LineTo( HDC hdc, INT x, INT y )
Alexandre Julliard's avatar
Alexandre Julliard committed
233
{
234
    DC * dc = get_dc_ptr( hdc );
235
    BOOL ret;
Alexandre Julliard's avatar
Alexandre Julliard committed
236

237 238
    if(!dc) return FALSE;

239
    update_dc( dc );
240
    if(PATH_IsPathOpen(dc->path))
241
        ret = PATH_LineTo(dc, x, y);
242
    else
243 244 245 246
    {
        PHYSDEV physdev = GET_DC_PHYSDEV( dc, pLineTo );
        ret = physdev->funcs->pLineTo( physdev, x, y );
    }
247
    if(ret) {
248 249
        dc->CursPosX = x;
        dc->CursPosY = y;
250
    }
251
    release_dc_ptr( dc );
252
    return ret;
Alexandre Julliard's avatar
Alexandre Julliard committed
253 254 255 256
}


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

264 265 266
    if(!dc) return FALSE;

    if(pt) {
267 268
        pt->x = dc->CursPosX;
        pt->y = dc->CursPosY;
269
    }
270 271
    dc->CursPosX = x;
    dc->CursPosY = y;
272

273
    if(PATH_IsPathOpen(dc->path)) ret = PATH_MoveTo(dc);
274 275 276 277 278
    else
    {
        PHYSDEV 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
    BOOL ret = FALSE;
292 293
    DC * dc = get_dc_ptr( hdc );

294 295
    if (dc)
    {
296 297
        update_dc( dc );
        if(PATH_IsPathOpen(dc->path))
298
            ret = PATH_Arc(dc, left, top, right, bottom, xstart, ystart, xend, yend,0);
299 300 301 302 303
        else
        {
            PHYSDEV physdev = GET_DC_PHYSDEV( dc, pArc );
            ret = physdev->funcs->pArc( physdev, left, top, right, bottom, xstart, ystart, xend, yend );
        }
304
        release_dc_ptr( dc );
305
    }
306
    return ret;
Alexandre Julliard's avatar
Alexandre Julliard committed
307 308
}

309
/***********************************************************************
310
 *           ArcTo    (GDI32.@)
311
 */
312 313
BOOL WINAPI ArcTo( HDC hdc,
                     INT left,   INT top,
314 315 316
                     INT right,  INT bottom,
                     INT xstart, INT ystart,
                     INT xend,   INT yend )
317
{
318 319 320 321 322 323 324
    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;
325
    BOOL result;
326
    DC * dc = get_dc_ptr( hdc );
327 328
    if(!dc) return FALSE;

329
    update_dc( dc );
330 331
    if(PATH_IsPathOpen(dc->path))
        result = PATH_Arc(dc,left,top,right,bottom,xstart,ystart,xend,yend,-1);
332
    else
333
    {
334 335
        PHYSDEV physdev = GET_DC_PHYSDEV( dc, pArcTo );
        result = physdev->funcs->pArcTo( physdev, left, top, right, bottom, xstart, ystart, xend, yend );
336 337 338 339 340 341
    }
    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));
342
    }
343
    release_dc_ptr( dc );
344 345
    return result;
}
Alexandre Julliard's avatar
Alexandre Julliard committed
346 347 348


/***********************************************************************
349
 *           Pie   (GDI32.@)
Alexandre Julliard's avatar
Alexandre Julliard committed
350
 */
351 352 353
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
354
{
355
    BOOL ret = FALSE;
356
    DC * dc = get_dc_ptr( hdc );
357 358
    if (!dc) return FALSE;

359
    update_dc( dc );
360
    if(PATH_IsPathOpen(dc->path))
361
        ret = PATH_Arc(dc,left,top,right,bottom,xstart,ystart,xend,yend,2);
362 363 364 365 366
    else
    {
        PHYSDEV physdev = GET_DC_PHYSDEV( dc, pPie );
        ret = physdev->funcs->pPie( physdev, left, top, right, bottom, xstart, ystart, xend, yend );
    }
367
    release_dc_ptr( dc );
368
    return ret;
Alexandre Julliard's avatar
Alexandre Julliard committed
369 370 371 372
}


/***********************************************************************
373
 *           Chord    (GDI32.@)
Alexandre Julliard's avatar
Alexandre Julliard committed
374
 */
375 376 377
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
378
{
379
    BOOL ret = FALSE;
380
    DC * dc = get_dc_ptr( hdc );
381 382
    if (!dc) return FALSE;

383
    update_dc( dc );
384
    if(PATH_IsPathOpen(dc->path))
385
	ret = PATH_Arc(dc,left,top,right,bottom,xstart,ystart,xend,yend,1);
386 387 388 389 390
    else
    {
        PHYSDEV physdev = GET_DC_PHYSDEV( dc, pChord );
        ret = physdev->funcs->pChord( physdev, left, top, right, bottom, xstart, ystart, xend, yend );
    }
391
    release_dc_ptr( dc );
392
    return ret;
Alexandre Julliard's avatar
Alexandre Julliard committed
393 394 395 396
}


/***********************************************************************
397
 *           Ellipse    (GDI32.@)
Alexandre Julliard's avatar
Alexandre Julliard committed
398
 */
399 400
BOOL WINAPI Ellipse( HDC hdc, INT left, INT top,
                         INT right, INT bottom )
Alexandre Julliard's avatar
Alexandre Julliard committed
401
{
402
    BOOL ret = FALSE;
403
    DC * dc = get_dc_ptr( hdc );
404 405
    if (!dc) return FALSE;

406
    update_dc( dc );
407
    if(PATH_IsPathOpen(dc->path))
408
	ret = PATH_Ellipse(dc,left,top,right,bottom);
409 410 411 412 413
    else
    {
        PHYSDEV physdev = GET_DC_PHYSDEV( dc, pEllipse );
        ret = physdev->funcs->pEllipse( physdev, left, top, right, bottom );
    }
414

415
    release_dc_ptr( dc );
416
    return ret;
Alexandre Julliard's avatar
Alexandre Julliard committed
417 418 419 420
}


/***********************************************************************
421
 *           Rectangle    (GDI32.@)
Alexandre Julliard's avatar
Alexandre Julliard committed
422
 */
423 424
BOOL WINAPI Rectangle( HDC hdc, INT left, INT top,
                           INT right, INT bottom )
Alexandre Julliard's avatar
Alexandre Julliard committed
425
{
426
    BOOL ret = FALSE;
427 428
    DC * dc = get_dc_ptr( hdc );

429
    if (dc)
430
    {
431 432
        update_dc( dc );
        if(PATH_IsPathOpen(dc->path))
433
            ret = PATH_Rectangle(dc, left, top, right, bottom);
434 435 436 437 438
        else
        {
            PHYSDEV physdev = GET_DC_PHYSDEV( dc, pRectangle );
            ret = physdev->funcs->pRectangle( physdev, left, top, right, bottom );
        }
439
        release_dc_ptr( dc );
440
    }
441
    return ret;
Alexandre Julliard's avatar
Alexandre Julliard committed
442 443 444 445
}


/***********************************************************************
446
 *           RoundRect    (GDI32.@)
Alexandre Julliard's avatar
Alexandre Julliard committed
447
 */
448 449
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
450
{
451
    BOOL ret = FALSE;
452
    DC *dc = get_dc_ptr( hdc );
453

454 455
    if (dc)
    {
456
        update_dc( dc );
457
        if(PATH_IsPathOpen(dc->path))
458
	    ret = PATH_RoundRect(dc,left,top,right,bottom,ell_width,ell_height);
459 460 461 462 463
        else
        {
            PHYSDEV physdev = GET_DC_PHYSDEV( dc, pRoundRect );
            ret = physdev->funcs->pRoundRect( physdev, left, top, right, bottom, ell_width, ell_height );
        }
464
        release_dc_ptr( dc );
465
    }
466
    return ret;
Alexandre Julliard's avatar
Alexandre Julliard committed
467 468 469
}

/***********************************************************************
470
 *           SetPixel    (GDI32.@)
Alexandre Julliard's avatar
Alexandre Julliard committed
471
 */
472
COLORREF WINAPI SetPixel( HDC hdc, INT x, INT y, COLORREF color )
Alexandre Julliard's avatar
Alexandre Julliard committed
473
{
474
    COLORREF ret = 0;
475 476
    DC * dc = get_dc_ptr( hdc );

477 478
    if (dc)
    {
479
        PHYSDEV physdev = GET_DC_PHYSDEV( dc, pSetPixel );
480
        update_dc( dc );
481
        ret = physdev->funcs->pSetPixel( physdev, x, y, color );
482
        release_dc_ptr( dc );
483 484
    }
    return ret;
Alexandre Julliard's avatar
Alexandre Julliard committed
485 486
}

Alexandre Julliard's avatar
Alexandre Julliard committed
487
/***********************************************************************
488
 *           SetPixelV    (GDI32.@)
Alexandre Julliard's avatar
Alexandre Julliard committed
489
 */
490
BOOL WINAPI SetPixelV( HDC hdc, INT x, INT y, COLORREF color )
Alexandre Julliard's avatar
Alexandre Julliard committed
491
{
492
    BOOL ret = FALSE;
493 494
    DC * dc = get_dc_ptr( hdc );

495 496
    if (dc)
    {
497
        PHYSDEV physdev = GET_DC_PHYSDEV( dc, pSetPixel );
498
        update_dc( dc );
499 500
        physdev->funcs->pSetPixel( physdev, x, y, color );
        ret = TRUE;
501
        release_dc_ptr( dc );
502 503
    }
    return ret;
Alexandre Julliard's avatar
Alexandre Julliard committed
504
}
Alexandre Julliard's avatar
Alexandre Julliard committed
505 506

/***********************************************************************
507
 *           GetPixel    (GDI32.@)
Alexandre Julliard's avatar
Alexandre Julliard committed
508
 */
509
COLORREF WINAPI GetPixel( HDC hdc, INT x, INT y )
Alexandre Julliard's avatar
Alexandre Julliard committed
510
{
511
    COLORREF ret = CLR_INVALID;
512
    DC * dc = get_dc_ptr( hdc );
Alexandre Julliard's avatar
Alexandre Julliard committed
513

514 515
    if (dc)
    {
516 517
        update_dc( dc );
        /* FIXME: should this be in the graphics driver? */
518 519
        if (PtVisible( hdc, x, y ))
        {
520 521
            PHYSDEV physdev = GET_DC_PHYSDEV( dc, pGetPixel );
            ret = physdev->funcs->pGetPixel( physdev, x, y );
522
        }
523
        release_dc_ptr( dc );
524 525
    }
    return ret;
Alexandre Julliard's avatar
Alexandre Julliard committed
526 527 528
}


Alexandre Julliard's avatar
Alexandre Julliard committed
529
/******************************************************************************
530
 * ChoosePixelFormat [GDI32.@]
Alexandre Julliard's avatar
Alexandre Julliard committed
531 532 533 534 535 536 537 538 539 540
 * 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
 */
541
INT WINAPI ChoosePixelFormat( HDC hdc, const PIXELFORMATDESCRIPTOR* ppfd )
Alexandre Julliard's avatar
Alexandre Julliard committed
542
{
543
    INT ret = 0;
544
    DC * dc = get_dc_ptr( hdc );
Lionel Ulmer's avatar
Lionel Ulmer committed
545

546
    TRACE("(%p,%p)\n",hdc,ppfd);
547

548 549 550 551 552 553
    if (dc)
    {
        PHYSDEV physdev = GET_DC_PHYSDEV( dc, pChoosePixelFormat );
        ret = physdev->funcs->pChoosePixelFormat( physdev, ppfd );
        release_dc_ptr( dc );
    }
554
    return ret;
Alexandre Julliard's avatar
Alexandre Julliard committed
555 556 557 558
}


/******************************************************************************
559
 * SetPixelFormat [GDI32.@]
Alexandre Julliard's avatar
Alexandre Julliard committed
560 561 562 563 564 565 566
 * 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
 *
567 568 569
 * RETURNS
 *    Success: TRUE
 *    Failure: FALSE
Alexandre Julliard's avatar
Alexandre Julliard committed
570
 */
571 572
BOOL WINAPI SetPixelFormat( HDC hdc, INT iPixelFormat,
                            const PIXELFORMATDESCRIPTOR *ppfd)
Alexandre Julliard's avatar
Alexandre Julliard committed
573
{
574
    INT bRet = FALSE;
575
    DC * dc = get_dc_ptr( hdc );
576

577
    TRACE("(%p,%d,%p)\n",hdc,iPixelFormat,ppfd);
578

579 580 581 582 583 584 585
    if (dc)
    {
        PHYSDEV physdev = GET_DC_PHYSDEV( dc, pSetPixelFormat );
        update_dc( dc );
        bRet = physdev->funcs->pSetPixelFormat( physdev, iPixelFormat, ppfd );
        release_dc_ptr( dc );
    }
586
    return bRet;
Alexandre Julliard's avatar
Alexandre Julliard committed
587 588 589 590
}


/******************************************************************************
591
 * GetPixelFormat [GDI32.@]
Alexandre Julliard's avatar
Alexandre Julliard committed
592 593 594 595 596 597 598 599 600
 * 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
 */
601
INT WINAPI GetPixelFormat( HDC hdc )
Alexandre Julliard's avatar
Alexandre Julliard committed
602
{
603
    INT ret = 0;
604
    DC * dc = get_dc_ptr( hdc );
605

606
    TRACE("(%p)\n",hdc);
607

608 609 610 611 612 613 614
    if (dc)
    {
        PHYSDEV physdev = GET_DC_PHYSDEV( dc, pGetPixelFormat );
        update_dc( dc );
        ret = physdev->funcs->pGetPixelFormat( physdev );
        release_dc_ptr( dc );
    }
615
    return ret;
Alexandre Julliard's avatar
Alexandre Julliard committed
616 617 618 619
}


/******************************************************************************
620
 * DescribePixelFormat [GDI32.@]
Alexandre Julliard's avatar
Alexandre Julliard committed
621 622 623 624 625 626 627 628 629 630 631 632
 * 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
 */
633
INT WINAPI DescribePixelFormat( HDC hdc, INT iPixelFormat, UINT nBytes,
Alexandre Julliard's avatar
Alexandre Julliard committed
634 635
                                LPPIXELFORMATDESCRIPTOR ppfd )
{
636
    INT ret = 0;
637
    DC * dc = get_dc_ptr( hdc );
638

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

641
    if (dc)
642
    {
643 644 645 646
        PHYSDEV physdev = GET_DC_PHYSDEV( dc, pDescribePixelFormat );
        update_dc( dc );
        ret = physdev->funcs->pDescribePixelFormat( physdev, iPixelFormat, nBytes, ppfd );
        release_dc_ptr( dc );
647 648
    }
    return ret;
Alexandre Julliard's avatar
Alexandre Julliard committed
649 650 651 652
}


/******************************************************************************
653
 * SwapBuffers [GDI32.@]
Alexandre Julliard's avatar
Alexandre Julliard committed
654 655 656 657 658
 * Exchanges front and back buffers of window
 *
 * PARAMS
 *    hdc [I] Device context whose buffers get swapped
 *
659 660 661
 * RETURNS
 *    Success: TRUE
 *    Failure: FALSE
Alexandre Julliard's avatar
Alexandre Julliard committed
662
 */
663
BOOL WINAPI SwapBuffers( HDC hdc )
Alexandre Julliard's avatar
Alexandre Julliard committed
664
{
665
    INT bRet = FALSE;
666
    DC * dc = get_dc_ptr( hdc );
Lionel Ulmer's avatar
Lionel Ulmer committed
667

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

670
    if (dc)
671
    {
672 673 674 675
        PHYSDEV physdev = GET_DC_PHYSDEV( dc, pSwapBuffers );
        update_dc( dc );
        bRet = physdev->funcs->pSwapBuffers( physdev );
        release_dc_ptr( dc );
676 677
    }
    return bRet;
Alexandre Julliard's avatar
Alexandre Julliard committed
678 679 680
}


Alexandre Julliard's avatar
Alexandre Julliard committed
681
/***********************************************************************
682
 *           PaintRgn    (GDI32.@)
Alexandre Julliard's avatar
Alexandre Julliard committed
683
 */
684
BOOL WINAPI PaintRgn( HDC hdc, HRGN hrgn )
Alexandre Julliard's avatar
Alexandre Julliard committed
685
{
686
    BOOL ret = FALSE;
687 688
    DC * dc = get_dc_ptr( hdc );

689 690
    if (dc)
    {
691
        PHYSDEV physdev = GET_DC_PHYSDEV( dc, pPaintRgn );
692
        update_dc( dc );
693
        ret = physdev->funcs->pPaintRgn( physdev, hrgn );
694
        release_dc_ptr( dc );
695 696
    }
    return ret;
Alexandre Julliard's avatar
Alexandre Julliard committed
697 698 699 700
}


/***********************************************************************
701
 *           FillRgn    (GDI32.@)
Alexandre Julliard's avatar
Alexandre Julliard committed
702
 */
703
BOOL WINAPI FillRgn( HDC hdc, HRGN hrgn, HBRUSH hbrush )
Alexandre Julliard's avatar
Alexandre Julliard committed
704
{
705
    BOOL retval = FALSE;
706
    DC * dc = get_dc_ptr( hdc );
707

708
    if (dc)
709
    {
710
        PHYSDEV physdev = GET_DC_PHYSDEV( dc, pFillRgn );
711
        update_dc( dc );
712 713
        retval = physdev->funcs->pFillRgn( physdev, hrgn, hbrush );
        release_dc_ptr( dc );
714
    }
Alexandre Julliard's avatar
Alexandre Julliard committed
715 716 717 718 719
    return retval;
}


/***********************************************************************
720
 *           FrameRgn     (GDI32.@)
Alexandre Julliard's avatar
Alexandre Julliard committed
721
 */
722 723
BOOL WINAPI FrameRgn( HDC hdc, HRGN hrgn, HBRUSH hbrush,
                          INT nWidth, INT nHeight )
Alexandre Julliard's avatar
Alexandre Julliard committed
724
{
725
    BOOL ret = FALSE;
726
    DC *dc = get_dc_ptr( hdc );
727

728
    if (dc)
729
    {
730
        PHYSDEV physdev = GET_DC_PHYSDEV( dc, pFrameRgn );
731
        update_dc( dc );
732 733
        ret = physdev->funcs->pFrameRgn( physdev, hrgn, hbrush, nWidth, nHeight );
        release_dc_ptr( dc );
734 735
    }
    return ret;
Alexandre Julliard's avatar
Alexandre Julliard committed
736 737 738 739
}


/***********************************************************************
740
 *           InvertRgn    (GDI32.@)
Alexandre Julliard's avatar
Alexandre Julliard committed
741
 */
742
BOOL WINAPI InvertRgn( HDC hdc, HRGN hrgn )
Alexandre Julliard's avatar
Alexandre Julliard committed
743
{
744
    BOOL ret = FALSE;
745
    DC *dc = get_dc_ptr( hdc );
746

747
    if (dc)
748
    {
749
        PHYSDEV physdev = GET_DC_PHYSDEV( dc, pInvertRgn );
750
        update_dc( dc );
751 752
        ret = physdev->funcs->pInvertRgn( physdev, hrgn );
        release_dc_ptr( dc );
753
    }
754
    return ret;
Alexandre Julliard's avatar
Alexandre Julliard committed
755 756 757 758
}


/**********************************************************************
759
 *          Polyline   (GDI32.@)
Alexandre Julliard's avatar
Alexandre Julliard committed
760
 */
761
BOOL WINAPI Polyline( HDC hdc, const POINT* pt, INT count )
Alexandre Julliard's avatar
Alexandre Julliard committed
762
{
763
    BOOL ret = FALSE;
764 765
    DC * dc = get_dc_ptr( hdc );

766 767
    if (dc)
    {
768
        update_dc( dc );
769
        if (PATH_IsPathOpen(dc->path)) ret = PATH_Polyline(dc, pt, count);
770 771 772 773 774
        else
        {
            PHYSDEV physdev = GET_DC_PHYSDEV( dc, pPolyline );
            ret = physdev->funcs->pPolyline( physdev, pt, count );
        }
775
        release_dc_ptr( dc );
776 777
    }
    return ret;
Alexandre Julliard's avatar
Alexandre Julliard committed
778 779
}

780
/**********************************************************************
781
 *          PolylineTo   (GDI32.@)
782
 */
783
BOOL WINAPI PolylineTo( HDC hdc, const POINT* pt, DWORD cCount )
784
{
785
    DC * dc = get_dc_ptr( hdc );
786
    BOOL ret = FALSE;
Huw D M Davies's avatar
Huw D M Davies committed
787

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

790 791 792
    update_dc( dc );
    if(PATH_IsPathOpen(dc->path)) ret = PATH_PolylineTo(dc, pt, cCount);
    else
793
    {
794 795
        PHYSDEV physdev = GET_DC_PHYSDEV( dc, pPolylineTo );
        ret = physdev->funcs->pPolylineTo( physdev, pt, cCount );
796
    }
797
    if (ret && cCount)
798
    {
799 800
        dc->CursPosX = pt[cCount-1].x;
	dc->CursPosY = pt[cCount-1].y;
801
    }
802
    release_dc_ptr( dc );
803
    return ret;
804
}
Alexandre Julliard's avatar
Alexandre Julliard committed
805 806 807


/**********************************************************************
808
 *          Polygon  (GDI32.@)
Alexandre Julliard's avatar
Alexandre Julliard committed
809
 */
810
BOOL WINAPI Polygon( HDC hdc, const POINT* pt, INT count )
Alexandre Julliard's avatar
Alexandre Julliard committed
811
{
812
    BOOL ret = FALSE;
813 814
    DC * dc = get_dc_ptr( hdc );

815 816
    if (dc)
    {
817
        update_dc( dc );
818
        if (PATH_IsPathOpen(dc->path)) ret = PATH_Polygon(dc, pt, count);
819 820 821 822 823
        else
        {
            PHYSDEV physdev = GET_DC_PHYSDEV( dc, pPolygon );
            ret = physdev->funcs->pPolygon( physdev, pt, count );
        }
824
        release_dc_ptr( dc );
825
    }
826
    return ret;
Alexandre Julliard's avatar
Alexandre Julliard committed
827 828 829 830
}


/**********************************************************************
831
 *          PolyPolygon  (GDI32.@)
Alexandre Julliard's avatar
Alexandre Julliard committed
832
 */
833 834
BOOL WINAPI PolyPolygon( HDC hdc, const POINT* pt, const INT* counts,
                             UINT polygons )
Alexandre Julliard's avatar
Alexandre Julliard committed
835
{
836
    BOOL ret = FALSE;
837 838
    DC * dc = get_dc_ptr( hdc );

839 840
    if (dc)
    {
841
        update_dc( dc );
842
        if (PATH_IsPathOpen(dc->path)) ret = PATH_PolyPolygon(dc, pt, counts, polygons);
843 844 845 846 847
        else
        {
            PHYSDEV physdev = GET_DC_PHYSDEV( dc, pPolyPolygon );
            ret = physdev->funcs->pPolyPolygon( physdev, pt, counts, polygons );
        }
848
        release_dc_ptr( dc );
849 850
    }
    return ret;
Alexandre Julliard's avatar
Alexandre Julliard committed
851 852
}

Alexandre Julliard's avatar
Alexandre Julliard committed
853
/**********************************************************************
854
 *          PolyPolyline  (GDI32.@)
Alexandre Julliard's avatar
Alexandre Julliard committed
855
 */
856
BOOL WINAPI PolyPolyline( HDC hdc, const POINT* pt, const DWORD* counts,
857
                            DWORD polylines )
Alexandre Julliard's avatar
Alexandre Julliard committed
858
{
859
    BOOL ret = FALSE;
860 861
    DC * dc = get_dc_ptr( hdc );

862 863
    if (dc)
    {
864
        update_dc( dc );
865
        if (PATH_IsPathOpen(dc->path)) ret = PATH_PolyPolyline(dc, pt, counts, polylines);
866 867 868 869 870
        else
        {
            PHYSDEV physdev = GET_DC_PHYSDEV( dc, pPolyPolyline );
            ret = physdev->funcs->pPolyPolyline( physdev, pt, counts, polylines );
        }
871
        release_dc_ptr( dc );
872
    }
873
    return ret;
Alexandre Julliard's avatar
Alexandre Julliard committed
874 875
}

Alexandre Julliard's avatar
Alexandre Julliard committed
876
/**********************************************************************
877
 *          ExtFloodFill   (GDI32.@)
Alexandre Julliard's avatar
Alexandre Julliard committed
878
 */
879 880
BOOL WINAPI ExtFloodFill( HDC hdc, INT x, INT y, COLORREF color,
                              UINT fillType )
Alexandre Julliard's avatar
Alexandre Julliard committed
881
{
882
    BOOL ret = FALSE;
883 884
    DC * dc = get_dc_ptr( hdc );

885 886
    if (dc)
    {
887 888
        PHYSDEV physdev = GET_DC_PHYSDEV( dc, pExtFloodFill );

889
        update_dc( dc );
890
        ret = physdev->funcs->pExtFloodFill( physdev, x, y, color, fillType );
891
        release_dc_ptr( dc );
892
    }
893
    return ret;
Alexandre Julliard's avatar
Alexandre Julliard committed
894 895 896 897
}


/**********************************************************************
898
 *          FloodFill   (GDI32.@)
Alexandre Julliard's avatar
Alexandre Julliard committed
899
 */
900
BOOL WINAPI FloodFill( HDC hdc, INT x, INT y, COLORREF color )
Alexandre Julliard's avatar
Alexandre Julliard committed
901
{
902
    return ExtFloodFill( hdc, x, y, color, FLOODFILLBORDER );
Alexandre Julliard's avatar
Alexandre Julliard committed
903 904 905
}


Alexandre Julliard's avatar
Alexandre Julliard committed
906
/******************************************************************************
907
 * PolyBezier [GDI32.@]
Alexandre Julliard's avatar
Alexandre Julliard committed
908 909 910 911 912 913 914
 * 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
 *
915 916 917
 * RETURNS
 *    Success: TRUE
 *    Failure: FALSE
Alexandre Julliard's avatar
Alexandre Julliard committed
918
 */
919
BOOL WINAPI PolyBezier( HDC hdc, const POINT* lppt, DWORD cPoints )
Alexandre Julliard's avatar
Alexandre Julliard committed
920
{
921
    BOOL ret = FALSE;
922 923 924 925
    DC * dc;

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

927
    dc = get_dc_ptr( hdc );
928 929
    if(!dc) return FALSE;

930 931 932
    update_dc( dc );
    if(PATH_IsPathOpen(dc->path)) ret = PATH_PolyBezier(dc, lppt, cPoints);
    else
933
    {
934 935
        PHYSDEV physdev = GET_DC_PHYSDEV( dc, pPolyBezier );
        ret = physdev->funcs->pPolyBezier( physdev, lppt, cPoints );
936
    }
937
    release_dc_ptr( dc );
938 939 940
    return ret;
}

Alexandre Julliard's avatar
Alexandre Julliard committed
941
/******************************************************************************
942
 * PolyBezierTo [GDI32.@]
Alexandre Julliard's avatar
Alexandre Julliard committed
943 944 945 946 947 948 949
 * 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
 *
950 951 952
 * RETURNS
 *    Success: TRUE
 *    Failure: FALSE
Alexandre Julliard's avatar
Alexandre Julliard committed
953
 */
954
BOOL WINAPI PolyBezierTo( HDC hdc, const POINT* lppt, DWORD cPoints )
Alexandre Julliard's avatar
Alexandre Julliard committed
955
{
956
    DC * dc;
957
    BOOL ret = FALSE;
958

959 960 961
    /* cbPoints must be 3 * n (where n>=1) */
    if (!cPoints || (cPoints % 3) != 0) return FALSE;

962
    dc = get_dc_ptr( hdc );
Alexandre Julliard's avatar
Alexandre Julliard committed
963
    if(!dc) return FALSE;
964

965 966 967
    update_dc( dc );
    if(PATH_IsPathOpen(dc->path)) ret = PATH_PolyBezierTo(dc, lppt, cPoints);
    else
968
    {
969 970
        PHYSDEV physdev = GET_DC_PHYSDEV( dc, pPolyBezierTo );
        ret = physdev->funcs->pPolyBezierTo( physdev, lppt, cPoints );
971
    }
972
    if(ret) {
973 974
        dc->CursPosX = lppt[cPoints-1].x;
        dc->CursPosY = lppt[cPoints-1].y;
975
    }
976
    release_dc_ptr( dc );
Alexandre Julliard's avatar
Alexandre Julliard committed
977 978
    return ret;
}
979

980
/***********************************************************************
981
 *      AngleArc (GDI32.@)
982
 */
983
BOOL WINAPI AngleArc(HDC hdc, INT x, INT y, DWORD dwRadius, FLOAT eStartAngle, FLOAT eSweepAngle)
984
{
985
    INT x1,y1,x2,y2, arcdir;
986 987 988
    BOOL result;
    DC *dc;

989
    if( (signed int)dwRadius < 0 )
990 991
	return FALSE;

992
    dc = get_dc_ptr( hdc );
993 994
    if(!dc) return FALSE;

995
    /* Calculate the end point */
996 997
    x2 = GDI_ROUND( x + cos((eStartAngle+eSweepAngle)*M_PI/180) * dwRadius );
    y2 = GDI_ROUND( y - sin((eStartAngle+eSweepAngle)*M_PI/180) * dwRadius );
998

999 1000
    update_dc( dc );
    if(!PATH_IsPathOpen(dc->path))
1001
    {
1002 1003
        PHYSDEV physdev = GET_DC_PHYSDEV( dc, pAngleArc );
        result = physdev->funcs->pAngleArc( physdev, x, y, dwRadius, eStartAngle, eSweepAngle );
1004
    }
1005
    else { /* do it using ArcTo */
1006 1007
        x1 = GDI_ROUND( x + cos(eStartAngle*M_PI/180) * dwRadius );
        y1 = GDI_ROUND( y - sin(eStartAngle*M_PI/180) * dwRadius );
1008 1009 1010 1011 1012 1013 1014 1015 1016 1017

        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;
    }
1018
    release_dc_ptr( dc );
1019
    return result;
1020
}
1021

1022
/***********************************************************************
1023
 *      PolyDraw (GDI32.@)
1024
 */
1025
BOOL WINAPI PolyDraw(HDC hdc, const POINT *lppt, const BYTE *lpbTypes,
1026
                       DWORD cCount)
1027
{
1028
    DC *dc = get_dc_ptr( hdc );
1029
    BOOL result = FALSE;
1030

1031
    if(!dc) return FALSE;
1032

1033 1034 1035
    update_dc( dc );
    if( PATH_IsPathOpen( dc->path ) ) result = PATH_PolyDraw(dc, lppt, lpbTypes, cCount);
    else
1036
    {
1037 1038
        PHYSDEV physdev = GET_DC_PHYSDEV( dc, pPolyDraw );
        result = physdev->funcs->pPolyDraw( physdev, lppt, lpbTypes, cCount );
1039 1040
    }
    release_dc_ptr( dc );
1041
    return result;
1042
}
1043

1044 1045 1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068 1069

/**********************************************************************
 *           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;
1070
        for(cnt = 0;cnt < dx; cnt++)
1071 1072 1073 1074 1075 1076 1077 1078 1079 1080 1081 1082 1083 1084
        {
            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;
1085
        for(cnt = 0;cnt < dy; cnt++)
1086 1087 1088 1089 1090 1091 1092 1093 1094 1095 1096 1097 1098 1099 1100
        {
            callback(nXStart,nYStart,lParam);
            if (err > 0)
            {
                nXStart += xadd;
                err += erradd;
            }
            else err += 2*dx;
            nYStart += yadd;
        }
    }
    return TRUE;
}


1101
/******************************************************************
1102 1103
 *
 *   *Very* simple bezier drawing code,
1104 1105
 *
 *   It uses a recursive algorithm to divide the curve in a series
1106
 *   of straight line segments. Not ideal but sufficient for me.
1107 1108 1109 1110 1111 1112
 *   If you are in need for something better look for some incremental
 *   algorithm.
 *
 *   7 July 1998 Rein Klazes
 */

1113
 /*
1114 1115
  * some macro definitions for bezier drawing
  *
1116
  * to avoid truncation errors the coordinates are
1117 1118
  * shifted upwards. When used in drawing they are
  * shifted down again, including correct rounding
1119
  * and avoiding floating point arithmetic
1120
  * 4 bits should allow 27 bits coordinates which I saw
1121
  * somewhere in the win32 doc's
1122
  *
1123 1124 1125 1126
  */

#define BEZIERSHIFTBITS 4
#define BEZIERSHIFTUP(x)    ((x)<<BEZIERSHIFTBITS)
1127
#define BEZIERPIXEL        BEZIERSHIFTUP(1)
1128 1129 1130 1131 1132 1133 1134 1135
#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)

1136
/* calculate Bezier average, in this case the middle
1137 1138 1139 1140 1141 1142
 * correctly rounded...
 * */

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

1144 1145 1146 1147 1148 1149
/**********************************************************
* 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
1150
*       returns true if the recursion can be terminated
1151 1152
*/
static BOOL BezierCheck( int level, POINT *Points)
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 1187 1188 1189 1190 1191 1192 1193 1194 1195 1196 1197 1198 1199 1200 1201 1202 1203 1204
    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;
    }
}
1205

1206 1207 1208 1209 1210 1211 1212 1213 1214 1215 1216 1217 1218 1219 1220 1221 1222 1223 1224 1225 1226 1227 1228 1229 1230 1231 1232 1233 1234 1235 1236 1237 1238 1239 1240 1241 1242 1243 1244 1245 1246
/* 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);
    }
}


1247

1248 1249 1250 1251 1252 1253 1254 1255 1256 1257 1258 1259 1260 1261
/***********************************************************************
 *           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).
1262
 *
1263 1264
 *  RETURNS
 *
Austin English's avatar
Austin English committed
1265
 *  Ptr to an array of POINTs that contain the lines that approximate the
1266 1267
 *  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
1268
 *  but since we can't know in advance how many points we will generate, the
1269 1270 1271 1272 1273 1274 1275 1276
 *  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;

1277 1278
    if (count == 1 || (count - 1) % 3 != 0) {
        ERR("Invalid no. of points %d\n", count);
1279 1280 1281 1282 1283 1284 1285 1286 1287 1288 1289 1290 1291 1292 1293 1294
	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;
}
1295 1296

/******************************************************************************
1297
 *           GdiGradientFill   (GDI32.@)
1298 1299
 *
 *  FIXME: we don't support the Alpha channel properly
1300 1301 1302 1303
 */
BOOL WINAPI GdiGradientFill( HDC hdc, TRIVERTEX *vert_array, ULONG nvert,
                          void * grad_array, ULONG ngrad, ULONG mode )
{
1304
  unsigned int i;
1305

1306 1307
  TRACE("vert_array:%p nvert:%d grad_array:%p ngrad:%d\n",
        vert_array, nvert, grad_array, ngrad);
1308 1309 1310 1311 1312 1313 1314 1315 1316 1317 1318

  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;
1319
          int x, dx;
1320 1321 1322 1323 1324 1325 1326 1327 1328
          if (v1->x > v2->x)
            {
              TRIVERTEX *t = v2;
              v2 = v1;
              v1 = t;
            }
          dx = v2->x - v1->x;
          for (x = 0; x < dx; x++)
            {
1329 1330 1331 1332
              POINT pts[2];
              HPEN hPen, hOldPen;
              
              hPen = CreatePen( PS_SOLID, 1, RGB(
1333 1334 1335
                  (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));
1336
              hOldPen = SelectObject( hdc, hPen );
1337
              pts[0].x = v1->x + x;
1338
              pts[0].y = y1;
1339
              pts[1].x = v1->x + x;
1340 1341 1342
              pts[1].y = y2;
              Polyline( hdc, &pts[0], 2 );
              DeleteObject( SelectObject(hdc, hOldPen ) );
1343 1344 1345 1346 1347 1348 1349 1350 1351 1352 1353
            }
        }
      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;
1354
          int y, dy;
1355 1356 1357 1358 1359 1360 1361 1362 1363
          if (v1->y > v2->y)
            {
              TRIVERTEX *t = v2;
              v2 = v1;
              v1 = t;
            }
          dy = v2->y - v1->y;
          for (y = 0; y < dy; y++)
            {
1364 1365 1366 1367
              POINT pts[2];
              HPEN hPen, hOldPen;
              
              hPen = CreatePen( PS_SOLID, 1, RGB(
1368 1369 1370
                  (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));
1371 1372
              hOldPen = SelectObject( hdc, hPen );
              pts[0].x = x1;
1373
              pts[0].y = v1->y + y;
1374
              pts[1].x = x2;
1375
              pts[1].y = v1->y + y;
1376 1377
              Polyline( hdc, &pts[0], 2 );
              DeleteObject( SelectObject(hdc, hOldPen ) );
1378 1379 1380 1381 1382 1383 1384 1385 1386 1387 1388 1389 1390 1391 1392 1393 1394 1395 1396 1397 1398 1399 1400 1401 1402 1403 1404 1405 1406 1407 1408 1409 1410 1411 1412 1413 1414 1415 1416 1417 1418 1419 1420 1421 1422 1423 1424 1425 1426 1427 1428 1429 1430 1431 1432 1433 1434 1435 1436 1437 1438 1439 1440 1441
            }
        }
      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;
1442 1443 1444 1445
  }

  return TRUE;
}
1446 1447 1448 1449 1450 1451 1452 1453 1454 1455

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