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