Release 980215
[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 "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 "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         TSXDrawLine(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         TSXSetArcMode( display, dc->u.x.gc, (lines==1) ? ArcChord : ArcPieSlice);
113         TSXFillArc( 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     TSXDrawArc( 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     TSXDrawLines( 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         TSXFillArc( 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         TSXDrawArc( 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             TSXDrawLine(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             TSXFillRectangle( 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         TSXDrawRectangle( 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             TSXFillArc( 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             TSXFillArc( 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             TSXFillArc( 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             TSXFillArc( 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             TSXFillRectangle( 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             TSXFillRectangle( 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             TSXFillRectangle( 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             TSXDrawArc( 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             TSXDrawArc( 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             TSXDrawArc( 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             TSXDrawArc( 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             TSXDrawLine( 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             TSXDrawLine( 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             TSXDrawLine( 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             TSXDrawLine( 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     TSXSetForeground( display, dc->u.x.gc, pixel );
390     TSXSetFunction( display, dc->u.x.gc, GXcopy );
391     TSXDrawPoint( 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     EnterCriticalSection( &X11DRV_CritSection );
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     LeaveCriticalSection( &X11DRV_CritSection );
430     
431     return COLOR_ToLogical(pixel);
432 }
433
434
435 /***********************************************************************
436  *           X11DRV_PaintRgn
437  */
438 BOOL32
439 X11DRV_PaintRgn( DC *dc, HRGN32 hrgn )
440 {
441     RECT32 box;
442     HRGN32 tmpVisRgn, prevVisRgn;
443     HDC32  hdc = dc->hSelf; /* FIXME: should not mix dc/hdc this way */
444
445     if (!(tmpVisRgn = CreateRectRgn32( 0, 0, 0, 0 ))) return FALSE;
446
447       /* Transform region into device co-ords */
448     if (!REGION_LPTODP( hdc, tmpVisRgn, hrgn )) {
449         DeleteObject32( tmpVisRgn );
450         return FALSE;
451     }
452
453       /* Modify visible region */
454     if (!(prevVisRgn = SaveVisRgn( hdc ))) {
455         DeleteObject32( tmpVisRgn );
456         return FALSE;
457     }
458     CombineRgn32( tmpVisRgn, prevVisRgn, tmpVisRgn, RGN_AND );
459     SelectVisRgn( hdc, tmpVisRgn );
460     DeleteObject32( tmpVisRgn );
461
462       /* Fill the region */
463
464     GetRgnBox32( dc->w.hGCClipRgn, &box );
465     if (DC_SetupGCForBrush( dc ))
466         TSXFillRectangle( display, dc->u.x.drawable, dc->u.x.gc,
467                         dc->w.DCOrgX + box.left, dc->w.DCOrgY + box.top,
468                         box.right-box.left, box.bottom-box.top );
469
470       /* Restore the visible region */
471
472     RestoreVisRgn( hdc );
473     return TRUE;
474 }
475
476 /**********************************************************************
477  *          X11DRV_Polyline
478  */
479 BOOL32
480 X11DRV_Polyline( DC *dc, const LPPOINT32 pt, INT32 count )
481 {
482     register int i;
483
484     if (DC_SetupGCForPen( dc ))
485         for (i = 0; i < count-1; i ++)
486             TSXDrawLine (display, dc->u.x.drawable, dc->u.x.gc,  
487                        dc->w.DCOrgX + XLPTODP(dc, pt [i].x),
488                        dc->w.DCOrgY + YLPTODP(dc, pt [i].y),
489                        dc->w.DCOrgX + XLPTODP(dc, pt [i+1].x),
490                        dc->w.DCOrgY + YLPTODP(dc, pt [i+1].y));
491     return TRUE;
492 }
493
494
495 /**********************************************************************
496  *          X11DRV_Polygon
497  */
498 BOOL32
499 X11DRV_Polygon( DC *dc, LPPOINT32 pt, INT32 count )
500 {
501     register int i;
502     XPoint *points;
503
504     points = (XPoint *) xmalloc (sizeof (XPoint) * (count+1));
505     for (i = 0; i < count; i++)
506     {
507         points[i].x = dc->w.DCOrgX + XLPTODP( dc, pt[i].x );
508         points[i].y = dc->w.DCOrgY + YLPTODP( dc, pt[i].y );
509     }
510     points[count] = points[0];
511
512     if (DC_SetupGCForBrush( dc ))
513         TSXFillPolygon( display, dc->u.x.drawable, dc->u.x.gc,
514                      points, count+1, Complex, CoordModeOrigin);
515
516     if (DC_SetupGCForPen ( dc ))
517         TSXDrawLines( display, dc->u.x.drawable, dc->u.x.gc,
518                    points, count+1, CoordModeOrigin );
519
520     free( points );
521     return TRUE;
522 }
523
524
525 /**********************************************************************
526  *          X11DRV_PolyPolygon
527  */
528 BOOL32 
529 X11DRV_PolyPolygon( DC *dc, LPPOINT32 pt, LPINT32 counts, UINT32 polygons)
530 {
531     HRGN32 hrgn;
532
533       /* FIXME: The points should be converted to device coords before */
534       /* creating the region. But as CreatePolyPolygonRgn is not */
535       /* really correct either, it doesn't matter much... */
536       /* At least the outline will be correct :-) */
537     hrgn = CreatePolyPolygonRgn32( pt, counts, polygons, dc->w.polyFillMode );
538     X11DRV_PaintRgn( dc, hrgn );
539     DeleteObject32( hrgn );
540
541       /* Draw the outline of the polygons */
542
543     if (DC_SetupGCForPen ( dc ))
544     {
545         int i, j, max = 0;
546         XPoint *points;
547
548         for (i = 0; i < polygons; i++) if (counts[i] > max) max = counts[i];
549         points = (XPoint *) xmalloc( sizeof(XPoint) * (max+1) );
550
551         for (i = 0; i < polygons; i++)
552         {
553             for (j = 0; j < counts[i]; j++)
554             {
555                 points[j].x = dc->w.DCOrgX + XLPTODP( dc, pt->x );
556                 points[j].y = dc->w.DCOrgY + YLPTODP( dc, pt->y );
557                 pt++;
558             }
559             points[j] = points[0];
560             TSXDrawLines( display, dc->u.x.drawable, dc->u.x.gc,
561                         points, j + 1, CoordModeOrigin );
562         }
563         free( points );
564     }
565     return TRUE;
566 }
567
568
569 /**********************************************************************
570  *          X11DRV_InternalFloodFill
571  *
572  * Internal helper function for flood fill.
573  * (xorg,yorg) is the origin of the X image relative to the drawable.
574  * (x,y) is relative to the origin of the X image.
575  */
576 static void X11DRV_InternalFloodFill(XImage *image, DC *dc,
577                                      int x, int y,
578                                      int xOrg, int yOrg,
579                                      Pixel pixel, WORD fillType )
580 {
581     int left, right;
582
583 #define TO_FLOOD(x,y)  ((fillType == FLOODFILLBORDER) ? \
584                         (XGetPixel(image,x,y) != pixel) : \
585                         (XGetPixel(image,x,y) == pixel))
586
587     if (!TO_FLOOD(x,y)) return;
588
589       /* Find left and right boundaries */
590
591     left = right = x;
592     while ((left > 0) && TO_FLOOD( left-1, y )) left--;
593     while ((right < image->width) && TO_FLOOD( right, y )) right++;
594     XFillRectangle( display, dc->u.x.drawable, dc->u.x.gc,
595                     xOrg + left, yOrg + y, right-left, 1 );
596
597       /* Set the pixels of this line so we don't fill it again */
598
599     for (x = left; x < right; x++)
600     {
601         if (fillType == FLOODFILLBORDER) XPutPixel( image, x, y, pixel );
602         else XPutPixel( image, x, y, ~pixel );
603     }
604
605       /* Fill the line above */
606
607     if (--y >= 0)
608     {
609         x = left;
610         while (x < right)
611         {
612             while ((x < right) && !TO_FLOOD(x,y)) x++;
613             if (x >= right) break;
614             while ((x < right) && TO_FLOOD(x,y)) x++;
615             X11DRV_InternalFloodFill(image, dc, x-1, y,
616                                      xOrg, yOrg, pixel, fillType );
617         }
618     }
619
620       /* Fill the line below */
621
622     if ((y += 2) < image->height)
623     {
624         x = left;
625         while (x < right)
626         {
627             while ((x < right) && !TO_FLOOD(x,y)) x++;
628             if (x >= right) break;
629             while ((x < right) && TO_FLOOD(x,y)) x++;
630             X11DRV_InternalFloodFill(image, dc, x-1, y,
631                                      xOrg, yOrg, pixel, fillType );
632         }
633     }
634 #undef TO_FLOOD    
635 }
636
637
638 /**********************************************************************
639  *          X11DRV_DoFloodFill
640  *
641  * Main flood-fill routine.
642  *
643  * The Xlib critical section must be entered before calling this function.
644  */
645
646 struct FloodFill_params
647 {
648     DC      *dc;
649     INT32    x;
650     INT32    y;
651     COLORREF color;
652     UINT32   fillType;
653 };
654
655 static BOOL32 X11DRV_DoFloodFill( const struct FloodFill_params *params )
656 {
657     XImage *image;
658     RECT32 rect;
659     DC *dc = params->dc;
660
661     if (GetRgnBox32( dc->w.hGCClipRgn, &rect ) == ERROR) return FALSE;
662
663     if (!(image = XGetImage( display, dc->u.x.drawable,
664                              dc->w.DCOrgX + rect.left,
665                              dc->w.DCOrgY + rect.top,
666                              rect.right - rect.left,
667                              rect.bottom - rect.top,
668                              AllPlanes, ZPixmap ))) return FALSE;
669
670     if (DC_SetupGCForBrush( dc ))
671     {
672           /* ROP mode is always GXcopy for flood-fill */
673         XSetFunction( display, dc->u.x.gc, GXcopy );
674         X11DRV_InternalFloodFill(image, dc,
675                                  XLPTODP(dc,params->x) - rect.left,
676                                  YLPTODP(dc,params->y) - rect.top,
677                                  dc->w.DCOrgX + rect.left,
678                                  dc->w.DCOrgY + rect.top,
679                                  COLOR_ToPhysical( dc, params->color ),
680                                  params->fillType );
681     }
682
683     XDestroyImage( image );
684     return TRUE;
685 }
686
687
688 /**********************************************************************
689  *          X11DRV_ExtFloodFill
690  */
691 BOOL32
692 X11DRV_ExtFloodFill( DC *dc, INT32 x, INT32 y, COLORREF color,
693                      UINT32 fillType )
694 {
695     BOOL32 result;
696     struct FloodFill_params params = { dc, x, y, color, fillType };
697
698     dprintf_graphics( stddeb, "X11DRV_ExtFloodFill %d,%d %06lx %d\n",
699                       x, y, color, fillType );
700
701     if (!PtVisible32( dc->hSelf, x, y )) return FALSE;
702     EnterCriticalSection( &X11DRV_CritSection );
703     result = CALL_LARGE_STACK( X11DRV_DoFloodFill, &params );
704     LeaveCriticalSection( &X11DRV_CritSection );
705     return result;
706 }