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