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