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