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