Release 980503
[wine] / graphics / x11drv / graphics.c
1 /*
2  * X11 graphics driver graphics functions
3  *
4  * Copyright 1993,1994 Alexandre Julliard
5  */
6
7 #include <math.h>
8 #ifdef HAVE_FLOAT_H
9 # include <float.h>
10 #endif
11 #include <stdlib.h>
12 #include "ts_xlib.h"
13 #include "ts_xutil.h"
14 #include <X11/Intrinsic.h>
15 #ifndef PI
16 #define PI M_PI
17 #endif
18 #include <string.h>
19
20 #include "x11drv.h"
21 #include "bitmap.h"
22 #include "gdi.h"
23 #include "graphics.h"
24 #include "dc.h"
25 #include "bitmap.h"
26 #include "callback.h"
27 #include "metafile.h"
28 #include "palette.h"
29 #include "color.h"
30 #include "region.h"
31 #include "struct32.h"
32 #include "debug.h"
33 #include "xmalloc.h"
34
35
36 /**********************************************************************
37  *           X11DRV_MoveToEx
38  */
39 BOOL32
40 X11DRV_MoveToEx(DC *dc,INT32 x,INT32 y,LPPOINT32 pt) {
41     if (pt)
42     {
43         pt->x = dc->w.CursPosX;
44         pt->y = dc->w.CursPosY;
45     }
46     dc->w.CursPosX = x;
47     dc->w.CursPosY = y;
48     return TRUE;
49 }
50
51 /***********************************************************************
52  *           X11DRV_LineTo
53  */
54 BOOL32
55 X11DRV_LineTo( DC *dc, INT32 x, INT32 y )
56 {
57     if (DC_SetupGCForPen( dc ))
58         TSXDrawLine(display, dc->u.x.drawable, dc->u.x.gc, 
59                   dc->w.DCOrgX + XLPTODP( dc, dc->w.CursPosX ),
60                   dc->w.DCOrgY + YLPTODP( dc, dc->w.CursPosY ),
61                   dc->w.DCOrgX + XLPTODP( dc, x ),
62                   dc->w.DCOrgY + YLPTODP( dc, y ) );
63     dc->w.CursPosX = x;
64     dc->w.CursPosY = y;
65     return TRUE;
66 }
67
68
69
70 /***********************************************************************
71  *           GRAPH_DrawArc
72  *
73  * Helper functions for Arc(), Chord() and Pie().
74  * 'lines' is the number of lines to draw: 0 for Arc, 1 for Chord, 2 for Pie.
75  */
76 static BOOL32
77 X11DRV_DrawArc( DC *dc, INT32 left, INT32 top, INT32 right,
78                 INT32 bottom, INT32 xstart, INT32 ystart,
79                 INT32 xend, INT32 yend, INT32 lines )
80 {
81     INT32 xcenter, ycenter, istart_angle, idiff_angle, tmp;
82     double start_angle, end_angle;
83     XPoint points[3];
84
85     left   = XLPTODP( dc, left );
86     top    = YLPTODP( dc, top );
87     right  = XLPTODP( dc, right );
88     bottom = YLPTODP( dc, bottom );
89     xstart = XLPTODP( dc, xstart );
90     ystart = YLPTODP( dc, ystart );
91     xend   = XLPTODP( dc, xend );
92     yend   = YLPTODP( dc, yend );
93
94     if ((left == right) || (top == bottom)) return FALSE;
95
96     if (left > right) { tmp=left; left=right; right=tmp; }
97     if (top > bottom) { tmp=top; top=bottom; bottom=tmp; } 
98     xcenter = (right + left) / 2;
99     ycenter = (bottom + top) / 2;
100     start_angle = atan2( (double)(ycenter-ystart)*(right-left),
101                          (double)(xstart-xcenter)*(bottom-top) );
102     end_angle   = atan2( (double)(ycenter-yend)*(right-left),
103                          (double)(xend-xcenter)*(bottom-top) );
104     if ((xstart==xend)&&(ystart==yend))
105       { /* A lazy program delivers xstart=xend=ystart=yend=0) */
106         start_angle = 0;
107         end_angle = 2* PI;
108       }
109     else /* notorious cases */
110       if ((start_angle == PI)&&( end_angle <0))
111         start_angle = - PI;
112     else
113       if ((end_angle == PI)&&( start_angle <0))
114         end_angle = - PI;
115     istart_angle = (INT32)(start_angle * 180 * 64 / PI);
116     idiff_angle  = (INT32)((end_angle - start_angle) * 180 * 64 / PI );
117     if (idiff_angle <= 0) idiff_angle += 360 * 64;
118
119       /* Fill arc with brush if Chord() or Pie() */
120
121     if ((lines > 0) && DC_SetupGCForBrush( dc ))
122     {
123         TSXSetArcMode( display, dc->u.x.gc, (lines==1) ? ArcChord : ArcPieSlice);
124         TSXFillArc( display, dc->u.x.drawable, dc->u.x.gc,
125                  dc->w.DCOrgX + left, dc->w.DCOrgY + top,
126                  right-left-1, bottom-top-1, istart_angle, idiff_angle );
127     }
128
129       /* Draw arc and lines */
130
131     if (!DC_SetupGCForPen( dc )) return TRUE;
132     TSXDrawArc( display, dc->u.x.drawable, dc->u.x.gc,
133               dc->w.DCOrgX + left, dc->w.DCOrgY + top,
134               right-left-1, bottom-top-1, istart_angle, idiff_angle );
135     if (!lines) return TRUE;
136
137     points[0].x = dc->w.DCOrgX + xcenter + (int)(cos(start_angle) * (right-left) / 2);
138     points[0].y = dc->w.DCOrgY + ycenter - (int)(sin(start_angle) * (bottom-top) / 2);
139     points[1].x = dc->w.DCOrgX + xcenter + (int)(cos(end_angle) * (right-left) / 2);
140     points[1].y = dc->w.DCOrgY + ycenter - (int)(sin(end_angle) * (bottom-top) / 2);
141     if (lines == 2)
142     {
143         points[2] = points[1];
144         points[1].x = dc->w.DCOrgX + xcenter;
145         points[1].y = dc->w.DCOrgY + ycenter;
146     }
147     TSXDrawLines( display, dc->u.x.drawable, dc->u.x.gc,
148                 points, lines+1, CoordModeOrigin );
149     return TRUE;
150 }
151
152
153 /***********************************************************************
154  *           X11DRV_Arc
155  */
156 BOOL32
157 X11DRV_Arc( DC *dc, INT32 left, INT32 top, INT32 right, INT32 bottom,
158             INT32 xstart, INT32 ystart, INT32 xend, INT32 yend )
159 {
160     return X11DRV_DrawArc( dc, left, top, right, bottom,
161                            xstart, ystart, xend, yend, 0 );
162 }
163
164
165 /***********************************************************************
166  *           X11DRV_Pie
167  */
168 BOOL32
169 X11DRV_Pie( DC *dc, INT32 left, INT32 top, INT32 right, INT32 bottom,
170             INT32 xstart, INT32 ystart, INT32 xend, INT32 yend )
171 {
172     return X11DRV_DrawArc( dc, left, top, right, bottom,
173                            xstart, ystart, xend, yend, 2 );
174 }
175
176 /***********************************************************************
177  *           X11DRV_Chord
178  */
179 BOOL32
180 X11DRV_Chord( DC *dc, INT32 left, INT32 top, INT32 right, INT32 bottom,
181               INT32 xstart, INT32 ystart, INT32 xend, INT32 yend )
182 {
183     return X11DRV_DrawArc( dc, left, top, right, bottom,
184                            xstart, ystart, xend, yend, 1 );
185 }
186
187
188 /***********************************************************************
189  *           X11DRV_Ellipse
190  */
191 BOOL32
192 X11DRV_Ellipse( DC *dc, INT32 left, INT32 top, INT32 right, INT32 bottom )
193 {
194     left   = XLPTODP( dc, left );
195     top    = YLPTODP( dc, top );
196     right  = XLPTODP( dc, right );
197     bottom = YLPTODP( dc, bottom );
198     if ((left == right) || (top == bottom)) return FALSE;
199
200     if (right < left) { INT32 tmp = right; right = left; left = tmp; }
201     if (bottom < top) { INT32 tmp = bottom; bottom = top; top = tmp; }
202     
203     if ((dc->u.x.pen.style == PS_INSIDEFRAME) &&
204         (dc->u.x.pen.width < right-left-1) &&
205         (dc->u.x.pen.width < bottom-top-1))
206     {
207         left   += dc->u.x.pen.width / 2;
208         right  -= (dc->u.x.pen.width + 1) / 2;
209         top    += dc->u.x.pen.width / 2;
210         bottom -= (dc->u.x.pen.width + 1) / 2;
211     }
212
213     if (DC_SetupGCForBrush( dc ))
214         TSXFillArc( display, dc->u.x.drawable, dc->u.x.gc,
215                   dc->w.DCOrgX + left, dc->w.DCOrgY + top,
216                   right-left-1, bottom-top-1, 0, 360*64 );
217     if (DC_SetupGCForPen( dc ))
218         TSXDrawArc( display, dc->u.x.drawable, dc->u.x.gc,
219                   dc->w.DCOrgX + left, dc->w.DCOrgY + top,
220                   right-left-1, bottom-top-1, 0, 360*64 );
221     return TRUE;
222 }
223
224
225 /***********************************************************************
226  *           X11DRV_Rectangle
227  */
228 BOOL32
229 X11DRV_Rectangle(DC *dc, INT32 left, INT32 top, INT32 right, INT32 bottom)
230 {
231     INT32 width;
232     left   = XLPTODP( dc, left );
233     top    = YLPTODP( dc, top );
234     right  = XLPTODP( dc, right );
235     bottom = YLPTODP( dc, bottom );
236
237     if (right < left) { INT32 tmp = right; right = left; left = tmp; }
238     if (bottom < top) { INT32 tmp = bottom; bottom = top; top = tmp; }
239
240     if ((left == right) || (top == bottom))
241     {
242 #if 0
243         if (DC_SetupGCForPen( dc ))
244             TSXDrawLine(display, dc->u.x.drawable, dc->u.x.gc, 
245                   dc->w.DCOrgX + left,
246                   dc->w.DCOrgY + top,
247                   dc->w.DCOrgX + right,
248                   dc->w.DCOrgY + bottom);
249 #endif
250         return TRUE;
251     }
252     width = dc->u.x.pen.width;
253     if (!width) width = 1;
254     if(dc->u.x.pen.style == PS_NULL) width = 0;
255
256     if ((dc->u.x.pen.style == PS_INSIDEFRAME) &&
257         (width < right-left) && (width < bottom-top))
258     {
259         left   += width / 2;
260         right  -= (width + 1) / 2;
261         top    += width / 2;
262         bottom -= (width + 1) / 2;
263     }
264
265     if ((right > left + width) && (bottom > top + width))
266     {
267         if (DC_SetupGCForBrush( dc ))
268             TSXFillRectangle( display, dc->u.x.drawable, dc->u.x.gc,
269                             dc->w.DCOrgX + left + (width + 1) / 2,
270                             dc->w.DCOrgY + top + (width + 1) / 2,
271                             right-left-width-1, bottom-top-width-1);
272     }
273     if (DC_SetupGCForPen( dc ))
274         TSXDrawRectangle( display, dc->u.x.drawable, dc->u.x.gc,
275                         dc->w.DCOrgX + left, dc->w.DCOrgY + top,
276                         right-left-1, bottom-top-1 );
277     return TRUE;
278 }
279
280 /***********************************************************************
281  *           X11DRV_RoundRect
282  */
283 BOOL32
284 X11DRV_RoundRect( DC *dc, INT32 left, INT32 top, INT32 right,
285                   INT32 bottom, INT32 ell_width, INT32 ell_height )
286 {
287     TRACE(graphics, "(%d %d %d %d  %d %d\n", 
288         left, top, right, bottom, ell_width, ell_height);
289
290     left   = XLPTODP( dc, left );
291     top    = YLPTODP( dc, top );
292     right  = XLPTODP( dc, right );
293     bottom = YLPTODP( dc, bottom );
294     ell_width  = abs( ell_width * dc->vportExtX / dc->wndExtX );
295     ell_height = abs( ell_height * dc->vportExtY / dc->wndExtY );
296
297     /* Fix the coordinates */
298
299     if (right < left) { INT32 tmp = right; right = left; left = tmp; }
300     if (bottom < top) { INT32 tmp = bottom; bottom = top; top = tmp; }
301     if (ell_width > right - left) ell_width = right - left;
302     if (ell_height > bottom - top) ell_height = bottom - top;
303
304     if (DC_SetupGCForBrush( dc ))
305     {
306         if (ell_width && ell_height)
307         {
308             TSXFillArc( display, dc->u.x.drawable, dc->u.x.gc,
309                       dc->w.DCOrgX + left, dc->w.DCOrgY + top,
310                       ell_width, ell_height, 90 * 64, 90 * 64 );
311             TSXFillArc( display, dc->u.x.drawable, dc->u.x.gc,
312                       dc->w.DCOrgX + left, dc->w.DCOrgY + bottom - ell_height,
313                       ell_width, ell_height, 180 * 64, 90 * 64 );
314             TSXFillArc( display, dc->u.x.drawable, dc->u.x.gc,
315                       dc->w.DCOrgX + right - ell_width,
316                       dc->w.DCOrgY + bottom - ell_height,
317                       ell_width, ell_height, 270 * 64, 90 * 64 );
318             TSXFillArc( display, dc->u.x.drawable, dc->u.x.gc,
319                       dc->w.DCOrgX + right - ell_width, dc->w.DCOrgY + top,
320                       ell_width, ell_height, 0, 90 * 64 );
321         }
322         if (ell_width < right - left)
323         {
324             TSXFillRectangle( display, dc->u.x.drawable, dc->u.x.gc,
325                             dc->w.DCOrgX + left + ell_width / 2,
326                             dc->w.DCOrgY + top,
327                             right - left - ell_width, ell_height / 2 );
328             TSXFillRectangle( display, dc->u.x.drawable, dc->u.x.gc,
329                             dc->w.DCOrgX + left + ell_width / 2,
330                             dc->w.DCOrgY + bottom - (ell_height+1) / 2,
331                             right - left - ell_width, (ell_height+1) / 2 );
332         }
333         if  (ell_height < bottom - top)
334         {
335             TSXFillRectangle( display, dc->u.x.drawable, dc->u.x.gc,
336                             dc->w.DCOrgX + left,
337                             dc->w.DCOrgY + top + ell_height / 2,
338                             right - left, bottom - top - ell_height );
339         }
340     }
341     if (DC_SetupGCForPen(dc))
342     {
343         if (ell_width && ell_height)
344         {
345             TSXDrawArc( display, dc->u.x.drawable, dc->u.x.gc,
346                       dc->w.DCOrgX + left, dc->w.DCOrgY + top,
347                       ell_width, ell_height, 90 * 64, 90 * 64 );
348             TSXDrawArc( display, dc->u.x.drawable, dc->u.x.gc,
349                       dc->w.DCOrgX + left, dc->w.DCOrgY + bottom - ell_height,
350                       ell_width, ell_height, 180 * 64, 90 * 64 );
351             TSXDrawArc( display, dc->u.x.drawable, dc->u.x.gc,
352                       dc->w.DCOrgX + right - ell_width,
353                       dc->w.DCOrgY + bottom - ell_height,
354                       ell_width, ell_height, 270 * 64, 90 * 64 );
355             TSXDrawArc( display, dc->u.x.drawable, dc->u.x.gc,
356                       dc->w.DCOrgX + right - ell_width, dc->w.DCOrgY + top,
357                       ell_width, ell_height, 0, 90 * 64 );
358         }
359         if (ell_width < right - left)
360         {
361             TSXDrawLine( display, dc->u.x.drawable, dc->u.x.gc, 
362                        dc->w.DCOrgX + left + ell_width / 2,
363                        dc->w.DCOrgY + top,
364                        dc->w.DCOrgX + right - ell_width / 2,
365                        dc->w.DCOrgY + top );
366             TSXDrawLine( display, dc->u.x.drawable, dc->u.x.gc, 
367                        dc->w.DCOrgX + left + ell_width / 2,
368                        dc->w.DCOrgY + bottom,
369                        dc->w.DCOrgX + right - ell_width / 2,
370                        dc->w.DCOrgY + bottom );
371         }
372         if (ell_height < bottom - top)
373         {
374             TSXDrawLine( display, dc->u.x.drawable, dc->u.x.gc, 
375                        dc->w.DCOrgX + right,
376                        dc->w.DCOrgY + top + ell_height / 2,
377                        dc->w.DCOrgX + right,
378                        dc->w.DCOrgY + bottom - ell_height / 2 );
379             TSXDrawLine( display, dc->u.x.drawable, dc->u.x.gc, 
380                        dc->w.DCOrgX + left,
381                        dc->w.DCOrgY + top + ell_height / 2,
382                        dc->w.DCOrgX + left,
383                        dc->w.DCOrgY + bottom - ell_height / 2 );
384         }
385     }
386     return TRUE;
387 }
388
389
390 /***********************************************************************
391  *           X11DRV_SetPixel
392  */
393 COLORREF
394 X11DRV_SetPixel( DC *dc, INT32 x, INT32 y, COLORREF color )
395 {
396     Pixel pixel;
397     
398     x = dc->w.DCOrgX + XLPTODP( dc, x );
399     y = dc->w.DCOrgY + YLPTODP( dc, y );
400     pixel = COLOR_ToPhysical( dc, color );
401     
402     TSXSetForeground( display, dc->u.x.gc, pixel );
403     TSXSetFunction( display, dc->u.x.gc, GXcopy );
404     TSXDrawPoint( display, dc->u.x.drawable, dc->u.x.gc, x, y );
405
406     /* inefficient but simple... */
407
408     return COLOR_ToLogical(pixel);
409 }
410
411
412 /***********************************************************************
413  *           X11DRV_GetPixel
414  */
415 COLORREF
416 X11DRV_GetPixel( DC *dc, INT32 x, INT32 y )
417 {
418     static Pixmap pixmap = 0;
419     XImage * image;
420     int pixel;
421
422     x = dc->w.DCOrgX + XLPTODP( dc, x );
423     y = dc->w.DCOrgY + YLPTODP( dc, y );
424     EnterCriticalSection( &X11DRV_CritSection );
425     if (dc->w.flags & DC_MEMORY)
426     {
427         image = XGetImage( display, dc->u.x.drawable, x, y, 1, 1,
428                            AllPlanes, ZPixmap );
429     }
430     else
431     {
432         /* If we are reading from the screen, use a temporary copy */
433         /* to avoid a BadMatch error */
434         if (!pixmap) pixmap = XCreatePixmap( display, rootWindow,
435                                              1, 1, dc->w.bitsPerPixel );
436         XCopyArea( display, dc->u.x.drawable, pixmap, BITMAP_colorGC,
437                    x, y, 1, 1, 0, 0 );
438         image = XGetImage( display, pixmap, 0, 0, 1, 1, AllPlanes, ZPixmap );
439     }
440     pixel = XGetPixel( image, 0, 0 );
441     XDestroyImage( image );
442     LeaveCriticalSection( &X11DRV_CritSection );
443     
444     return COLOR_ToLogical(pixel);
445 }
446
447
448 /***********************************************************************
449  *           X11DRV_PaintRgn
450  */
451 BOOL32
452 X11DRV_PaintRgn( DC *dc, HRGN32 hrgn )
453 {
454     RECT32 box;
455     HRGN32 tmpVisRgn, prevVisRgn;
456     HDC32  hdc = dc->hSelf; /* FIXME: should not mix dc/hdc this way */
457
458     if (!(tmpVisRgn = CreateRectRgn32( 0, 0, 0, 0 ))) return FALSE;
459
460       /* Transform region into device co-ords */
461     if (!REGION_LPTODP( hdc, tmpVisRgn, hrgn )) {
462         DeleteObject32( tmpVisRgn );
463         return FALSE;
464     }
465
466       /* Modify visible region */
467     if (!(prevVisRgn = SaveVisRgn( hdc ))) {
468         DeleteObject32( tmpVisRgn );
469         return FALSE;
470     }
471     CombineRgn32( tmpVisRgn, prevVisRgn, tmpVisRgn, RGN_AND );
472     SelectVisRgn( hdc, tmpVisRgn );
473     DeleteObject32( tmpVisRgn );
474
475       /* Fill the region */
476
477     GetRgnBox32( dc->w.hGCClipRgn, &box );
478     if (DC_SetupGCForBrush( dc ))
479         TSXFillRectangle( display, dc->u.x.drawable, dc->u.x.gc,
480                         dc->w.DCOrgX + box.left, dc->w.DCOrgY + box.top,
481                         box.right-box.left, box.bottom-box.top );
482
483       /* Restore the visible region */
484
485     RestoreVisRgn( hdc );
486     return TRUE;
487 }
488
489 /**********************************************************************
490  *          X11DRV_Polyline
491  */
492 BOOL32
493 X11DRV_Polyline( DC *dc, const LPPOINT32 pt, INT32 count )
494 {
495     register int i;
496
497     if (DC_SetupGCForPen( dc ))
498         for (i = 0; i < count-1; i ++)
499             TSXDrawLine (display, dc->u.x.drawable, dc->u.x.gc,  
500                        dc->w.DCOrgX + XLPTODP(dc, pt [i].x),
501                        dc->w.DCOrgY + YLPTODP(dc, pt [i].y),
502                        dc->w.DCOrgX + XLPTODP(dc, pt [i+1].x),
503                        dc->w.DCOrgY + YLPTODP(dc, pt [i+1].y));
504     return TRUE;
505 }
506
507
508 /**********************************************************************
509  *          X11DRV_Polygon
510  */
511 BOOL32
512 X11DRV_Polygon( DC *dc, LPPOINT32 pt, INT32 count )
513 {
514     register int i;
515     XPoint *points;
516
517     points = (XPoint *) xmalloc (sizeof (XPoint) * (count+1));
518     for (i = 0; i < count; i++)
519     {
520         points[i].x = dc->w.DCOrgX + XLPTODP( dc, pt[i].x );
521         points[i].y = dc->w.DCOrgY + YLPTODP( dc, pt[i].y );
522     }
523     points[count] = points[0];
524
525     if (DC_SetupGCForBrush( dc ))
526         TSXFillPolygon( display, dc->u.x.drawable, dc->u.x.gc,
527                      points, count+1, Complex, CoordModeOrigin);
528
529     if (DC_SetupGCForPen ( dc ))
530         TSXDrawLines( display, dc->u.x.drawable, dc->u.x.gc,
531                    points, count+1, CoordModeOrigin );
532
533     free( points );
534     return TRUE;
535 }
536
537
538 /**********************************************************************
539  *          X11DRV_PolyPolygon
540  */
541 BOOL32 
542 X11DRV_PolyPolygon( DC *dc, LPPOINT32 pt, LPINT32 counts, UINT32 polygons)
543 {
544     HRGN32 hrgn;
545
546       /* FIXME: The points should be converted to device coords before */
547       /* creating the region. But as CreatePolyPolygonRgn is not */
548       /* really correct either, it doesn't matter much... */
549       /* At least the outline will be correct :-) */
550     hrgn = CreatePolyPolygonRgn32( pt, counts, polygons, dc->w.polyFillMode );
551     X11DRV_PaintRgn( dc, hrgn );
552     DeleteObject32( hrgn );
553
554       /* Draw the outline of the polygons */
555
556     if (DC_SetupGCForPen ( dc ))
557     {
558         int i, j, max = 0;
559         XPoint *points;
560
561         for (i = 0; i < polygons; i++) if (counts[i] > max) max = counts[i];
562         points = (XPoint *) xmalloc( sizeof(XPoint) * (max+1) );
563
564         for (i = 0; i < polygons; i++)
565         {
566             for (j = 0; j < counts[i]; j++)
567             {
568                 points[j].x = dc->w.DCOrgX + XLPTODP( dc, pt->x );
569                 points[j].y = dc->w.DCOrgY + YLPTODP( dc, pt->y );
570                 pt++;
571             }
572             points[j] = points[0];
573             TSXDrawLines( display, dc->u.x.drawable, dc->u.x.gc,
574                         points, j + 1, CoordModeOrigin );
575         }
576         free( points );
577     }
578     return TRUE;
579 }
580
581
582 /**********************************************************************
583  *          X11DRV_PolyPolyline
584  */
585 BOOL32 
586 X11DRV_PolyPolyline( DC *dc, LPPOINT32 pt, LPINT32 counts, UINT32 polylines )
587 {
588     if (DC_SetupGCForPen ( dc ))
589     {
590         int i, j, max = 0;
591         XPoint *points;
592
593         for (i = 0; i < polylines; i++) if (counts[i] > max) max = counts[i];
594         points = (XPoint *) xmalloc( sizeof(XPoint) * (max+1) );
595
596         for (i = 0; i < polylines; i++)
597         {
598             for (j = 0; j < counts[i]; j++)
599             {
600                 points[j].x = dc->w.DCOrgX + XLPTODP( dc, pt->x );
601                 points[j].y = dc->w.DCOrgY + YLPTODP( dc, pt->y );
602                 pt++;
603             }
604             points[j] = points[0];
605             TSXDrawLines( display, dc->u.x.drawable, dc->u.x.gc,
606                         points, j + 1, CoordModeOrigin );
607         }
608         free( points );
609     }
610     return TRUE;
611 }
612
613
614 /**********************************************************************
615  *          X11DRV_InternalFloodFill
616  *
617  * Internal helper function for flood fill.
618  * (xorg,yorg) is the origin of the X image relative to the drawable.
619  * (x,y) is relative to the origin of the X image.
620  */
621 static void X11DRV_InternalFloodFill(XImage *image, DC *dc,
622                                      int x, int y,
623                                      int xOrg, int yOrg,
624                                      Pixel pixel, WORD fillType )
625 {
626     int left, right;
627
628 #define TO_FLOOD(x,y)  ((fillType == FLOODFILLBORDER) ? \
629                         (XGetPixel(image,x,y) != pixel) : \
630                         (XGetPixel(image,x,y) == pixel))
631
632     if (!TO_FLOOD(x,y)) return;
633
634       /* Find left and right boundaries */
635
636     left = right = x;
637     while ((left > 0) && TO_FLOOD( left-1, y )) left--;
638     while ((right < image->width) && TO_FLOOD( right, y )) right++;
639     XFillRectangle( display, dc->u.x.drawable, dc->u.x.gc,
640                     xOrg + left, yOrg + y, right-left, 1 );
641
642       /* Set the pixels of this line so we don't fill it again */
643
644     for (x = left; x < right; x++)
645     {
646         if (fillType == FLOODFILLBORDER) XPutPixel( image, x, y, pixel );
647         else XPutPixel( image, x, y, ~pixel );
648     }
649
650       /* Fill the line above */
651
652     if (--y >= 0)
653     {
654         x = left;
655         while (x < right)
656         {
657             while ((x < right) && !TO_FLOOD(x,y)) x++;
658             if (x >= right) break;
659             while ((x < right) && TO_FLOOD(x,y)) x++;
660             X11DRV_InternalFloodFill(image, dc, x-1, y,
661                                      xOrg, yOrg, pixel, fillType );
662         }
663     }
664
665       /* Fill the line below */
666
667     if ((y += 2) < image->height)
668     {
669         x = left;
670         while (x < right)
671         {
672             while ((x < right) && !TO_FLOOD(x,y)) x++;
673             if (x >= right) break;
674             while ((x < right) && TO_FLOOD(x,y)) x++;
675             X11DRV_InternalFloodFill(image, dc, x-1, y,
676                                      xOrg, yOrg, pixel, fillType );
677         }
678     }
679 #undef TO_FLOOD    
680 }
681
682
683 /**********************************************************************
684  *          X11DRV_DoFloodFill
685  *
686  * Main flood-fill routine.
687  *
688  * The Xlib critical section must be entered before calling this function.
689  */
690
691 struct FloodFill_params
692 {
693     DC      *dc;
694     INT32    x;
695     INT32    y;
696     COLORREF color;
697     UINT32   fillType;
698 };
699
700 static BOOL32 X11DRV_DoFloodFill( const struct FloodFill_params *params )
701 {
702     XImage *image;
703     RECT32 rect;
704     DC *dc = params->dc;
705
706     if (GetRgnBox32( dc->w.hGCClipRgn, &rect ) == ERROR) return FALSE;
707
708     if (!(image = XGetImage( display, dc->u.x.drawable,
709                              dc->w.DCOrgX + rect.left,
710                              dc->w.DCOrgY + rect.top,
711                              rect.right - rect.left,
712                              rect.bottom - rect.top,
713                              AllPlanes, ZPixmap ))) return FALSE;
714
715     if (DC_SetupGCForBrush( dc ))
716     {
717           /* ROP mode is always GXcopy for flood-fill */
718         XSetFunction( display, dc->u.x.gc, GXcopy );
719         X11DRV_InternalFloodFill(image, dc,
720                                  XLPTODP(dc,params->x) - rect.left,
721                                  YLPTODP(dc,params->y) - rect.top,
722                                  dc->w.DCOrgX + rect.left,
723                                  dc->w.DCOrgY + rect.top,
724                                  COLOR_ToPhysical( dc, params->color ),
725                                  params->fillType );
726     }
727
728     XDestroyImage( image );
729     return TRUE;
730 }
731
732
733 /**********************************************************************
734  *          X11DRV_ExtFloodFill
735  */
736 BOOL32
737 X11DRV_ExtFloodFill( DC *dc, INT32 x, INT32 y, COLORREF color,
738                      UINT32 fillType )
739 {
740     BOOL32 result;
741     struct FloodFill_params params = { dc, x, y, color, fillType };
742
743     TRACE(graphics, "X11DRV_ExtFloodFill %d,%d %06lx %d\n",
744                       x, y, color, fillType );
745
746     if (!PtVisible32( dc->hSelf, x, y )) return FALSE;
747     EnterCriticalSection( &X11DRV_CritSection );
748     result = CALL_LARGE_STACK( X11DRV_DoFloodFill, &params );
749     LeaveCriticalSection( &X11DRV_CritSection );
750     return result;
751 }