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