msxml3: Release IDispatchEx dynamic data properly.
[wine] / dlls / gdi32 / path.c
1 /*
2  * Graphics paths (BeginPath, EndPath etc.)
3  *
4  * Copyright 1997, 1998 Martin Boehme
5  *                 1999 Huw D M Davies
6  * Copyright 2005 Dmitry Timoshkov
7  * Copyright 2011 Alexandre Julliard
8  *
9  * This library is free software; you can redistribute it and/or
10  * modify it under the terms of the GNU Lesser General Public
11  * License as published by the Free Software Foundation; either
12  * version 2.1 of the License, or (at your option) any later version.
13  *
14  * This library is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
17  * Lesser General Public License for more details.
18  *
19  * You should have received a copy of the GNU Lesser General Public
20  * License along with this library; if not, write to the Free Software
21  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
22  */
23
24 #include "config.h"
25 #include "wine/port.h"
26
27 #include <assert.h>
28 #include <math.h>
29 #include <stdarg.h>
30 #include <string.h>
31 #include <stdlib.h>
32 #if defined(HAVE_FLOAT_H)
33 #include <float.h>
34 #endif
35
36 #include "windef.h"
37 #include "winbase.h"
38 #include "wingdi.h"
39 #include "winerror.h"
40
41 #include "gdi_private.h"
42 #include "wine/debug.h"
43
44 WINE_DEFAULT_DEBUG_CHANNEL(gdi);
45
46 /* Notes on the implementation
47  *
48  * The implementation is based on dynamically resizable arrays of points and
49  * flags. I dithered for a bit before deciding on this implementation, and
50  * I had even done a bit of work on a linked list version before switching
51  * to arrays. It's a bit of a tradeoff. When you use linked lists, the
52  * implementation of FlattenPath is easier, because you can rip the
53  * PT_BEZIERTO entries out of the middle of the list and link the
54  * corresponding PT_LINETO entries in. However, when you use arrays,
55  * PathToRegion becomes easier, since you can essentially just pass your array
56  * of points to CreatePolyPolygonRgn. Also, if I'd used linked lists, I would
57  * have had the extra effort of creating a chunk-based allocation scheme
58  * in order to use memory effectively. That's why I finally decided to use
59  * arrays. Note by the way that the array based implementation has the same
60  * linear time complexity that linked lists would have since the arrays grow
61  * exponentially.
62  *
63  * The points are stored in the path in device coordinates. This is
64  * consistent with the way Windows does things (for instance, see the Win32
65  * SDK documentation for GetPath).
66  *
67  * The word "stroke" appears in several places (e.g. in the flag
68  * GdiPath.newStroke). A stroke consists of a PT_MOVETO followed by one or
69  * more PT_LINETOs or PT_BEZIERTOs, up to, but not including, the next
70  * PT_MOVETO. Note that this is not the same as the definition of a figure;
71  * a figure can contain several strokes.
72  *
73  * Martin Boehme
74  */
75
76 #define NUM_ENTRIES_INITIAL 16  /* Initial size of points / flags arrays  */
77 #define GROW_FACTOR_NUMER    2  /* Numerator of grow factor for the array */
78 #define GROW_FACTOR_DENOM    1  /* Denominator of grow factor             */
79
80 /* A floating point version of the POINT structure */
81 typedef struct tagFLOAT_POINT
82 {
83    double x, y;
84 } FLOAT_POINT;
85
86
87 struct path_physdev
88 {
89     struct gdi_physdev dev;
90     GdiPath           *path;
91 };
92
93 static inline struct path_physdev *get_path_physdev( PHYSDEV dev )
94 {
95     return (struct path_physdev *)dev;
96 }
97
98 static inline void pop_path_driver( DC *dc )
99 {
100     PHYSDEV dev = pop_dc_driver( &dc->physDev );
101     assert( dev->funcs == &path_driver );
102     HeapFree( GetProcessHeap(), 0, dev );
103 }
104
105
106 /* Performs a world-to-viewport transformation on the specified point (which
107  * is in floating point format).
108  */
109 static inline void INTERNAL_LPTODP_FLOAT( HDC hdc, FLOAT_POINT *point, int count )
110 {
111     DC *dc = get_dc_ptr( hdc );
112     double x, y;
113
114     while (count--)
115     {
116         x = point->x;
117         y = point->y;
118         point->x = x * dc->xformWorld2Vport.eM11 + y * dc->xformWorld2Vport.eM21 + dc->xformWorld2Vport.eDx;
119         point->y = x * dc->xformWorld2Vport.eM12 + y * dc->xformWorld2Vport.eM22 + dc->xformWorld2Vport.eDy;
120         point++;
121     }
122     release_dc_ptr( dc );
123 }
124
125 static inline INT int_from_fixed(FIXED f)
126 {
127     return (f.fract >= 0x8000) ? (f.value + 1) : f.value;
128 }
129
130
131 /* PATH_EmptyPath
132  *
133  * Removes all entries from the path and sets the path state to PATH_Null.
134  */
135 static void PATH_EmptyPath(GdiPath *pPath)
136 {
137     pPath->state=PATH_Null;
138     pPath->numEntriesUsed=0;
139 }
140
141 /* PATH_ReserveEntries
142  *
143  * Ensures that at least "numEntries" entries (for points and flags) have
144  * been allocated; allocates larger arrays and copies the existing entries
145  * to those arrays, if necessary. Returns TRUE if successful, else FALSE.
146  */
147 static BOOL PATH_ReserveEntries(GdiPath *pPath, INT numEntries)
148 {
149     INT   numEntriesToAllocate;
150     POINT *pPointsNew;
151     BYTE    *pFlagsNew;
152
153     assert(numEntries>=0);
154
155     /* Do we have to allocate more memory? */
156     if(numEntries > pPath->numEntriesAllocated)
157     {
158         /* Find number of entries to allocate. We let the size of the array
159          * grow exponentially, since that will guarantee linear time
160          * complexity. */
161         if(pPath->numEntriesAllocated)
162         {
163             numEntriesToAllocate=pPath->numEntriesAllocated;
164             while(numEntriesToAllocate<numEntries)
165                 numEntriesToAllocate=numEntriesToAllocate*GROW_FACTOR_NUMER/
166                     GROW_FACTOR_DENOM;
167         }
168         else
169             numEntriesToAllocate=numEntries;
170
171         /* Allocate new arrays */
172         pPointsNew=HeapAlloc( GetProcessHeap(), 0, numEntriesToAllocate * sizeof(POINT) );
173         if(!pPointsNew)
174             return FALSE;
175         pFlagsNew=HeapAlloc( GetProcessHeap(), 0, numEntriesToAllocate * sizeof(BYTE) );
176         if(!pFlagsNew)
177         {
178             HeapFree( GetProcessHeap(), 0, pPointsNew );
179             return FALSE;
180         }
181
182         /* Copy old arrays to new arrays and discard old arrays */
183         if(pPath->pPoints)
184         {
185             assert(pPath->pFlags);
186
187             memcpy(pPointsNew, pPath->pPoints,
188                    sizeof(POINT)*pPath->numEntriesUsed);
189             memcpy(pFlagsNew, pPath->pFlags,
190                    sizeof(BYTE)*pPath->numEntriesUsed);
191
192             HeapFree( GetProcessHeap(), 0, pPath->pPoints );
193             HeapFree( GetProcessHeap(), 0, pPath->pFlags );
194         }
195         pPath->pPoints=pPointsNew;
196         pPath->pFlags=pFlagsNew;
197         pPath->numEntriesAllocated=numEntriesToAllocate;
198     }
199
200     return TRUE;
201 }
202
203 /* PATH_AddEntry
204  *
205  * Adds an entry to the path. For "flags", pass either PT_MOVETO, PT_LINETO
206  * or PT_BEZIERTO, optionally ORed with PT_CLOSEFIGURE. Returns TRUE if
207  * successful, FALSE otherwise (e.g. if not enough memory was available).
208  */
209 static BOOL PATH_AddEntry(GdiPath *pPath, const POINT *pPoint, BYTE flags)
210 {
211     /* FIXME: If newStroke is true, perhaps we want to check that we're
212      * getting a PT_MOVETO
213      */
214     TRACE("(%d,%d) - %d\n", pPoint->x, pPoint->y, flags);
215
216     /* Check that path is open */
217     if(pPath->state!=PATH_Open)
218         return FALSE;
219
220     /* Reserve enough memory for an extra path entry */
221     if(!PATH_ReserveEntries(pPath, pPath->numEntriesUsed+1))
222         return FALSE;
223
224     /* Store information in path entry */
225     pPath->pPoints[pPath->numEntriesUsed]=*pPoint;
226     pPath->pFlags[pPath->numEntriesUsed]=flags;
227
228     pPath->numEntriesUsed++;
229
230     return TRUE;
231 }
232
233 /* add a number of points, converting them to device coords */
234 /* return a pointer to the first type byte so it can be fixed up if necessary */
235 static BYTE *add_log_points( struct path_physdev *physdev, const POINT *points, DWORD count, BYTE type )
236 {
237     BYTE *ret;
238     GdiPath *path = physdev->path;
239
240     if (!PATH_ReserveEntries( path, path->numEntriesUsed + count )) return NULL;
241
242     ret = &path->pFlags[path->numEntriesUsed];
243     memcpy( &path->pPoints[path->numEntriesUsed], points, count * sizeof(*points) );
244     LPtoDP( physdev->dev.hdc, &path->pPoints[path->numEntriesUsed], count );
245     memset( ret, type, count );
246     path->numEntriesUsed += count;
247     return ret;
248 }
249
250 /* start a new path stroke if necessary */
251 static BOOL start_new_stroke( struct path_physdev *physdev )
252 {
253     POINT pos;
254     GdiPath *path = physdev->path;
255
256     if (!path->newStroke && path->numEntriesUsed &&
257         !(path->pFlags[path->numEntriesUsed - 1] & PT_CLOSEFIGURE))
258         return TRUE;
259
260     path->newStroke = FALSE;
261     GetCurrentPositionEx( physdev->dev.hdc, &pos );
262     return add_log_points( physdev, &pos, 1, PT_MOVETO ) != NULL;
263 }
264
265 /* PATH_AssignGdiPath
266  *
267  * Copies the GdiPath structure "pPathSrc" to "pPathDest". A deep copy is
268  * performed, i.e. the contents of the pPoints and pFlags arrays are copied,
269  * not just the pointers. Since this means that the arrays in pPathDest may
270  * need to be resized, pPathDest should have been initialized using
271  * PATH_InitGdiPath (in C++, this function would be an assignment operator,
272  * not a copy constructor).
273  * Returns TRUE if successful, else FALSE.
274  */
275 static BOOL PATH_AssignGdiPath(GdiPath *pPathDest, const GdiPath *pPathSrc)
276 {
277    /* Make sure destination arrays are big enough */
278    if(!PATH_ReserveEntries(pPathDest, pPathSrc->numEntriesUsed))
279       return FALSE;
280
281    /* Perform the copy operation */
282    memcpy(pPathDest->pPoints, pPathSrc->pPoints,
283       sizeof(POINT)*pPathSrc->numEntriesUsed);
284    memcpy(pPathDest->pFlags, pPathSrc->pFlags,
285       sizeof(BYTE)*pPathSrc->numEntriesUsed);
286
287    pPathDest->state=pPathSrc->state;
288    pPathDest->numEntriesUsed=pPathSrc->numEntriesUsed;
289    pPathDest->newStroke=pPathSrc->newStroke;
290
291    return TRUE;
292 }
293
294 /* PATH_CheckCorners
295  *
296  * Helper function for RoundRect() and Rectangle()
297  */
298 static void PATH_CheckCorners( HDC hdc, POINT corners[], INT x1, INT y1, INT x2, INT y2 )
299 {
300     INT temp;
301
302     /* Convert points to device coordinates */
303     corners[0].x=x1;
304     corners[0].y=y1;
305     corners[1].x=x2;
306     corners[1].y=y2;
307     LPtoDP( hdc, corners, 2 );
308
309     /* Make sure first corner is top left and second corner is bottom right */
310     if(corners[0].x>corners[1].x)
311     {
312         temp=corners[0].x;
313         corners[0].x=corners[1].x;
314         corners[1].x=temp;
315     }
316     if(corners[0].y>corners[1].y)
317     {
318         temp=corners[0].y;
319         corners[0].y=corners[1].y;
320         corners[1].y=temp;
321     }
322
323     /* In GM_COMPATIBLE, don't include bottom and right edges */
324     if (GetGraphicsMode( hdc ) == GM_COMPATIBLE)
325     {
326         corners[1].x--;
327         corners[1].y--;
328     }
329 }
330
331 /* PATH_AddFlatBezier
332  */
333 static BOOL PATH_AddFlatBezier(GdiPath *pPath, POINT *pt, BOOL closed)
334 {
335     POINT *pts;
336     INT no, i;
337
338     pts = GDI_Bezier( pt, 4, &no );
339     if(!pts) return FALSE;
340
341     for(i = 1; i < no; i++)
342         PATH_AddEntry(pPath, &pts[i], (i == no-1 && closed) ? PT_LINETO | PT_CLOSEFIGURE : PT_LINETO);
343     HeapFree( GetProcessHeap(), 0, pts );
344     return TRUE;
345 }
346
347 /* PATH_FlattenPath
348  *
349  * Replaces Beziers with line segments
350  *
351  */
352 static BOOL PATH_FlattenPath(GdiPath *pPath)
353 {
354     GdiPath newPath;
355     INT srcpt;
356
357     memset(&newPath, 0, sizeof(newPath));
358     newPath.state = PATH_Open;
359     for(srcpt = 0; srcpt < pPath->numEntriesUsed; srcpt++) {
360         switch(pPath->pFlags[srcpt] & ~PT_CLOSEFIGURE) {
361         case PT_MOVETO:
362         case PT_LINETO:
363             PATH_AddEntry(&newPath, &pPath->pPoints[srcpt],
364                           pPath->pFlags[srcpt]);
365             break;
366         case PT_BEZIERTO:
367             PATH_AddFlatBezier(&newPath, &pPath->pPoints[srcpt-1],
368                                pPath->pFlags[srcpt+2] & PT_CLOSEFIGURE);
369             srcpt += 2;
370             break;
371         }
372     }
373     newPath.state = PATH_Closed;
374     PATH_AssignGdiPath(pPath, &newPath);
375     PATH_DestroyGdiPath(&newPath);
376     return TRUE;
377 }
378
379 /* PATH_PathToRegion
380  *
381  * Creates a region from the specified path using the specified polygon
382  * filling mode. The path is left unchanged. A handle to the region that
383  * was created is stored in *pHrgn. If successful, TRUE is returned; if an
384  * error occurs, SetLastError is called with the appropriate value and
385  * FALSE is returned.
386  */
387 static BOOL PATH_PathToRegion(GdiPath *pPath, INT nPolyFillMode,
388    HRGN *pHrgn)
389 {
390     int    numStrokes, iStroke, i;
391     INT  *pNumPointsInStroke;
392     HRGN hrgn;
393
394     PATH_FlattenPath(pPath);
395
396     /* FIXME: What happens when number of points is zero? */
397
398     /* First pass: Find out how many strokes there are in the path */
399     /* FIXME: We could eliminate this with some bookkeeping in GdiPath */
400     numStrokes=0;
401     for(i=0; i<pPath->numEntriesUsed; i++)
402         if((pPath->pFlags[i] & ~PT_CLOSEFIGURE) == PT_MOVETO)
403             numStrokes++;
404
405     /* Allocate memory for number-of-points-in-stroke array */
406     pNumPointsInStroke=HeapAlloc( GetProcessHeap(), 0, sizeof(int) * numStrokes );
407     if(!pNumPointsInStroke)
408     {
409         SetLastError(ERROR_NOT_ENOUGH_MEMORY);
410         return FALSE;
411     }
412
413     /* Second pass: remember number of points in each polygon */
414     iStroke=-1;  /* Will get incremented to 0 at beginning of first stroke */
415     for(i=0; i<pPath->numEntriesUsed; i++)
416     {
417         /* Is this the beginning of a new stroke? */
418         if((pPath->pFlags[i] & ~PT_CLOSEFIGURE) == PT_MOVETO)
419         {
420             iStroke++;
421             pNumPointsInStroke[iStroke]=0;
422         }
423
424         pNumPointsInStroke[iStroke]++;
425     }
426
427     /* Create a region from the strokes */
428     hrgn=CreatePolyPolygonRgn(pPath->pPoints, pNumPointsInStroke,
429                               numStrokes, nPolyFillMode);
430
431     /* Free memory for number-of-points-in-stroke array */
432     HeapFree( GetProcessHeap(), 0, pNumPointsInStroke );
433
434     if(hrgn==NULL)
435     {
436         SetLastError(ERROR_NOT_ENOUGH_MEMORY);
437         return FALSE;
438     }
439
440     /* Success! */
441     *pHrgn=hrgn;
442     return TRUE;
443 }
444
445 /* PATH_ScaleNormalizedPoint
446  *
447  * Scales a normalized point (x, y) with respect to the box whose corners are
448  * passed in "corners". The point is stored in "*pPoint". The normalized
449  * coordinates (-1.0, -1.0) correspond to corners[0], the coordinates
450  * (1.0, 1.0) correspond to corners[1].
451  */
452 static void PATH_ScaleNormalizedPoint(FLOAT_POINT corners[], double x,
453    double y, POINT *pPoint)
454 {
455     pPoint->x=GDI_ROUND( (double)corners[0].x + (double)(corners[1].x-corners[0].x)*0.5*(x+1.0) );
456     pPoint->y=GDI_ROUND( (double)corners[0].y + (double)(corners[1].y-corners[0].y)*0.5*(y+1.0) );
457 }
458
459 /* PATH_NormalizePoint
460  *
461  * Normalizes a point with respect to the box whose corners are passed in
462  * "corners". The normalized coordinates are stored in "*pX" and "*pY".
463  */
464 static void PATH_NormalizePoint(FLOAT_POINT corners[],
465    const FLOAT_POINT *pPoint,
466    double *pX, double *pY)
467 {
468     *pX=(double)(pPoint->x-corners[0].x)/(double)(corners[1].x-corners[0].x) * 2.0 - 1.0;
469     *pY=(double)(pPoint->y-corners[0].y)/(double)(corners[1].y-corners[0].y) * 2.0 - 1.0;
470 }
471
472 /* PATH_DoArcPart
473  *
474  * Creates a Bezier spline that corresponds to part of an arc and appends the
475  * corresponding points to the path. The start and end angles are passed in
476  * "angleStart" and "angleEnd"; these angles should span a quarter circle
477  * at most. If "startEntryType" is non-zero, an entry of that type for the first
478  * control point is added to the path; otherwise, it is assumed that the current
479  * position is equal to the first control point.
480  */
481 static BOOL PATH_DoArcPart(GdiPath *pPath, FLOAT_POINT corners[],
482    double angleStart, double angleEnd, BYTE startEntryType)
483 {
484     double  halfAngle, a;
485     double  xNorm[4], yNorm[4];
486     POINT point;
487     int     i;
488
489     assert(fabs(angleEnd-angleStart)<=M_PI_2);
490
491     /* FIXME: Is there an easier way of computing this? */
492
493     /* Compute control points */
494     halfAngle=(angleEnd-angleStart)/2.0;
495     if(fabs(halfAngle)>1e-8)
496     {
497         a=4.0/3.0*(1-cos(halfAngle))/sin(halfAngle);
498         xNorm[0]=cos(angleStart);
499         yNorm[0]=sin(angleStart);
500         xNorm[1]=xNorm[0] - a*yNorm[0];
501         yNorm[1]=yNorm[0] + a*xNorm[0];
502         xNorm[3]=cos(angleEnd);
503         yNorm[3]=sin(angleEnd);
504         xNorm[2]=xNorm[3] + a*yNorm[3];
505         yNorm[2]=yNorm[3] - a*xNorm[3];
506     }
507     else
508         for(i=0; i<4; i++)
509         {
510             xNorm[i]=cos(angleStart);
511             yNorm[i]=sin(angleStart);
512         }
513
514     /* Add starting point to path if desired */
515     if(startEntryType)
516     {
517         PATH_ScaleNormalizedPoint(corners, xNorm[0], yNorm[0], &point);
518         if(!PATH_AddEntry(pPath, &point, startEntryType))
519             return FALSE;
520     }
521
522     /* Add remaining control points */
523     for(i=1; i<4; i++)
524     {
525         PATH_ScaleNormalizedPoint(corners, xNorm[i], yNorm[i], &point);
526         if(!PATH_AddEntry(pPath, &point, PT_BEZIERTO))
527             return FALSE;
528     }
529
530     return TRUE;
531 }
532
533
534 /***********************************************************************
535  *           BeginPath    (GDI32.@)
536  */
537 BOOL WINAPI BeginPath(HDC hdc)
538 {
539     BOOL ret = FALSE;
540     DC *dc = get_dc_ptr( hdc );
541
542     if (dc)
543     {
544         PHYSDEV physdev = GET_DC_PHYSDEV( dc, pBeginPath );
545         ret = physdev->funcs->pBeginPath( physdev );
546         release_dc_ptr( dc );
547     }
548     return ret;
549 }
550
551
552 /***********************************************************************
553  *           EndPath    (GDI32.@)
554  */
555 BOOL WINAPI EndPath(HDC hdc)
556 {
557     BOOL ret = FALSE;
558     DC *dc = get_dc_ptr( hdc );
559
560     if (dc)
561     {
562         PHYSDEV physdev = GET_DC_PHYSDEV( dc, pEndPath );
563         ret = physdev->funcs->pEndPath( physdev );
564         release_dc_ptr( dc );
565     }
566     return ret;
567 }
568
569
570 /******************************************************************************
571  * AbortPath [GDI32.@]
572  * Closes and discards paths from device context
573  *
574  * NOTES
575  *    Check that SetLastError is being called correctly
576  *
577  * PARAMS
578  *    hdc [I] Handle to device context
579  *
580  * RETURNS
581  *    Success: TRUE
582  *    Failure: FALSE
583  */
584 BOOL WINAPI AbortPath( HDC hdc )
585 {
586     BOOL ret = FALSE;
587     DC *dc = get_dc_ptr( hdc );
588
589     if (dc)
590     {
591         PHYSDEV physdev = GET_DC_PHYSDEV( dc, pAbortPath );
592         ret = physdev->funcs->pAbortPath( physdev );
593         release_dc_ptr( dc );
594     }
595     return ret;
596 }
597
598
599 /***********************************************************************
600  *           CloseFigure    (GDI32.@)
601  *
602  * FIXME: Check that SetLastError is being called correctly
603  */
604 BOOL WINAPI CloseFigure(HDC hdc)
605 {
606     BOOL ret = FALSE;
607     DC *dc = get_dc_ptr( hdc );
608
609     if (dc)
610     {
611         PHYSDEV physdev = GET_DC_PHYSDEV( dc, pCloseFigure );
612         ret = physdev->funcs->pCloseFigure( physdev );
613         release_dc_ptr( dc );
614     }
615     return ret;
616 }
617
618
619 /***********************************************************************
620  *           GetPath    (GDI32.@)
621  */
622 INT WINAPI GetPath(HDC hdc, LPPOINT pPoints, LPBYTE pTypes,
623    INT nSize)
624 {
625    INT ret = -1;
626    GdiPath *pPath;
627    DC *dc = get_dc_ptr( hdc );
628
629    if(!dc) return -1;
630
631    pPath = &dc->path;
632
633    /* Check that path is closed */
634    if(pPath->state!=PATH_Closed)
635    {
636       SetLastError(ERROR_CAN_NOT_COMPLETE);
637       goto done;
638    }
639
640    if(nSize==0)
641       ret = pPath->numEntriesUsed;
642    else if(nSize<pPath->numEntriesUsed)
643    {
644       SetLastError(ERROR_INVALID_PARAMETER);
645       goto done;
646    }
647    else
648    {
649       memcpy(pPoints, pPath->pPoints, sizeof(POINT)*pPath->numEntriesUsed);
650       memcpy(pTypes, pPath->pFlags, sizeof(BYTE)*pPath->numEntriesUsed);
651
652       /* Convert the points to logical coordinates */
653       if(!DPtoLP(hdc, pPoints, pPath->numEntriesUsed))
654       {
655          /* FIXME: Is this the correct value? */
656          SetLastError(ERROR_CAN_NOT_COMPLETE);
657         goto done;
658       }
659      else ret = pPath->numEntriesUsed;
660    }
661  done:
662    release_dc_ptr( dc );
663    return ret;
664 }
665
666
667 /***********************************************************************
668  *           PathToRegion    (GDI32.@)
669  *
670  * FIXME
671  *   Check that SetLastError is being called correctly
672  *
673  * The documentation does not state this explicitly, but a test under Windows
674  * shows that the region which is returned should be in device coordinates.
675  */
676 HRGN WINAPI PathToRegion(HDC hdc)
677 {
678    GdiPath *pPath;
679    HRGN  hrgnRval = 0;
680    DC *dc = get_dc_ptr( hdc );
681
682    /* Get pointer to path */
683    if(!dc) return 0;
684
685     pPath = &dc->path;
686
687    /* Check that path is closed */
688    if(pPath->state!=PATH_Closed) SetLastError(ERROR_CAN_NOT_COMPLETE);
689    else
690    {
691        /* FIXME: Should we empty the path even if conversion failed? */
692        if(PATH_PathToRegion(pPath, GetPolyFillMode(hdc), &hrgnRval))
693            PATH_EmptyPath(pPath);
694        else
695            hrgnRval=0;
696    }
697    release_dc_ptr( dc );
698    return hrgnRval;
699 }
700
701 static BOOL PATH_FillPath( HDC hdc, GdiPath *pPath )
702 {
703    INT   mapMode, graphicsMode;
704    SIZE  ptViewportExt, ptWindowExt;
705    POINT ptViewportOrg, ptWindowOrg;
706    XFORM xform;
707    HRGN  hrgn;
708
709    /* Construct a region from the path and fill it */
710    if(PATH_PathToRegion(pPath, GetPolyFillMode(hdc), &hrgn))
711    {
712       /* Since PaintRgn interprets the region as being in logical coordinates
713        * but the points we store for the path are already in device
714        * coordinates, we have to set the mapping mode to MM_TEXT temporarily.
715        * Using SaveDC to save information about the mapping mode / world
716        * transform would be easier but would require more overhead, especially
717        * now that SaveDC saves the current path.
718        */
719
720       /* Save the information about the old mapping mode */
721       mapMode=GetMapMode(hdc);
722       GetViewportExtEx(hdc, &ptViewportExt);
723       GetViewportOrgEx(hdc, &ptViewportOrg);
724       GetWindowExtEx(hdc, &ptWindowExt);
725       GetWindowOrgEx(hdc, &ptWindowOrg);
726
727       /* Save world transform
728        * NB: The Windows documentation on world transforms would lead one to
729        * believe that this has to be done only in GM_ADVANCED; however, my
730        * tests show that resetting the graphics mode to GM_COMPATIBLE does
731        * not reset the world transform.
732        */
733       GetWorldTransform(hdc, &xform);
734
735       /* Set MM_TEXT */
736       SetMapMode(hdc, MM_TEXT);
737       SetViewportOrgEx(hdc, 0, 0, NULL);
738       SetWindowOrgEx(hdc, 0, 0, NULL);
739       graphicsMode=GetGraphicsMode(hdc);
740       SetGraphicsMode(hdc, GM_ADVANCED);
741       ModifyWorldTransform(hdc, &xform, MWT_IDENTITY);
742       SetGraphicsMode(hdc, graphicsMode);
743
744       /* Paint the region */
745       PaintRgn(hdc, hrgn);
746       DeleteObject(hrgn);
747       /* Restore the old mapping mode */
748       SetMapMode(hdc, mapMode);
749       SetViewportExtEx(hdc, ptViewportExt.cx, ptViewportExt.cy, NULL);
750       SetViewportOrgEx(hdc, ptViewportOrg.x, ptViewportOrg.y, NULL);
751       SetWindowExtEx(hdc, ptWindowExt.cx, ptWindowExt.cy, NULL);
752       SetWindowOrgEx(hdc, ptWindowOrg.x, ptWindowOrg.y, NULL);
753
754       /* Go to GM_ADVANCED temporarily to restore the world transform */
755       graphicsMode=GetGraphicsMode(hdc);
756       SetGraphicsMode(hdc, GM_ADVANCED);
757       SetWorldTransform(hdc, &xform);
758       SetGraphicsMode(hdc, graphicsMode);
759       return TRUE;
760    }
761    return FALSE;
762 }
763
764
765 /***********************************************************************
766  *           FillPath    (GDI32.@)
767  *
768  * FIXME
769  *    Check that SetLastError is being called correctly
770  */
771 BOOL WINAPI FillPath(HDC hdc)
772 {
773     BOOL ret = FALSE;
774     DC *dc = get_dc_ptr( hdc );
775
776     if (dc)
777     {
778         PHYSDEV physdev = GET_DC_PHYSDEV( dc, pFillPath );
779         ret = physdev->funcs->pFillPath( physdev );
780         release_dc_ptr( dc );
781     }
782     return ret;
783 }
784
785
786 /***********************************************************************
787  *           SelectClipPath    (GDI32.@)
788  * FIXME
789  *  Check that SetLastError is being called correctly
790  */
791 BOOL WINAPI SelectClipPath(HDC hdc, INT iMode)
792 {
793     BOOL ret = FALSE;
794     DC *dc = get_dc_ptr( hdc );
795
796     if (dc)
797     {
798         PHYSDEV physdev = GET_DC_PHYSDEV( dc, pSelectClipPath );
799         ret = physdev->funcs->pSelectClipPath( physdev, iMode );
800         release_dc_ptr( dc );
801     }
802     return ret;
803 }
804
805
806 /***********************************************************************
807  *           pathdrv_BeginPath
808  */
809 static BOOL pathdrv_BeginPath( PHYSDEV dev )
810 {
811     /* path already open, nothing to do */
812     return TRUE;
813 }
814
815
816 /***********************************************************************
817  *           pathdrv_AbortPath
818  */
819 static BOOL pathdrv_AbortPath( PHYSDEV dev )
820 {
821     DC *dc = get_dc_ptr( dev->hdc );
822
823     if (!dc) return FALSE;
824     PATH_EmptyPath( &dc->path );
825     pop_path_driver( dc );
826     release_dc_ptr( dc );
827     return TRUE;
828 }
829
830
831 /***********************************************************************
832  *           pathdrv_EndPath
833  */
834 static BOOL pathdrv_EndPath( PHYSDEV dev )
835 {
836     DC *dc = get_dc_ptr( dev->hdc );
837
838     if (!dc) return FALSE;
839     dc->path.state = PATH_Closed;
840     pop_path_driver( dc );
841     release_dc_ptr( dc );
842     return TRUE;
843 }
844
845
846 /***********************************************************************
847  *           pathdrv_CreateDC
848  */
849 static BOOL pathdrv_CreateDC( PHYSDEV *dev, LPCWSTR driver, LPCWSTR device,
850                               LPCWSTR output, const DEVMODEW *devmode )
851 {
852     struct path_physdev *physdev = HeapAlloc( GetProcessHeap(), 0, sizeof(*physdev) );
853     DC *dc;
854
855     if (!physdev) return FALSE;
856     dc = get_dc_ptr( (*dev)->hdc );
857     physdev->path = &dc->path;
858     push_dc_driver( dev, &physdev->dev, &path_driver );
859     release_dc_ptr( dc );
860     return TRUE;
861 }
862
863
864 /*************************************************************
865  *           pathdrv_DeleteDC
866  */
867 static BOOL pathdrv_DeleteDC( PHYSDEV dev )
868 {
869     assert( 0 );  /* should never be called */
870     return TRUE;
871 }
872
873
874 /* PATH_InitGdiPath
875  *
876  * Initializes the GdiPath structure.
877  */
878 void PATH_InitGdiPath(GdiPath *pPath)
879 {
880    assert(pPath!=NULL);
881
882    pPath->state=PATH_Null;
883    pPath->pPoints=NULL;
884    pPath->pFlags=NULL;
885    pPath->numEntriesUsed=0;
886    pPath->numEntriesAllocated=0;
887 }
888
889 /* PATH_DestroyGdiPath
890  *
891  * Destroys a GdiPath structure (frees the memory in the arrays).
892  */
893 void PATH_DestroyGdiPath(GdiPath *pPath)
894 {
895    assert(pPath!=NULL);
896
897    HeapFree( GetProcessHeap(), 0, pPath->pPoints );
898    HeapFree( GetProcessHeap(), 0, pPath->pFlags );
899 }
900
901 BOOL PATH_SavePath( DC *dst, DC *src )
902 {
903     PATH_InitGdiPath( &dst->path );
904     return PATH_AssignGdiPath( &dst->path, &src->path );
905 }
906
907 BOOL PATH_RestorePath( DC *dst, DC *src )
908 {
909     BOOL ret;
910
911     if (src->path.state == PATH_Open && dst->path.state != PATH_Open)
912     {
913         if (!path_driver.pCreateDC( &dst->physDev, NULL, NULL, NULL, NULL )) return FALSE;
914         ret = PATH_AssignGdiPath( &dst->path, &src->path );
915         if (!ret) pop_path_driver( dst );
916     }
917     else if (src->path.state != PATH_Open && dst->path.state == PATH_Open)
918     {
919         ret = PATH_AssignGdiPath( &dst->path, &src->path );
920         if (ret) pop_path_driver( dst );
921     }
922     else ret = PATH_AssignGdiPath( &dst->path, &src->path );
923     return ret;
924 }
925
926
927 /*************************************************************
928  *           pathdrv_MoveTo
929  */
930 static BOOL pathdrv_MoveTo( PHYSDEV dev, INT x, INT y )
931 {
932     struct path_physdev *physdev = get_path_physdev( dev );
933     physdev->path->newStroke = TRUE;
934     return TRUE;
935 }
936
937
938 /*************************************************************
939  *           pathdrv_LineTo
940  */
941 static BOOL pathdrv_LineTo( PHYSDEV dev, INT x, INT y )
942 {
943     struct path_physdev *physdev = get_path_physdev( dev );
944     POINT point;
945
946     if (!start_new_stroke( physdev )) return FALSE;
947     point.x = x;
948     point.y = y;
949     return add_log_points( physdev, &point, 1, PT_LINETO ) != NULL;
950 }
951
952
953 /*************************************************************
954  *           pathdrv_RoundRect
955  *
956  * FIXME: it adds the same entries to the path as windows does, but there
957  * is an error in the bezier drawing code so that there are small pixel-size
958  * gaps when the resulting path is drawn by StrokePath()
959  */
960 static BOOL pathdrv_RoundRect( PHYSDEV dev, INT x1, INT y1, INT x2, INT y2, INT ell_width, INT ell_height )
961 {
962     struct path_physdev *physdev = get_path_physdev( dev );
963     POINT corners[2], pointTemp;
964     FLOAT_POINT ellCorners[2];
965
966     PATH_CheckCorners(dev->hdc,corners,x1,y1,x2,y2);
967
968    /* Add points to the roundrect path */
969    ellCorners[0].x = corners[1].x-ell_width;
970    ellCorners[0].y = corners[0].y;
971    ellCorners[1].x = corners[1].x;
972    ellCorners[1].y = corners[0].y+ell_height;
973    if(!PATH_DoArcPart(physdev->path, ellCorners, 0, -M_PI_2, PT_MOVETO))
974       return FALSE;
975    pointTemp.x = corners[0].x+ell_width/2;
976    pointTemp.y = corners[0].y;
977    if(!PATH_AddEntry(physdev->path, &pointTemp, PT_LINETO))
978       return FALSE;
979    ellCorners[0].x = corners[0].x;
980    ellCorners[1].x = corners[0].x+ell_width;
981    if(!PATH_DoArcPart(physdev->path, ellCorners, -M_PI_2, -M_PI, FALSE))
982       return FALSE;
983    pointTemp.x = corners[0].x;
984    pointTemp.y = corners[1].y-ell_height/2;
985    if(!PATH_AddEntry(physdev->path, &pointTemp, PT_LINETO))
986       return FALSE;
987    ellCorners[0].y = corners[1].y-ell_height;
988    ellCorners[1].y = corners[1].y;
989    if(!PATH_DoArcPart(physdev->path, ellCorners, M_PI, M_PI_2, FALSE))
990       return FALSE;
991    pointTemp.x = corners[1].x-ell_width/2;
992    pointTemp.y = corners[1].y;
993    if(!PATH_AddEntry(physdev->path, &pointTemp, PT_LINETO))
994       return FALSE;
995    ellCorners[0].x = corners[1].x-ell_width;
996    ellCorners[1].x = corners[1].x;
997    if(!PATH_DoArcPart(physdev->path, ellCorners, M_PI_2, 0, FALSE))
998       return FALSE;
999
1000    /* Close the roundrect figure */
1001    return CloseFigure( dev->hdc );
1002 }
1003
1004
1005 /*************************************************************
1006  *           pathdrv_Rectangle
1007  */
1008 static BOOL pathdrv_Rectangle( PHYSDEV dev, INT x1, INT y1, INT x2, INT y2 )
1009 {
1010     struct path_physdev *physdev = get_path_physdev( dev );
1011     POINT corners[2], pointTemp;
1012
1013     PATH_CheckCorners(dev->hdc,corners,x1,y1,x2,y2);
1014
1015    /* Add four points to the path */
1016    pointTemp.x=corners[1].x;
1017    pointTemp.y=corners[0].y;
1018    if(!PATH_AddEntry(physdev->path, &pointTemp, PT_MOVETO))
1019       return FALSE;
1020    if(!PATH_AddEntry(physdev->path, corners, PT_LINETO))
1021       return FALSE;
1022    pointTemp.x=corners[0].x;
1023    pointTemp.y=corners[1].y;
1024    if(!PATH_AddEntry(physdev->path, &pointTemp, PT_LINETO))
1025       return FALSE;
1026    if(!PATH_AddEntry(physdev->path, corners+1, PT_LINETO))
1027       return FALSE;
1028
1029    /* Close the rectangle figure */
1030    return CloseFigure( dev->hdc );
1031 }
1032
1033
1034 /* PATH_Arc
1035  *
1036  * Should be called when a call to Arc is performed on a DC that has
1037  * an open path. This adds up to five Bezier splines representing the arc
1038  * to the path. When 'lines' is 1, we add 1 extra line to get a chord,
1039  * when 'lines' is 2, we add 2 extra lines to get a pie, and when 'lines' is
1040  * -1 we add 1 extra line from the current DC position to the starting position
1041  * of the arc before drawing the arc itself (arcto). Returns TRUE if successful,
1042  * else FALSE.
1043  */
1044 static BOOL PATH_Arc( PHYSDEV dev, INT x1, INT y1, INT x2, INT y2,
1045                       INT xStart, INT yStart, INT xEnd, INT yEnd, INT lines )
1046 {
1047     struct path_physdev *physdev = get_path_physdev( dev );
1048     double angleStart, angleEnd, angleStartQuadrant, angleEndQuadrant=0.0;
1049                /* Initialize angleEndQuadrant to silence gcc's warning */
1050     double x, y;
1051     FLOAT_POINT corners[2], pointStart, pointEnd;
1052     POINT centre;
1053     BOOL start, end;
1054     INT temp, direction = GetArcDirection(dev->hdc);
1055
1056    /* FIXME: Do we have to respect newStroke? */
1057
1058    /* Check for zero height / width */
1059    /* FIXME: Only in GM_COMPATIBLE? */
1060    if(x1==x2 || y1==y2)
1061       return TRUE;
1062
1063    /* Convert points to device coordinates */
1064    corners[0].x = x1;
1065    corners[0].y = y1;
1066    corners[1].x = x2;
1067    corners[1].y = y2;
1068    pointStart.x = xStart;
1069    pointStart.y = yStart;
1070    pointEnd.x = xEnd;
1071    pointEnd.y = yEnd;
1072    INTERNAL_LPTODP_FLOAT(dev->hdc, corners, 2);
1073    INTERNAL_LPTODP_FLOAT(dev->hdc, &pointStart, 1);
1074    INTERNAL_LPTODP_FLOAT(dev->hdc, &pointEnd, 1);
1075
1076    /* Make sure first corner is top left and second corner is bottom right */
1077    if(corners[0].x>corners[1].x)
1078    {
1079       temp=corners[0].x;
1080       corners[0].x=corners[1].x;
1081       corners[1].x=temp;
1082    }
1083    if(corners[0].y>corners[1].y)
1084    {
1085       temp=corners[0].y;
1086       corners[0].y=corners[1].y;
1087       corners[1].y=temp;
1088    }
1089
1090    /* Compute start and end angle */
1091    PATH_NormalizePoint(corners, &pointStart, &x, &y);
1092    angleStart=atan2(y, x);
1093    PATH_NormalizePoint(corners, &pointEnd, &x, &y);
1094    angleEnd=atan2(y, x);
1095
1096    /* Make sure the end angle is "on the right side" of the start angle */
1097    if (direction == AD_CLOCKWISE)
1098    {
1099       if(angleEnd<=angleStart)
1100       {
1101          angleEnd+=2*M_PI;
1102          assert(angleEnd>=angleStart);
1103       }
1104    }
1105    else
1106    {
1107       if(angleEnd>=angleStart)
1108       {
1109          angleEnd-=2*M_PI;
1110          assert(angleEnd<=angleStart);
1111       }
1112    }
1113
1114    /* In GM_COMPATIBLE, don't include bottom and right edges */
1115    if (GetGraphicsMode(dev->hdc) == GM_COMPATIBLE)
1116    {
1117       corners[1].x--;
1118       corners[1].y--;
1119    }
1120
1121    /* arcto: Add a PT_MOVETO only if this is the first entry in a stroke */
1122    if (lines==-1 && !start_new_stroke( physdev )) return FALSE;
1123
1124    /* Add the arc to the path with one Bezier spline per quadrant that the
1125     * arc spans */
1126    start=TRUE;
1127    end=FALSE;
1128    do
1129    {
1130       /* Determine the start and end angles for this quadrant */
1131       if(start)
1132       {
1133          angleStartQuadrant=angleStart;
1134          if (direction == AD_CLOCKWISE)
1135             angleEndQuadrant=(floor(angleStart/M_PI_2)+1.0)*M_PI_2;
1136          else
1137             angleEndQuadrant=(ceil(angleStart/M_PI_2)-1.0)*M_PI_2;
1138       }
1139       else
1140       {
1141          angleStartQuadrant=angleEndQuadrant;
1142          if (direction == AD_CLOCKWISE)
1143             angleEndQuadrant+=M_PI_2;
1144          else
1145             angleEndQuadrant-=M_PI_2;
1146       }
1147
1148       /* Have we reached the last part of the arc? */
1149       if((direction == AD_CLOCKWISE && angleEnd<angleEndQuadrant) ||
1150          (direction == AD_COUNTERCLOCKWISE && angleEnd>angleEndQuadrant))
1151       {
1152          /* Adjust the end angle for this quadrant */
1153          angleEndQuadrant=angleEnd;
1154          end=TRUE;
1155       }
1156
1157       /* Add the Bezier spline to the path */
1158       PATH_DoArcPart(physdev->path, corners, angleStartQuadrant, angleEndQuadrant,
1159          start ? (lines==-1 ? PT_LINETO : PT_MOVETO) : FALSE);
1160       start=FALSE;
1161    }  while(!end);
1162
1163    /* chord: close figure. pie: add line and close figure */
1164    if(lines==1)
1165    {
1166       return CloseFigure(dev->hdc);
1167    }
1168    else if(lines==2)
1169    {
1170       centre.x = (corners[0].x+corners[1].x)/2;
1171       centre.y = (corners[0].y+corners[1].y)/2;
1172       if(!PATH_AddEntry(physdev->path, &centre, PT_LINETO | PT_CLOSEFIGURE))
1173          return FALSE;
1174    }
1175
1176    return TRUE;
1177 }
1178
1179
1180 /*************************************************************
1181  *           pathdrv_AngleArc
1182  */
1183 static BOOL pathdrv_AngleArc( PHYSDEV dev, INT x, INT y, DWORD radius, FLOAT eStartAngle, FLOAT eSweepAngle)
1184 {
1185     INT x1, y1, x2, y2, arcdir;
1186     BOOL ret;
1187
1188     x1 = GDI_ROUND( x + cos(eStartAngle*M_PI/180) * radius );
1189     y1 = GDI_ROUND( y - sin(eStartAngle*M_PI/180) * radius );
1190     x2 = GDI_ROUND( x + cos((eStartAngle+eSweepAngle)*M_PI/180) * radius );
1191     y2 = GDI_ROUND( y - sin((eStartAngle+eSweepAngle)*M_PI/180) * radius );
1192     arcdir = SetArcDirection( dev->hdc, eSweepAngle >= 0 ? AD_COUNTERCLOCKWISE : AD_CLOCKWISE);
1193     ret = PATH_Arc( dev, x-radius, y-radius, x+radius, y+radius, x1, y1, x2, y2, -1 );
1194     SetArcDirection( dev->hdc, arcdir );
1195     return ret;
1196 }
1197
1198
1199 /*************************************************************
1200  *           pathdrv_Arc
1201  */
1202 static BOOL pathdrv_Arc( PHYSDEV dev, INT left, INT top, INT right, INT bottom,
1203                          INT xstart, INT ystart, INT xend, INT yend )
1204 {
1205     return PATH_Arc( dev, left, top, right, bottom, xstart, ystart, xend, yend, 0 );
1206 }
1207
1208
1209 /*************************************************************
1210  *           pathdrv_ArcTo
1211  */
1212 static BOOL pathdrv_ArcTo( PHYSDEV dev, INT left, INT top, INT right, INT bottom,
1213                            INT xstart, INT ystart, INT xend, INT yend )
1214 {
1215     return PATH_Arc( dev, left, top, right, bottom, xstart, ystart, xend, yend, -1 );
1216 }
1217
1218
1219 /*************************************************************
1220  *           pathdrv_Chord
1221  */
1222 static BOOL pathdrv_Chord( PHYSDEV dev, INT left, INT top, INT right, INT bottom,
1223                            INT xstart, INT ystart, INT xend, INT yend )
1224 {
1225     return PATH_Arc( dev, left, top, right, bottom, xstart, ystart, xend, yend, 1);
1226 }
1227
1228
1229 /*************************************************************
1230  *           pathdrv_Pie
1231  */
1232 static BOOL pathdrv_Pie( PHYSDEV dev, INT left, INT top, INT right, INT bottom,
1233                          INT xstart, INT ystart, INT xend, INT yend )
1234 {
1235     return PATH_Arc( dev, left, top, right, bottom, xstart, ystart, xend, yend, 2 );
1236 }
1237
1238
1239 /*************************************************************
1240  *           pathdrv_Ellipse
1241  */
1242 static BOOL pathdrv_Ellipse( PHYSDEV dev, INT x1, INT y1, INT x2, INT y2 )
1243 {
1244     return PATH_Arc( dev, x1, y1, x2, y2, x1, (y1+y2)/2, x1, (y1+y2)/2, 0 ) && CloseFigure( dev->hdc );
1245 }
1246
1247
1248 /*************************************************************
1249  *           pathdrv_PolyBezierTo
1250  */
1251 static BOOL pathdrv_PolyBezierTo( PHYSDEV dev, const POINT *pts, DWORD cbPoints )
1252 {
1253     struct path_physdev *physdev = get_path_physdev( dev );
1254
1255     if (!start_new_stroke( physdev )) return FALSE;
1256     return add_log_points( physdev, pts, cbPoints, PT_BEZIERTO ) != NULL;
1257 }
1258
1259
1260 /*************************************************************
1261  *           pathdrv_PolyBezier
1262  */
1263 static BOOL pathdrv_PolyBezier( PHYSDEV dev, const POINT *pts, DWORD cbPoints )
1264 {
1265     struct path_physdev *physdev = get_path_physdev( dev );
1266     BYTE *type = add_log_points( physdev, pts, cbPoints, PT_BEZIERTO );
1267
1268     if (!type) return FALSE;
1269     type[0] = PT_MOVETO;
1270     return TRUE;
1271 }
1272
1273
1274 /*************************************************************
1275  *           pathdrv_PolyDraw
1276  */
1277 static BOOL pathdrv_PolyDraw( PHYSDEV dev, const POINT *pts, const BYTE *types, DWORD cbPoints )
1278 {
1279     struct path_physdev *physdev = get_path_physdev( dev );
1280     POINT lastmove, orig_pos;
1281     INT i;
1282
1283     GetCurrentPositionEx( dev->hdc, &orig_pos );
1284     lastmove = orig_pos;
1285
1286     for(i = physdev->path->numEntriesUsed - 1; i >= 0; i--){
1287         if(physdev->path->pFlags[i] == PT_MOVETO){
1288             lastmove = physdev->path->pPoints[i];
1289             DPtoLP(dev->hdc, &lastmove, 1);
1290             break;
1291         }
1292     }
1293
1294     for(i = 0; i < cbPoints; i++)
1295     {
1296         switch (types[i])
1297         {
1298         case PT_MOVETO:
1299             MoveToEx( dev->hdc, pts[i].x, pts[i].y, NULL );
1300             break;
1301         case PT_LINETO:
1302         case PT_LINETO | PT_CLOSEFIGURE:
1303             LineTo( dev->hdc, pts[i].x, pts[i].y );
1304             break;
1305         case PT_BEZIERTO:
1306             if ((i + 2 < cbPoints) && (types[i + 1] == PT_BEZIERTO) &&
1307                 (types[i + 2] & ~PT_CLOSEFIGURE) == PT_BEZIERTO)
1308             {
1309                 PolyBezierTo( dev->hdc, &pts[i], 3 );
1310                 i += 2;
1311                 break;
1312             }
1313             /* fall through */
1314         default:
1315             if (i)  /* restore original position */
1316             {
1317                 if (!(types[i - 1] & PT_CLOSEFIGURE)) lastmove = pts[i - 1];
1318                 if (lastmove.x != orig_pos.x || lastmove.y != orig_pos.y)
1319                     MoveToEx( dev->hdc, orig_pos.x, orig_pos.y, NULL );
1320             }
1321             return FALSE;
1322         }
1323
1324         if(types[i] & PT_CLOSEFIGURE){
1325             physdev->path->pFlags[physdev->path->numEntriesUsed-1] |= PT_CLOSEFIGURE;
1326             MoveToEx( dev->hdc, lastmove.x, lastmove.y, NULL );
1327         }
1328     }
1329
1330     return TRUE;
1331 }
1332
1333
1334 /*************************************************************
1335  *           pathdrv_Polyline
1336  */
1337 static BOOL pathdrv_Polyline( PHYSDEV dev, const POINT *pts, INT cbPoints )
1338 {
1339     struct path_physdev *physdev = get_path_physdev( dev );
1340     BYTE *type = add_log_points( physdev, pts, cbPoints, PT_LINETO );
1341
1342     if (!type) return FALSE;
1343     if (cbPoints) type[0] = PT_MOVETO;
1344     return TRUE;
1345 }
1346
1347
1348 /*************************************************************
1349  *           pathdrv_PolylineTo
1350  */
1351 static BOOL pathdrv_PolylineTo( PHYSDEV dev, const POINT *pts, INT cbPoints )
1352 {
1353     struct path_physdev *physdev = get_path_physdev( dev );
1354
1355     if (!start_new_stroke( physdev )) return FALSE;
1356     return add_log_points( physdev, pts, cbPoints, PT_LINETO ) != NULL;
1357 }
1358
1359
1360 /*************************************************************
1361  *           pathdrv_Polygon
1362  */
1363 static BOOL pathdrv_Polygon( PHYSDEV dev, const POINT *pts, INT cbPoints )
1364 {
1365     struct path_physdev *physdev = get_path_physdev( dev );
1366     BYTE *type = add_log_points( physdev, pts, cbPoints, PT_LINETO );
1367
1368     if (!type) return FALSE;
1369     if (cbPoints) type[0] = PT_MOVETO;
1370     if (cbPoints > 1) type[cbPoints - 1] = PT_LINETO | PT_CLOSEFIGURE;
1371     return TRUE;
1372 }
1373
1374
1375 /*************************************************************
1376  *           pathdrv_PolyPolygon
1377  */
1378 static BOOL pathdrv_PolyPolygon( PHYSDEV dev, const POINT* pts, const INT* counts, UINT polygons )
1379 {
1380     struct path_physdev *physdev = get_path_physdev( dev );
1381     UINT poly;
1382     BYTE *type;
1383
1384     for(poly = 0; poly < polygons; poly++) {
1385         type = add_log_points( physdev, pts, counts[poly], PT_LINETO );
1386         if (!type) return FALSE;
1387         type[0] = PT_MOVETO;
1388         /* win98 adds an extra line to close the figure for some reason */
1389         add_log_points( physdev, pts, 1, PT_LINETO | PT_CLOSEFIGURE );
1390         pts += counts[poly];
1391     }
1392     return TRUE;
1393 }
1394
1395
1396 /*************************************************************
1397  *           pathdrv_PolyPolyline
1398  */
1399 static BOOL pathdrv_PolyPolyline( PHYSDEV dev, const POINT* pts, const DWORD* counts, DWORD polylines )
1400 {
1401     struct path_physdev *physdev = get_path_physdev( dev );
1402     UINT poly, count;
1403     BYTE *type;
1404
1405     for (poly = count = 0; poly < polylines; poly++) count += counts[poly];
1406
1407     type = add_log_points( physdev, pts, count, PT_LINETO );
1408     if (!type) return FALSE;
1409
1410     /* make the first point of each polyline a PT_MOVETO */
1411     for (poly = 0; poly < polylines; poly++, type += counts[poly]) *type = PT_MOVETO;
1412     return TRUE;
1413 }
1414
1415
1416 /**********************************************************************
1417  *      PATH_BezierTo
1418  *
1419  * internally used by PATH_add_outline
1420  */
1421 static void PATH_BezierTo(GdiPath *pPath, POINT *lppt, INT n)
1422 {
1423     if (n < 2) return;
1424
1425     if (n == 2)
1426     {
1427         PATH_AddEntry(pPath, &lppt[1], PT_LINETO);
1428     }
1429     else if (n == 3)
1430     {
1431         PATH_AddEntry(pPath, &lppt[0], PT_BEZIERTO);
1432         PATH_AddEntry(pPath, &lppt[1], PT_BEZIERTO);
1433         PATH_AddEntry(pPath, &lppt[2], PT_BEZIERTO);
1434     }
1435     else
1436     {
1437         POINT pt[3];
1438         INT i = 0;
1439
1440         pt[2] = lppt[0];
1441         n--;
1442
1443         while (n > 2)
1444         {
1445             pt[0] = pt[2];
1446             pt[1] = lppt[i+1];
1447             pt[2].x = (lppt[i+2].x + lppt[i+1].x) / 2;
1448             pt[2].y = (lppt[i+2].y + lppt[i+1].y) / 2;
1449             PATH_BezierTo(pPath, pt, 3);
1450             n--;
1451             i++;
1452         }
1453
1454         pt[0] = pt[2];
1455         pt[1] = lppt[i+1];
1456         pt[2] = lppt[i+2];
1457         PATH_BezierTo(pPath, pt, 3);
1458     }
1459 }
1460
1461 static BOOL PATH_add_outline(struct path_physdev *physdev, INT x, INT y,
1462                              TTPOLYGONHEADER *header, DWORD size)
1463 {
1464     TTPOLYGONHEADER *start;
1465     POINT pt;
1466
1467     start = header;
1468
1469     while ((char *)header < (char *)start + size)
1470     {
1471         TTPOLYCURVE *curve;
1472
1473         if (header->dwType != TT_POLYGON_TYPE)
1474         {
1475             FIXME("Unknown header type %d\n", header->dwType);
1476             return FALSE;
1477         }
1478
1479         pt.x = x + int_from_fixed(header->pfxStart.x);
1480         pt.y = y - int_from_fixed(header->pfxStart.y);
1481         PATH_AddEntry(physdev->path, &pt, PT_MOVETO);
1482
1483         curve = (TTPOLYCURVE *)(header + 1);
1484
1485         while ((char *)curve < (char *)header + header->cb)
1486         {
1487             /*TRACE("curve->wType %d\n", curve->wType);*/
1488
1489             switch(curve->wType)
1490             {
1491             case TT_PRIM_LINE:
1492             {
1493                 WORD i;
1494
1495                 for (i = 0; i < curve->cpfx; i++)
1496                 {
1497                     pt.x = x + int_from_fixed(curve->apfx[i].x);
1498                     pt.y = y - int_from_fixed(curve->apfx[i].y);
1499                     PATH_AddEntry(physdev->path, &pt, PT_LINETO);
1500                 }
1501                 break;
1502             }
1503
1504             case TT_PRIM_QSPLINE:
1505             case TT_PRIM_CSPLINE:
1506             {
1507                 WORD i;
1508                 POINTFX ptfx;
1509                 POINT *pts = HeapAlloc(GetProcessHeap(), 0, (curve->cpfx + 1) * sizeof(POINT));
1510
1511                 if (!pts) return FALSE;
1512
1513                 ptfx = *(POINTFX *)((char *)curve - sizeof(POINTFX));
1514
1515                 pts[0].x = x + int_from_fixed(ptfx.x);
1516                 pts[0].y = y - int_from_fixed(ptfx.y);
1517
1518                 for(i = 0; i < curve->cpfx; i++)
1519                 {
1520                     pts[i + 1].x = x + int_from_fixed(curve->apfx[i].x);
1521                     pts[i + 1].y = y - int_from_fixed(curve->apfx[i].y);
1522                 }
1523
1524                 PATH_BezierTo(physdev->path, pts, curve->cpfx + 1);
1525
1526                 HeapFree(GetProcessHeap(), 0, pts);
1527                 break;
1528             }
1529
1530             default:
1531                 FIXME("Unknown curve type %04x\n", curve->wType);
1532                 return FALSE;
1533             }
1534
1535             curve = (TTPOLYCURVE *)&curve->apfx[curve->cpfx];
1536         }
1537
1538         header = (TTPOLYGONHEADER *)((char *)header + header->cb);
1539     }
1540
1541     return CloseFigure(physdev->dev.hdc);
1542 }
1543
1544 /*************************************************************
1545  *           pathdrv_ExtTextOut
1546  */
1547 static BOOL pathdrv_ExtTextOut( PHYSDEV dev, INT x, INT y, UINT flags, const RECT *lprc,
1548                                 LPCWSTR str, UINT count, const INT *dx )
1549 {
1550     struct path_physdev *physdev = get_path_physdev( dev );
1551     unsigned int idx;
1552     POINT offset = {0, 0};
1553
1554     if (!count) return TRUE;
1555
1556     for (idx = 0; idx < count; idx++)
1557     {
1558         static const MAT2 identity = { {0,1},{0,0},{0,0},{0,1} };
1559         GLYPHMETRICS gm;
1560         DWORD dwSize;
1561         void *outline;
1562
1563         dwSize = GetGlyphOutlineW(dev->hdc, str[idx], GGO_GLYPH_INDEX | GGO_NATIVE,
1564                                   &gm, 0, NULL, &identity);
1565         if (dwSize == GDI_ERROR) return FALSE;
1566
1567         /* add outline only if char is printable */
1568         if(dwSize)
1569         {
1570             outline = HeapAlloc(GetProcessHeap(), 0, dwSize);
1571             if (!outline) return FALSE;
1572
1573             GetGlyphOutlineW(dev->hdc, str[idx], GGO_GLYPH_INDEX | GGO_NATIVE,
1574                              &gm, dwSize, outline, &identity);
1575
1576             PATH_add_outline(physdev, x + offset.x, y + offset.y, outline, dwSize);
1577
1578             HeapFree(GetProcessHeap(), 0, outline);
1579         }
1580
1581         if (dx)
1582         {
1583             if(flags & ETO_PDY)
1584             {
1585                 offset.x += dx[idx * 2];
1586                 offset.y += dx[idx * 2 + 1];
1587             }
1588             else
1589                 offset.x += dx[idx];
1590         }
1591         else
1592         {
1593             offset.x += gm.gmCellIncX;
1594             offset.y += gm.gmCellIncY;
1595         }
1596     }
1597     return TRUE;
1598 }
1599
1600
1601 /*************************************************************
1602  *           pathdrv_CloseFigure
1603  */
1604 static BOOL pathdrv_CloseFigure( PHYSDEV dev )
1605 {
1606     struct path_physdev *physdev = get_path_physdev( dev );
1607
1608     /* Set PT_CLOSEFIGURE on the last entry and start a new stroke */
1609     /* It is not necessary to draw a line, PT_CLOSEFIGURE is a virtual closing line itself */
1610     if (physdev->path->numEntriesUsed)
1611         physdev->path->pFlags[physdev->path->numEntriesUsed - 1] |= PT_CLOSEFIGURE;
1612     return TRUE;
1613 }
1614
1615
1616 /*******************************************************************
1617  *      FlattenPath [GDI32.@]
1618  *
1619  *
1620  */
1621 BOOL WINAPI FlattenPath(HDC hdc)
1622 {
1623     BOOL ret = FALSE;
1624     DC *dc = get_dc_ptr( hdc );
1625
1626     if (dc)
1627     {
1628         PHYSDEV physdev = GET_DC_PHYSDEV( dc, pFlattenPath );
1629         ret = physdev->funcs->pFlattenPath( physdev );
1630         release_dc_ptr( dc );
1631     }
1632     return ret;
1633 }
1634
1635
1636 static BOOL PATH_StrokePath( HDC hdc, GdiPath *pPath )
1637 {
1638     INT i, nLinePts, nAlloc;
1639     POINT *pLinePts;
1640     POINT ptViewportOrg, ptWindowOrg;
1641     SIZE szViewportExt, szWindowExt;
1642     DWORD mapMode, graphicsMode;
1643     XFORM xform;
1644     BOOL ret = TRUE;
1645
1646     /* Save the mapping mode info */
1647     mapMode=GetMapMode(hdc);
1648     GetViewportExtEx(hdc, &szViewportExt);
1649     GetViewportOrgEx(hdc, &ptViewportOrg);
1650     GetWindowExtEx(hdc, &szWindowExt);
1651     GetWindowOrgEx(hdc, &ptWindowOrg);
1652     GetWorldTransform(hdc, &xform);
1653
1654     /* Set MM_TEXT */
1655     SetMapMode(hdc, MM_TEXT);
1656     SetViewportOrgEx(hdc, 0, 0, NULL);
1657     SetWindowOrgEx(hdc, 0, 0, NULL);
1658     graphicsMode=GetGraphicsMode(hdc);
1659     SetGraphicsMode(hdc, GM_ADVANCED);
1660     ModifyWorldTransform(hdc, &xform, MWT_IDENTITY);
1661     SetGraphicsMode(hdc, graphicsMode);
1662
1663     /* Allocate enough memory for the worst case without beziers (one PT_MOVETO
1664      * and the rest PT_LINETO with PT_CLOSEFIGURE at the end) plus some buffer 
1665      * space in case we get one to keep the number of reallocations small. */
1666     nAlloc = pPath->numEntriesUsed + 1 + 300; 
1667     pLinePts = HeapAlloc(GetProcessHeap(), 0, nAlloc * sizeof(POINT));
1668     nLinePts = 0;
1669     
1670     for(i = 0; i < pPath->numEntriesUsed; i++) {
1671         if((i == 0 || (pPath->pFlags[i-1] & PT_CLOSEFIGURE)) &&
1672            (pPath->pFlags[i] != PT_MOVETO)) {
1673             ERR("Expected PT_MOVETO %s, got path flag %d\n", 
1674                 i == 0 ? "as first point" : "after PT_CLOSEFIGURE",
1675                 (INT)pPath->pFlags[i]);
1676             ret = FALSE;
1677             goto end;
1678         }
1679         switch(pPath->pFlags[i]) {
1680         case PT_MOVETO:
1681             TRACE("Got PT_MOVETO (%d, %d)\n",
1682                   pPath->pPoints[i].x, pPath->pPoints[i].y);
1683             if(nLinePts >= 2)
1684                 Polyline(hdc, pLinePts, nLinePts);
1685             nLinePts = 0;
1686             pLinePts[nLinePts++] = pPath->pPoints[i];
1687             break;
1688         case PT_LINETO:
1689         case (PT_LINETO | PT_CLOSEFIGURE):
1690             TRACE("Got PT_LINETO (%d, %d)\n",
1691                   pPath->pPoints[i].x, pPath->pPoints[i].y);
1692             pLinePts[nLinePts++] = pPath->pPoints[i];
1693             break;
1694         case PT_BEZIERTO:
1695             TRACE("Got PT_BEZIERTO\n");
1696             if(pPath->pFlags[i+1] != PT_BEZIERTO ||
1697                (pPath->pFlags[i+2] & ~PT_CLOSEFIGURE) != PT_BEZIERTO) {
1698                 ERR("Path didn't contain 3 successive PT_BEZIERTOs\n");
1699                 ret = FALSE;
1700                 goto end;
1701             } else {
1702                 INT nBzrPts, nMinAlloc;
1703                 POINT *pBzrPts = GDI_Bezier(&pPath->pPoints[i-1], 4, &nBzrPts);
1704                 /* Make sure we have allocated enough memory for the lines of 
1705                  * this bezier and the rest of the path, assuming we won't get
1706                  * another one (since we won't reallocate again then). */
1707                 nMinAlloc = nLinePts + (pPath->numEntriesUsed - i) + nBzrPts;
1708                 if(nAlloc < nMinAlloc)
1709                 {
1710                     nAlloc = nMinAlloc * 2;
1711                     pLinePts = HeapReAlloc(GetProcessHeap(), 0, pLinePts,
1712                                            nAlloc * sizeof(POINT));
1713                 }
1714                 memcpy(&pLinePts[nLinePts], &pBzrPts[1],
1715                        (nBzrPts - 1) * sizeof(POINT));
1716                 nLinePts += nBzrPts - 1;
1717                 HeapFree(GetProcessHeap(), 0, pBzrPts);
1718                 i += 2;
1719             }
1720             break;
1721         default:
1722             ERR("Got path flag %d\n", (INT)pPath->pFlags[i]);
1723             ret = FALSE;
1724             goto end;
1725         }
1726         if(pPath->pFlags[i] & PT_CLOSEFIGURE)
1727             pLinePts[nLinePts++] = pLinePts[0];
1728     }
1729     if(nLinePts >= 2)
1730         Polyline(hdc, pLinePts, nLinePts);
1731
1732  end:
1733     HeapFree(GetProcessHeap(), 0, pLinePts);
1734
1735     /* Restore the old mapping mode */
1736     SetMapMode(hdc, mapMode);
1737     SetWindowExtEx(hdc, szWindowExt.cx, szWindowExt.cy, NULL);
1738     SetWindowOrgEx(hdc, ptWindowOrg.x, ptWindowOrg.y, NULL);
1739     SetViewportExtEx(hdc, szViewportExt.cx, szViewportExt.cy, NULL);
1740     SetViewportOrgEx(hdc, ptViewportOrg.x, ptViewportOrg.y, NULL);
1741
1742     /* Go to GM_ADVANCED temporarily to restore the world transform */
1743     graphicsMode=GetGraphicsMode(hdc);
1744     SetGraphicsMode(hdc, GM_ADVANCED);
1745     SetWorldTransform(hdc, &xform);
1746     SetGraphicsMode(hdc, graphicsMode);
1747
1748     /* If we've moved the current point then get its new position
1749        which will be in device (MM_TEXT) co-ords, convert it to
1750        logical co-ords and re-set it.  This basically updates
1751        dc->CurPosX|Y so that their values are in the correct mapping
1752        mode.
1753     */
1754     if(i > 0) {
1755         POINT pt;
1756         GetCurrentPositionEx(hdc, &pt);
1757         DPtoLP(hdc, &pt, 1);
1758         MoveToEx(hdc, pt.x, pt.y, NULL);
1759     }
1760
1761     return ret;
1762 }
1763
1764 #define round(x) ((int)((x)>0?(x)+0.5:(x)-0.5))
1765
1766 static BOOL PATH_WidenPath(DC *dc)
1767 {
1768     INT i, j, numStrokes, penWidth, penWidthIn, penWidthOut, size, penStyle;
1769     BOOL ret = FALSE;
1770     GdiPath *pPath, *pNewPath, **pStrokes = NULL, *pUpPath, *pDownPath;
1771     EXTLOGPEN *elp;
1772     DWORD obj_type, joint, endcap, penType;
1773
1774     pPath = &dc->path;
1775
1776     PATH_FlattenPath(pPath);
1777
1778     size = GetObjectW( dc->hPen, 0, NULL );
1779     if (!size) {
1780         SetLastError(ERROR_CAN_NOT_COMPLETE);
1781         return FALSE;
1782     }
1783
1784     elp = HeapAlloc( GetProcessHeap(), 0, size );
1785     GetObjectW( dc->hPen, size, elp );
1786
1787     obj_type = GetObjectType(dc->hPen);
1788     if(obj_type == OBJ_PEN) {
1789         penStyle = ((LOGPEN*)elp)->lopnStyle;
1790     }
1791     else if(obj_type == OBJ_EXTPEN) {
1792         penStyle = elp->elpPenStyle;
1793     }
1794     else {
1795         SetLastError(ERROR_CAN_NOT_COMPLETE);
1796         HeapFree( GetProcessHeap(), 0, elp );
1797         return FALSE;
1798     }
1799
1800     penWidth = elp->elpWidth;
1801     HeapFree( GetProcessHeap(), 0, elp );
1802
1803     endcap = (PS_ENDCAP_MASK & penStyle);
1804     joint = (PS_JOIN_MASK & penStyle);
1805     penType = (PS_TYPE_MASK & penStyle);
1806
1807     /* The function cannot apply to cosmetic pens */
1808     if(obj_type == OBJ_EXTPEN && penType == PS_COSMETIC) {
1809         SetLastError(ERROR_CAN_NOT_COMPLETE);
1810         return FALSE;
1811     }
1812
1813     penWidthIn = penWidth / 2;
1814     penWidthOut = penWidth / 2;
1815     if(penWidthIn + penWidthOut < penWidth)
1816         penWidthOut++;
1817
1818     numStrokes = 0;
1819
1820     for(i = 0, j = 0; i < pPath->numEntriesUsed; i++, j++) {
1821         POINT point;
1822         if((i == 0 || (pPath->pFlags[i-1] & PT_CLOSEFIGURE)) &&
1823             (pPath->pFlags[i] != PT_MOVETO)) {
1824             ERR("Expected PT_MOVETO %s, got path flag %c\n",
1825                 i == 0 ? "as first point" : "after PT_CLOSEFIGURE",
1826                 pPath->pFlags[i]);
1827             return FALSE;
1828         }
1829         switch(pPath->pFlags[i]) {
1830             case PT_MOVETO:
1831                 if(numStrokes > 0) {
1832                     pStrokes[numStrokes - 1]->state = PATH_Closed;
1833                 }
1834                 numStrokes++;
1835                 j = 0;
1836                 if(numStrokes == 1)
1837                     pStrokes = HeapAlloc(GetProcessHeap(), 0, sizeof(GdiPath*));
1838                 else
1839                     pStrokes = HeapReAlloc(GetProcessHeap(), 0, pStrokes, numStrokes * sizeof(GdiPath*));
1840                 if(!pStrokes) return FALSE;
1841                 pStrokes[numStrokes - 1] = HeapAlloc(GetProcessHeap(), 0, sizeof(GdiPath));
1842                 PATH_InitGdiPath(pStrokes[numStrokes - 1]);
1843                 pStrokes[numStrokes - 1]->state = PATH_Open;
1844                 /* fall through */
1845             case PT_LINETO:
1846             case (PT_LINETO | PT_CLOSEFIGURE):
1847                 point.x = pPath->pPoints[i].x;
1848                 point.y = pPath->pPoints[i].y;
1849                 PATH_AddEntry(pStrokes[numStrokes - 1], &point, pPath->pFlags[i]);
1850                 break;
1851             case PT_BEZIERTO:
1852                 /* should never happen because of the FlattenPath call */
1853                 ERR("Should never happen\n");
1854                 break;
1855             default:
1856                 ERR("Got path flag %c\n", pPath->pFlags[i]);
1857                 return FALSE;
1858         }
1859     }
1860
1861     pNewPath = HeapAlloc(GetProcessHeap(), 0, sizeof(GdiPath));
1862     PATH_InitGdiPath(pNewPath);
1863     pNewPath->state = PATH_Open;
1864
1865     for(i = 0; i < numStrokes; i++) {
1866         pUpPath = HeapAlloc(GetProcessHeap(), 0, sizeof(GdiPath));
1867         PATH_InitGdiPath(pUpPath);
1868         pUpPath->state = PATH_Open;
1869         pDownPath = HeapAlloc(GetProcessHeap(), 0, sizeof(GdiPath));
1870         PATH_InitGdiPath(pDownPath);
1871         pDownPath->state = PATH_Open;
1872
1873         for(j = 0; j < pStrokes[i]->numEntriesUsed; j++) {
1874             /* Beginning or end of the path if not closed */
1875             if((!(pStrokes[i]->pFlags[pStrokes[i]->numEntriesUsed - 1] & PT_CLOSEFIGURE)) && (j == 0 || j == pStrokes[i]->numEntriesUsed - 1) ) {
1876                 /* Compute segment angle */
1877                 double xo, yo, xa, ya, theta;
1878                 POINT pt;
1879                 FLOAT_POINT corners[2];
1880                 if(j == 0) {
1881                     xo = pStrokes[i]->pPoints[j].x;
1882                     yo = pStrokes[i]->pPoints[j].y;
1883                     xa = pStrokes[i]->pPoints[1].x;
1884                     ya = pStrokes[i]->pPoints[1].y;
1885                 }
1886                 else {
1887                     xa = pStrokes[i]->pPoints[j - 1].x;
1888                     ya = pStrokes[i]->pPoints[j - 1].y;
1889                     xo = pStrokes[i]->pPoints[j].x;
1890                     yo = pStrokes[i]->pPoints[j].y;
1891                 }
1892                 theta = atan2( ya - yo, xa - xo );
1893                 switch(endcap) {
1894                     case PS_ENDCAP_SQUARE :
1895                         pt.x = xo + round(sqrt(2) * penWidthOut * cos(M_PI_4 + theta));
1896                         pt.y = yo + round(sqrt(2) * penWidthOut * sin(M_PI_4 + theta));
1897                         PATH_AddEntry(pUpPath, &pt, (j == 0 ? PT_MOVETO : PT_LINETO) );
1898                         pt.x = xo + round(sqrt(2) * penWidthIn * cos(- M_PI_4 + theta));
1899                         pt.y = yo + round(sqrt(2) * penWidthIn * sin(- M_PI_4 + theta));
1900                         PATH_AddEntry(pUpPath, &pt, PT_LINETO);
1901                         break;
1902                     case PS_ENDCAP_FLAT :
1903                         pt.x = xo + round( penWidthOut * cos(theta + M_PI_2) );
1904                         pt.y = yo + round( penWidthOut * sin(theta + M_PI_2) );
1905                         PATH_AddEntry(pUpPath, &pt, (j == 0 ? PT_MOVETO : PT_LINETO));
1906                         pt.x = xo - round( penWidthIn * cos(theta + M_PI_2) );
1907                         pt.y = yo - round( penWidthIn * sin(theta + M_PI_2) );
1908                         PATH_AddEntry(pUpPath, &pt, PT_LINETO);
1909                         break;
1910                     case PS_ENDCAP_ROUND :
1911                     default :
1912                         corners[0].x = xo - penWidthIn;
1913                         corners[0].y = yo - penWidthIn;
1914                         corners[1].x = xo + penWidthOut;
1915                         corners[1].y = yo + penWidthOut;
1916                         PATH_DoArcPart(pUpPath ,corners, theta + M_PI_2 , theta + 3 * M_PI_4, (j == 0 ? PT_MOVETO : FALSE));
1917                         PATH_DoArcPart(pUpPath ,corners, theta + 3 * M_PI_4 , theta + M_PI, FALSE);
1918                         PATH_DoArcPart(pUpPath ,corners, theta + M_PI, theta +  5 * M_PI_4, FALSE);
1919                         PATH_DoArcPart(pUpPath ,corners, theta + 5 * M_PI_4 , theta + 3 * M_PI_2, FALSE);
1920                         break;
1921                 }
1922             }
1923             /* Corpse of the path */
1924             else {
1925                 /* Compute angle */
1926                 INT previous, next;
1927                 double xa, ya, xb, yb, xo, yo;
1928                 double alpha, theta, miterWidth;
1929                 DWORD _joint = joint;
1930                 POINT pt;
1931                 GdiPath *pInsidePath, *pOutsidePath;
1932                 if(j > 0 && j < pStrokes[i]->numEntriesUsed - 1) {
1933                     previous = j - 1;
1934                     next = j + 1;
1935                 }
1936                 else if (j == 0) {
1937                     previous = pStrokes[i]->numEntriesUsed - 1;
1938                     next = j + 1;
1939                 }
1940                 else {
1941                     previous = j - 1;
1942                     next = 0;
1943                 }
1944                 xo = pStrokes[i]->pPoints[j].x;
1945                 yo = pStrokes[i]->pPoints[j].y;
1946                 xa = pStrokes[i]->pPoints[previous].x;
1947                 ya = pStrokes[i]->pPoints[previous].y;
1948                 xb = pStrokes[i]->pPoints[next].x;
1949                 yb = pStrokes[i]->pPoints[next].y;
1950                 theta = atan2( yo - ya, xo - xa );
1951                 alpha = atan2( yb - yo, xb - xo ) - theta;
1952                 if (alpha > 0) alpha -= M_PI;
1953                 else alpha += M_PI;
1954                 if(_joint == PS_JOIN_MITER && dc->miterLimit < fabs(1 / sin(alpha/2))) {
1955                     _joint = PS_JOIN_BEVEL;
1956                 }
1957                 if(alpha > 0) {
1958                     pInsidePath = pUpPath;
1959                     pOutsidePath = pDownPath;
1960                 }
1961                 else if(alpha < 0) {
1962                     pInsidePath = pDownPath;
1963                     pOutsidePath = pUpPath;
1964                 }
1965                 else {
1966                     continue;
1967                 }
1968                 /* Inside angle points */
1969                 if(alpha > 0) {
1970                     pt.x = xo - round( penWidthIn * cos(theta + M_PI_2) );
1971                     pt.y = yo - round( penWidthIn * sin(theta + M_PI_2) );
1972                 }
1973                 else {
1974                     pt.x = xo + round( penWidthIn * cos(theta + M_PI_2) );
1975                     pt.y = yo + round( penWidthIn * sin(theta + M_PI_2) );
1976                 }
1977                 PATH_AddEntry(pInsidePath, &pt, PT_LINETO);
1978                 if(alpha > 0) {
1979                     pt.x = xo + round( penWidthIn * cos(M_PI_2 + alpha + theta) );
1980                     pt.y = yo + round( penWidthIn * sin(M_PI_2 + alpha + theta) );
1981                 }
1982                 else {
1983                     pt.x = xo - round( penWidthIn * cos(M_PI_2 + alpha + theta) );
1984                     pt.y = yo - round( penWidthIn * sin(M_PI_2 + alpha + theta) );
1985                 }
1986                 PATH_AddEntry(pInsidePath, &pt, PT_LINETO);
1987                 /* Outside angle point */
1988                 switch(_joint) {
1989                      case PS_JOIN_MITER :
1990                         miterWidth = fabs(penWidthOut / cos(M_PI_2 - fabs(alpha) / 2));
1991                         pt.x = xo + round( miterWidth * cos(theta + alpha / 2) );
1992                         pt.y = yo + round( miterWidth * sin(theta + alpha / 2) );
1993                         PATH_AddEntry(pOutsidePath, &pt, PT_LINETO);
1994                         break;
1995                     case PS_JOIN_BEVEL :
1996                         if(alpha > 0) {
1997                             pt.x = xo + round( penWidthOut * cos(theta + M_PI_2) );
1998                             pt.y = yo + round( penWidthOut * sin(theta + M_PI_2) );
1999                         }
2000                         else {
2001                             pt.x = xo - round( penWidthOut * cos(theta + M_PI_2) );
2002                             pt.y = yo - round( penWidthOut * sin(theta + M_PI_2) );
2003                         }
2004                         PATH_AddEntry(pOutsidePath, &pt, PT_LINETO);
2005                         if(alpha > 0) {
2006                             pt.x = xo - round( penWidthOut * cos(M_PI_2 + alpha + theta) );
2007                             pt.y = yo - round( penWidthOut * sin(M_PI_2 + alpha + theta) );
2008                         }
2009                         else {
2010                             pt.x = xo + round( penWidthOut * cos(M_PI_2 + alpha + theta) );
2011                             pt.y = yo + round( penWidthOut * sin(M_PI_2 + alpha + theta) );
2012                         }
2013                         PATH_AddEntry(pOutsidePath, &pt, PT_LINETO);
2014                         break;
2015                     case PS_JOIN_ROUND :
2016                     default :
2017                         if(alpha > 0) {
2018                             pt.x = xo + round( penWidthOut * cos(theta + M_PI_2) );
2019                             pt.y = yo + round( penWidthOut * sin(theta + M_PI_2) );
2020                         }
2021                         else {
2022                             pt.x = xo - round( penWidthOut * cos(theta + M_PI_2) );
2023                             pt.y = yo - round( penWidthOut * sin(theta + M_PI_2) );
2024                         }
2025                         PATH_AddEntry(pOutsidePath, &pt, PT_BEZIERTO);
2026                         pt.x = xo + round( penWidthOut * cos(theta + alpha / 2) );
2027                         pt.y = yo + round( penWidthOut * sin(theta + alpha / 2) );
2028                         PATH_AddEntry(pOutsidePath, &pt, PT_BEZIERTO);
2029                         if(alpha > 0) {
2030                             pt.x = xo - round( penWidthOut * cos(M_PI_2 + alpha + theta) );
2031                             pt.y = yo - round( penWidthOut * sin(M_PI_2 + alpha + theta) );
2032                         }
2033                         else {
2034                             pt.x = xo + round( penWidthOut * cos(M_PI_2 + alpha + theta) );
2035                             pt.y = yo + round( penWidthOut * sin(M_PI_2 + alpha + theta) );
2036                         }
2037                         PATH_AddEntry(pOutsidePath, &pt, PT_BEZIERTO);
2038                         break;
2039                 }
2040             }
2041         }
2042         for(j = 0; j < pUpPath->numEntriesUsed; j++) {
2043             POINT pt;
2044             pt.x = pUpPath->pPoints[j].x;
2045             pt.y = pUpPath->pPoints[j].y;
2046             PATH_AddEntry(pNewPath, &pt, (j == 0 ? PT_MOVETO : PT_LINETO));
2047         }
2048         for(j = 0; j < pDownPath->numEntriesUsed; j++) {
2049             POINT pt;
2050             pt.x = pDownPath->pPoints[pDownPath->numEntriesUsed - j - 1].x;
2051             pt.y = pDownPath->pPoints[pDownPath->numEntriesUsed - j - 1].y;
2052             PATH_AddEntry(pNewPath, &pt, ( (j == 0 && (pStrokes[i]->pFlags[pStrokes[i]->numEntriesUsed - 1] & PT_CLOSEFIGURE)) ? PT_MOVETO : PT_LINETO));
2053         }
2054
2055         PATH_DestroyGdiPath(pStrokes[i]);
2056         HeapFree(GetProcessHeap(), 0, pStrokes[i]);
2057         PATH_DestroyGdiPath(pUpPath);
2058         HeapFree(GetProcessHeap(), 0, pUpPath);
2059         PATH_DestroyGdiPath(pDownPath);
2060         HeapFree(GetProcessHeap(), 0, pDownPath);
2061     }
2062     HeapFree(GetProcessHeap(), 0, pStrokes);
2063
2064     pNewPath->state = PATH_Closed;
2065     if (!(ret = PATH_AssignGdiPath(pPath, pNewPath)))
2066         ERR("Assign path failed\n");
2067     PATH_DestroyGdiPath(pNewPath);
2068     HeapFree(GetProcessHeap(), 0, pNewPath);
2069     return ret;
2070 }
2071
2072
2073 /*******************************************************************
2074  *      StrokeAndFillPath [GDI32.@]
2075  *
2076  *
2077  */
2078 BOOL WINAPI StrokeAndFillPath(HDC hdc)
2079 {
2080     BOOL ret = FALSE;
2081     DC *dc = get_dc_ptr( hdc );
2082
2083     if (dc)
2084     {
2085         PHYSDEV physdev = GET_DC_PHYSDEV( dc, pStrokeAndFillPath );
2086         ret = physdev->funcs->pStrokeAndFillPath( physdev );
2087         release_dc_ptr( dc );
2088     }
2089     return ret;
2090 }
2091
2092
2093 /*******************************************************************
2094  *      StrokePath [GDI32.@]
2095  *
2096  *
2097  */
2098 BOOL WINAPI StrokePath(HDC hdc)
2099 {
2100     BOOL ret = FALSE;
2101     DC *dc = get_dc_ptr( hdc );
2102
2103     if (dc)
2104     {
2105         PHYSDEV physdev = GET_DC_PHYSDEV( dc, pStrokePath );
2106         ret = physdev->funcs->pStrokePath( physdev );
2107         release_dc_ptr( dc );
2108     }
2109     return ret;
2110 }
2111
2112
2113 /*******************************************************************
2114  *      WidenPath [GDI32.@]
2115  *
2116  *
2117  */
2118 BOOL WINAPI WidenPath(HDC hdc)
2119 {
2120     BOOL ret = FALSE;
2121     DC *dc = get_dc_ptr( hdc );
2122
2123     if (dc)
2124     {
2125         PHYSDEV physdev = GET_DC_PHYSDEV( dc, pWidenPath );
2126         ret = physdev->funcs->pWidenPath( physdev );
2127         release_dc_ptr( dc );
2128     }
2129     return ret;
2130 }
2131
2132
2133 /***********************************************************************
2134  *           null driver fallback implementations
2135  */
2136
2137 BOOL nulldrv_BeginPath( PHYSDEV dev )
2138 {
2139     DC *dc = get_nulldrv_dc( dev );
2140
2141     if (!path_driver.pCreateDC( &dc->physDev, NULL, NULL, NULL, NULL )) return FALSE;
2142     PATH_EmptyPath(&dc->path);
2143     dc->path.newStroke = TRUE;
2144     dc->path.state = PATH_Open;
2145     return TRUE;
2146 }
2147
2148 BOOL nulldrv_EndPath( PHYSDEV dev )
2149 {
2150     SetLastError( ERROR_CAN_NOT_COMPLETE );
2151     return FALSE;
2152 }
2153
2154 BOOL nulldrv_AbortPath( PHYSDEV dev )
2155 {
2156     DC *dc = get_nulldrv_dc( dev );
2157
2158     PATH_EmptyPath( &dc->path );
2159     return TRUE;
2160 }
2161
2162 BOOL nulldrv_CloseFigure( PHYSDEV dev )
2163 {
2164     SetLastError( ERROR_CAN_NOT_COMPLETE );
2165     return FALSE;
2166 }
2167
2168 BOOL nulldrv_SelectClipPath( PHYSDEV dev, INT mode )
2169 {
2170     BOOL ret;
2171     HRGN hrgn;
2172     DC *dc = get_nulldrv_dc( dev );
2173
2174     if (dc->path.state != PATH_Closed)
2175     {
2176         SetLastError( ERROR_CAN_NOT_COMPLETE );
2177         return FALSE;
2178     }
2179     if (!PATH_PathToRegion( &dc->path, GetPolyFillMode(dev->hdc), &hrgn )) return FALSE;
2180     ret = ExtSelectClipRgn( dev->hdc, hrgn, mode ) != ERROR;
2181     if (ret) PATH_EmptyPath( &dc->path );
2182     /* FIXME: Should this function delete the path even if it failed? */
2183     DeleteObject( hrgn );
2184     return ret;
2185 }
2186
2187 BOOL nulldrv_FillPath( PHYSDEV dev )
2188 {
2189     DC *dc = get_nulldrv_dc( dev );
2190
2191     if (dc->path.state != PATH_Closed)
2192     {
2193         SetLastError( ERROR_CAN_NOT_COMPLETE );
2194         return FALSE;
2195     }
2196     if (!PATH_FillPath( dev->hdc, &dc->path )) return FALSE;
2197     /* FIXME: Should the path be emptied even if conversion failed? */
2198     PATH_EmptyPath( &dc->path );
2199     return TRUE;
2200 }
2201
2202 BOOL nulldrv_StrokeAndFillPath( PHYSDEV dev )
2203 {
2204     DC *dc = get_nulldrv_dc( dev );
2205
2206     if (dc->path.state != PATH_Closed)
2207     {
2208         SetLastError( ERROR_CAN_NOT_COMPLETE );
2209         return FALSE;
2210     }
2211     if (!PATH_FillPath( dev->hdc, &dc->path )) return FALSE;
2212     if (!PATH_StrokePath( dev->hdc, &dc->path )) return FALSE;
2213     PATH_EmptyPath( &dc->path );
2214     return TRUE;
2215 }
2216
2217 BOOL nulldrv_StrokePath( PHYSDEV dev )
2218 {
2219     DC *dc = get_nulldrv_dc( dev );
2220
2221     if (dc->path.state != PATH_Closed)
2222     {
2223         SetLastError( ERROR_CAN_NOT_COMPLETE );
2224         return FALSE;
2225     }
2226     if (!PATH_StrokePath( dev->hdc, &dc->path )) return FALSE;
2227     PATH_EmptyPath( &dc->path );
2228     return TRUE;
2229 }
2230
2231 BOOL nulldrv_FlattenPath( PHYSDEV dev )
2232 {
2233     DC *dc = get_nulldrv_dc( dev );
2234
2235     if (dc->path.state != PATH_Closed)
2236     {
2237         SetLastError( ERROR_CAN_NOT_COMPLETE );
2238         return FALSE;
2239     }
2240     return PATH_FlattenPath( &dc->path );
2241 }
2242
2243 BOOL nulldrv_WidenPath( PHYSDEV dev )
2244 {
2245     DC *dc = get_nulldrv_dc( dev );
2246
2247     if (dc->path.state != PATH_Closed)
2248     {
2249         SetLastError( ERROR_CAN_NOT_COMPLETE );
2250         return FALSE;
2251     }
2252     return PATH_WidenPath( dc );
2253 }
2254
2255 const struct gdi_dc_funcs path_driver =
2256 {
2257     NULL,                               /* pAbortDoc */
2258     pathdrv_AbortPath,                  /* pAbortPath */
2259     NULL,                               /* pAlphaBlend */
2260     pathdrv_AngleArc,                   /* pAngleArc */
2261     pathdrv_Arc,                        /* pArc */
2262     pathdrv_ArcTo,                      /* pArcTo */
2263     pathdrv_BeginPath,                  /* pBeginPath */
2264     NULL,                               /* pBlendImage */
2265     NULL,                               /* pChoosePixelFormat */
2266     pathdrv_Chord,                      /* pChord */
2267     pathdrv_CloseFigure,                /* pCloseFigure */
2268     NULL,                               /* pCreateBitmap */
2269     NULL,                               /* pCreateCompatibleDC */
2270     pathdrv_CreateDC,                   /* pCreateDC */
2271     NULL,                               /* pCreateDIBSection */
2272     NULL,                               /* pDeleteBitmap */
2273     pathdrv_DeleteDC,                   /* pDeleteDC */
2274     NULL,                               /* pDeleteObject */
2275     NULL,                               /* pDescribePixelFormat */
2276     NULL,                               /* pDeviceCapabilities */
2277     pathdrv_Ellipse,                    /* pEllipse */
2278     NULL,                               /* pEndDoc */
2279     NULL,                               /* pEndPage */
2280     pathdrv_EndPath,                    /* pEndPath */
2281     NULL,                               /* pEnumFonts */
2282     NULL,                               /* pEnumICMProfiles */
2283     NULL,                               /* pExcludeClipRect */
2284     NULL,                               /* pExtDeviceMode */
2285     NULL,                               /* pExtEscape */
2286     NULL,                               /* pExtFloodFill */
2287     NULL,                               /* pExtSelectClipRgn */
2288     pathdrv_ExtTextOut,                 /* pExtTextOut */
2289     NULL,                               /* pFillPath */
2290     NULL,                               /* pFillRgn */
2291     NULL,                               /* pFlattenPath */
2292     NULL,                               /* pFontIsLinked */
2293     NULL,                               /* pFrameRgn */
2294     NULL,                               /* pGdiComment */
2295     NULL,                               /* pGdiRealizationInfo */
2296     NULL,                               /* pGetCharABCWidths */
2297     NULL,                               /* pGetCharABCWidthsI */
2298     NULL,                               /* pGetCharWidth */
2299     NULL,                               /* pGetDeviceCaps */
2300     NULL,                               /* pGetDeviceGammaRamp */
2301     NULL,                               /* pGetFontData */
2302     NULL,                               /* pGetFontUnicodeRanges */
2303     NULL,                               /* pGetGlyphIndices */
2304     NULL,                               /* pGetGlyphOutline */
2305     NULL,                               /* pGetICMProfile */
2306     NULL,                               /* pGetImage */
2307     NULL,                               /* pGetKerningPairs */
2308     NULL,                               /* pGetNearestColor */
2309     NULL,                               /* pGetOutlineTextMetrics */
2310     NULL,                               /* pGetPixel */
2311     NULL,                               /* pGetPixelFormat */
2312     NULL,                               /* pGetSystemPaletteEntries */
2313     NULL,                               /* pGetTextCharsetInfo */
2314     NULL,                               /* pGetTextExtentExPoint */
2315     NULL,                               /* pGetTextExtentExPointI */
2316     NULL,                               /* pGetTextFace */
2317     NULL,                               /* pGetTextMetrics */
2318     NULL,                               /* pIntersectClipRect */
2319     NULL,                               /* pInvertRgn */
2320     pathdrv_LineTo,                     /* pLineTo */
2321     NULL,                               /* pModifyWorldTransform */
2322     pathdrv_MoveTo,                     /* pMoveTo */
2323     NULL,                               /* pOffsetClipRgn */
2324     NULL,                               /* pOffsetViewportOrg */
2325     NULL,                               /* pOffsetWindowOrg */
2326     NULL,                               /* pPaintRgn */
2327     NULL,                               /* pPatBlt */
2328     pathdrv_Pie,                        /* pPie */
2329     pathdrv_PolyBezier,                 /* pPolyBezier */
2330     pathdrv_PolyBezierTo,               /* pPolyBezierTo */
2331     pathdrv_PolyDraw,                   /* pPolyDraw */
2332     pathdrv_PolyPolygon,                /* pPolyPolygon */
2333     pathdrv_PolyPolyline,               /* pPolyPolyline */
2334     pathdrv_Polygon,                    /* pPolygon */
2335     pathdrv_Polyline,                   /* pPolyline */
2336     pathdrv_PolylineTo,                 /* pPolylineTo */
2337     NULL,                               /* pPutImage */
2338     NULL,                               /* pRealizeDefaultPalette */
2339     NULL,                               /* pRealizePalette */
2340     pathdrv_Rectangle,                  /* pRectangle */
2341     NULL,                               /* pResetDC */
2342     NULL,                               /* pRestoreDC */
2343     pathdrv_RoundRect,                  /* pRoundRect */
2344     NULL,                               /* pSaveDC */
2345     NULL,                               /* pScaleViewportExt */
2346     NULL,                               /* pScaleWindowExt */
2347     NULL,                               /* pSelectBitmap */
2348     NULL,                               /* pSelectBrush */
2349     NULL,                               /* pSelectClipPath */
2350     NULL,                               /* pSelectFont */
2351     NULL,                               /* pSelectPalette */
2352     NULL,                               /* pSelectPen */
2353     NULL,                               /* pSetArcDirection */
2354     NULL,                               /* pSetBkColor */
2355     NULL,                               /* pSetBkMode */
2356     NULL,                               /* pSetDCBrushColor */
2357     NULL,                               /* pSetDCPenColor */
2358     NULL,                               /* pSetDIBColorTable */
2359     NULL,                               /* pSetDIBitsToDevice */
2360     NULL,                               /* pSetDeviceClipping */
2361     NULL,                               /* pSetDeviceGammaRamp */
2362     NULL,                               /* pSetLayout */
2363     NULL,                               /* pSetMapMode */
2364     NULL,                               /* pSetMapperFlags */
2365     NULL,                               /* pSetPixel */
2366     NULL,                               /* pSetPixelFormat */
2367     NULL,                               /* pSetPolyFillMode */
2368     NULL,                               /* pSetROP2 */
2369     NULL,                               /* pSetRelAbs */
2370     NULL,                               /* pSetStretchBltMode */
2371     NULL,                               /* pSetTextAlign */
2372     NULL,                               /* pSetTextCharacterExtra */
2373     NULL,                               /* pSetTextColor */
2374     NULL,                               /* pSetTextJustification */
2375     NULL,                               /* pSetViewportExt */
2376     NULL,                               /* pSetViewportOrg */
2377     NULL,                               /* pSetWindowExt */
2378     NULL,                               /* pSetWindowOrg */
2379     NULL,                               /* pSetWorldTransform */
2380     NULL,                               /* pStartDoc */
2381     NULL,                               /* pStartPage */
2382     NULL,                               /* pStretchBlt */
2383     NULL,                               /* pStretchDIBits */
2384     NULL,                               /* pStrokeAndFillPath */
2385     NULL,                               /* pStrokePath */
2386     NULL,                               /* pSwapBuffers */
2387     NULL,                               /* pUnrealizePalette */
2388     NULL,                               /* pWidenPath */
2389     /* OpenGL not supported */
2390 };