Release 980628
[wine] / graphics / x11drv / graphics.c
1 /*
2  * X11 graphics driver graphics functions
3  *
4  * Copyright 1993,1994 Alexandre Julliard
5  */
6
7
8 /*
9  * FIXME: none of these functions obey the GM_ADVANCED
10  * graphics mode
11  */
12
13 #include <math.h>
14 #ifdef HAVE_FLOAT_H
15 # include <float.h>
16 #endif
17 #include <stdlib.h>
18 #include "ts_xlib.h"
19 #include "ts_xutil.h"
20 #include <X11/Intrinsic.h>
21 #ifndef PI
22 #define PI M_PI
23 #endif
24 #include <string.h>
25
26 #include "x11drv.h"
27 #include "bitmap.h"
28 #include "gdi.h"
29 #include "graphics.h"
30 #include "dc.h"
31 #include "bitmap.h"
32 #include "callback.h"
33 #include "metafile.h"
34 #include "palette.h"
35 #include "color.h"
36 #include "region.h"
37 #include "struct32.h"
38 #include "debug.h"
39 #include "xmalloc.h"
40
41
42 /**********************************************************************
43  *           X11DRV_MoveToEx
44  */
45 BOOL32
46 X11DRV_MoveToEx(DC *dc,INT32 x,INT32 y,LPPOINT32 pt) {
47     if (pt)
48     {
49         pt->x = dc->w.CursPosX;
50         pt->y = dc->w.CursPosY;
51     }
52     dc->w.CursPosX = x;
53     dc->w.CursPosY = y;
54     return TRUE;
55 }
56
57 /***********************************************************************
58  *           X11DRV_LineTo
59  */
60 BOOL32
61 X11DRV_LineTo( DC *dc, INT32 x, INT32 y )
62 {
63     if (DC_SetupGCForPen( dc ))
64         TSXDrawLine(display, dc->u.x.drawable, dc->u.x.gc, 
65                   dc->w.DCOrgX + XLPTODP( dc, dc->w.CursPosX ),
66                   dc->w.DCOrgY + YLPTODP( dc, dc->w.CursPosY ),
67                   dc->w.DCOrgX + XLPTODP( dc, x ),
68                   dc->w.DCOrgY + YLPTODP( dc, y ) );
69     dc->w.CursPosX = x;
70     dc->w.CursPosY = y;
71     return TRUE;
72 }
73
74
75
76 /***********************************************************************
77  *           GRAPH_DrawArc
78  *
79  * Helper functions for Arc(), Chord() and Pie().
80  * 'lines' is the number of lines to draw: 0 for Arc, 1 for Chord, 2 for Pie.
81  *
82  * FIXME: incorrect with thick pen and/or PS_INSIDEFRAME style
83  *        see ellipse and rectangle functions
84  */
85 static BOOL32
86 X11DRV_DrawArc( DC *dc, INT32 left, INT32 top, INT32 right,
87                 INT32 bottom, INT32 xstart, INT32 ystart,
88                 INT32 xend, INT32 yend, INT32 lines )
89 {
90     INT32 xcenter, ycenter, istart_angle, idiff_angle, tmp;
91     double start_angle, end_angle;
92     XPoint points[3];
93
94     left   = XLPTODP( dc, left );
95     top    = YLPTODP( dc, top );
96     right  = XLPTODP( dc, right );
97     bottom = YLPTODP( dc, bottom );
98     xstart = XLPTODP( dc, xstart );
99     ystart = YLPTODP( dc, ystart );
100     xend   = XLPTODP( dc, xend );
101     yend   = YLPTODP( dc, yend );
102
103     if ((left == right) || (top == bottom)) return TRUE;
104
105     if (left > right) { tmp=left; left=right; right=tmp; }
106     if (top > bottom) { tmp=top; top=bottom; bottom=tmp; } 
107     xcenter = (right + left) / 2;
108     ycenter = (bottom + top) / 2;
109     start_angle = atan2( (double)(ycenter-ystart)*(right-left),
110                          (double)(xstart-xcenter)*(bottom-top) );
111     end_angle   = atan2( (double)(ycenter-yend)*(right-left),
112                          (double)(xend-xcenter)*(bottom-top) );
113     if ((xstart==xend)&&(ystart==yend))
114       { /* A lazy program delivers xstart=xend=ystart=yend=0) */
115         start_angle = 0;
116         end_angle = 2* PI;
117       }
118     else /* notorious cases */
119       if ((start_angle == PI)&&( end_angle <0))
120         start_angle = - PI;
121     else
122       if ((end_angle == PI)&&( start_angle <0))
123         end_angle = - PI;
124     istart_angle = (INT32)(start_angle * 180 * 64 / PI);
125     idiff_angle  = (INT32)((end_angle - start_angle) * 180 * 64 / PI );
126     if (idiff_angle <= 0) idiff_angle += 360 * 64;
127
128       /* Fill arc with brush if Chord() or Pie() */
129
130     if ((lines > 0) && DC_SetupGCForBrush( dc ))
131     {
132         TSXSetArcMode( display, dc->u.x.gc, (lines==1) ? ArcChord : ArcPieSlice);
133         TSXFillArc( display, dc->u.x.drawable, dc->u.x.gc,
134                  dc->w.DCOrgX + left, dc->w.DCOrgY + top,
135                  right-left-1, bottom-top-1, istart_angle, idiff_angle );
136     }
137
138       /* Draw arc and lines */
139
140     if (!DC_SetupGCForPen( dc )) return TRUE;
141     TSXDrawArc( display, dc->u.x.drawable, dc->u.x.gc,
142               dc->w.DCOrgX + left, dc->w.DCOrgY + top,
143               right-left-1, bottom-top-1, istart_angle, idiff_angle );
144     if (!lines) return TRUE;
145
146     points[0].x = dc->w.DCOrgX + xcenter + (int)(cos(start_angle) * (right-left) / 2);
147     points[0].y = dc->w.DCOrgY + ycenter - (int)(sin(start_angle) * (bottom-top) / 2);
148     points[1].x = dc->w.DCOrgX + xcenter + (int)(cos(end_angle) * (right-left) / 2);
149     points[1].y = dc->w.DCOrgY + ycenter - (int)(sin(end_angle) * (bottom-top) / 2);
150     if (lines == 2)
151     {
152         points[2] = points[1];
153         points[1].x = dc->w.DCOrgX + xcenter;
154         points[1].y = dc->w.DCOrgY + ycenter;
155     }
156     TSXDrawLines( display, dc->u.x.drawable, dc->u.x.gc,
157                 points, lines+1, CoordModeOrigin );
158     return TRUE;
159 }
160
161
162 /***********************************************************************
163  *           X11DRV_Arc
164  */
165 BOOL32
166 X11DRV_Arc( DC *dc, INT32 left, INT32 top, INT32 right, INT32 bottom,
167             INT32 xstart, INT32 ystart, INT32 xend, INT32 yend )
168 {
169     return X11DRV_DrawArc( dc, left, top, right, bottom,
170                            xstart, ystart, xend, yend, 0 );
171 }
172
173
174 /***********************************************************************
175  *           X11DRV_Pie
176  */
177 BOOL32
178 X11DRV_Pie( DC *dc, INT32 left, INT32 top, INT32 right, INT32 bottom,
179             INT32 xstart, INT32 ystart, INT32 xend, INT32 yend )
180 {
181     return X11DRV_DrawArc( dc, left, top, right, bottom,
182                            xstart, ystart, xend, yend, 2 );
183 }
184
185 /***********************************************************************
186  *           X11DRV_Chord
187  */
188 BOOL32
189 X11DRV_Chord( DC *dc, INT32 left, INT32 top, INT32 right, INT32 bottom,
190               INT32 xstart, INT32 ystart, INT32 xend, INT32 yend )
191 {
192     return X11DRV_DrawArc( dc, left, top, right, bottom,
193                            xstart, ystart, xend, yend, 1 );
194 }
195
196
197 /***********************************************************************
198  *           X11DRV_Ellipse
199  */
200 BOOL32
201 X11DRV_Ellipse( DC *dc, INT32 left, INT32 top, INT32 right, INT32 bottom )
202 {
203     INT32 width, oldwidth;
204
205     left   = XLPTODP( dc, left );
206     top    = YLPTODP( dc, top );
207     right  = XLPTODP( dc, right );
208     bottom = YLPTODP( dc, bottom );
209     if ((left == right) || (top == bottom)) return TRUE;
210
211     if (right < left) { INT32 tmp = right; right = left; left = tmp; }
212     if (bottom < top) { INT32 tmp = bottom; bottom = top; top = tmp; }
213     
214     oldwidth = width = dc->u.x.pen.width;
215     if (!width) width = 1;
216     if(dc->u.x.pen.style == PS_NULL) width = 0;
217
218     if ((dc->u.x.pen.style == PS_INSIDEFRAME))
219     {
220         if (2*width > (right-left)) width=(right-left + 1)/2;
221         if (2*width > (bottom-top)) width=(bottom-top + 1)/2;
222         left   += width / 2;
223         right  -= (width - 1) / 2;
224         top    += width / 2;
225         bottom -= (width - 1) / 2;
226     }
227     if(width == 1) width=0;
228     dc->u.x.pen.width=width;
229
230     if (DC_SetupGCForBrush( dc ))
231         TSXFillArc( display, dc->u.x.drawable, dc->u.x.gc,
232                   dc->w.DCOrgX + left, dc->w.DCOrgY + top,
233                   right-left-1, bottom-top-1, 0, 360*64 );
234     if (DC_SetupGCForPen( dc ))
235         TSXDrawArc( display, dc->u.x.drawable, dc->u.x.gc,
236                   dc->w.DCOrgX + left, dc->w.DCOrgY + top,
237                   right-left-1, bottom-top-1, 0, 360*64 );
238     dc->u.x.pen.width=oldwidth;
239     return TRUE;
240 }
241
242
243 /***********************************************************************
244  *           X11DRV_Rectangle
245  */
246 BOOL32
247 X11DRV_Rectangle(DC *dc, INT32 left, INT32 top, INT32 right, INT32 bottom)
248 {
249     INT32 width, oldwidth, oldjoinstyle;
250
251     TRACE(graphics, "(%d %d %d %d)\n", 
252         left, top, right, bottom);
253
254     left   = XLPTODP( dc, left );
255     top    = YLPTODP( dc, top );
256     right  = XLPTODP( dc, right );
257     bottom = YLPTODP( dc, bottom );
258
259     if ((left == right) || (top == bottom)) return TRUE;
260
261     if (right < left) { INT32 tmp = right; right = left; left = tmp; }
262     if (bottom < top) { INT32 tmp = bottom; bottom = top; top = tmp; }
263
264     oldwidth = width = dc->u.x.pen.width;
265     if (!width) width = 1;
266     if(dc->u.x.pen.style == PS_NULL) width = 0;
267
268     if ((dc->u.x.pen.style == PS_INSIDEFRAME))
269     {
270         if (2*width > (right-left)) width=(right-left + 1)/2;
271         if (2*width > (bottom-top)) width=(bottom-top + 1)/2;
272         left   += width / 2;
273         right  -= (width - 1) / 2;
274         top    += width / 2;
275         bottom -= (width - 1) / 2;
276     }
277     if(width == 1) width=0;
278     dc->u.x.pen.width=width;
279     oldjoinstyle=dc->u.x.pen.linejoin;
280     if(dc->u.x.pen.type!=PS_GEOMETRIC)
281             dc->u.x.pen.linejoin=PS_JOIN_MITER;
282
283     if ((right > left + width) && (bottom > top + width))
284     {
285         if (DC_SetupGCForBrush( dc ))
286             TSXFillRectangle( display, dc->u.x.drawable, dc->u.x.gc,
287                             dc->w.DCOrgX + left + (width + 1) / 2,
288                             dc->w.DCOrgY + top + (width + 1) / 2,
289                             right-left-width-1, bottom-top-width-1);
290     }
291     if (DC_SetupGCForPen( dc ))
292         TSXDrawRectangle( display, dc->u.x.drawable, dc->u.x.gc,
293                         dc->w.DCOrgX + left, dc->w.DCOrgY + top,
294                         right-left-1, bottom-top-1 );
295
296     dc->u.x.pen.width=oldwidth;
297     dc->u.x.pen.linejoin=oldjoinstyle;
298     return TRUE;
299 }
300
301 /***********************************************************************
302  *           X11DRV_RoundRect
303  */
304 BOOL32
305 X11DRV_RoundRect( DC *dc, INT32 left, INT32 top, INT32 right,
306                   INT32 bottom, INT32 ell_width, INT32 ell_height )
307 {
308     INT32 width, oldwidth;
309
310     TRACE(graphics, "(%d %d %d %d  %d %d\n", 
311         left, top, right, bottom, ell_width, ell_height);
312
313     left   = XLPTODP( dc, left );
314     top    = YLPTODP( dc, top );
315     right  = XLPTODP( dc, right );
316     bottom = YLPTODP( dc, bottom );
317
318     if ((left == right) || (top == bottom))
319         return TRUE;
320
321     ell_width  = abs( ell_width * dc->vportExtX / dc->wndExtX );
322     ell_height = abs( ell_height * dc->vportExtY / dc->wndExtY );
323
324     /* Fix the coordinates */
325
326     if (right < left) { INT32 tmp = right; right = left; left = tmp; }
327     if (bottom < top) { INT32 tmp = bottom; bottom = top; top = tmp; }
328
329     oldwidth=width = dc->u.x.pen.width;
330     if (!width) width = 1;
331     if(dc->u.x.pen.style == PS_NULL) width = 0;
332
333     if ((dc->u.x.pen.style == PS_INSIDEFRAME))
334     {
335         if (2*width > (right-left)) width=(right-left + 1)/2;
336         if (2*width > (bottom-top)) width=(bottom-top + 1)/2;
337         left   += width / 2;
338         right  -= (width - 1) / 2;
339         top    += width / 2;
340         bottom -= (width - 1) / 2;
341     }
342     if(width == 1) width=0;
343     dc->u.x.pen.width=width;
344
345     if (DC_SetupGCForBrush( dc ))
346     {
347         if (ell_width > (right-left) )
348             if (ell_height > (bottom-top) )
349                     TSXFillArc( display, dc->u.x.drawable, dc->u.x.gc,
350                               dc->w.DCOrgX + left, dc->w.DCOrgY + top,
351                               right - left - 1, bottom - top - 1,
352                               0, 360 * 64 );
353             else{
354                     TSXFillArc( display, dc->u.x.drawable, dc->u.x.gc,
355                               dc->w.DCOrgX + left, dc->w.DCOrgY + top,
356                               right - left - 1, ell_height, 0, 180 * 64 );
357                     TSXFillArc( display, dc->u.x.drawable, dc->u.x.gc,
358                               dc->w.DCOrgX + left,
359                               dc->w.DCOrgY + bottom - ell_height - 1,
360                               right - left - 1, ell_height, 180 * 64, 180 * 64 );
361            }
362         else if (ell_height > (bottom-top) ){
363                 TSXFillArc( display, dc->u.x.drawable, dc->u.x.gc,
364                       dc->w.DCOrgX + left, dc->w.DCOrgY + top,
365                       ell_width, bottom - top - 1, 90 * 64, 180 * 64 );
366                 TSXFillArc( display, dc->u.x.drawable, dc->u.x.gc,
367                       dc->w.DCOrgX + right - ell_width -1, dc->w.DCOrgY + top,
368                       ell_width, bottom - top - 1, 270 * 64, 180 * 64 );
369         }else{
370                 TSXFillArc( display, dc->u.x.drawable, dc->u.x.gc,
371                       dc->w.DCOrgX + left, dc->w.DCOrgY + top,
372                       ell_width, ell_height, 90 * 64, 90 * 64 );
373                 TSXFillArc( display, dc->u.x.drawable, dc->u.x.gc,
374                       dc->w.DCOrgX + left,
375                       dc->w.DCOrgY + bottom - ell_height - 1,
376                       ell_width, ell_height, 180 * 64, 90 * 64 );
377                 TSXFillArc( display, dc->u.x.drawable, dc->u.x.gc,
378                       dc->w.DCOrgX + right - ell_width - 1,
379                       dc->w.DCOrgY + bottom - ell_height - 1,
380                       ell_width, ell_height, 270 * 64, 90 * 64 );
381                 TSXFillArc( display, dc->u.x.drawable, dc->u.x.gc,
382                       dc->w.DCOrgX + right - ell_width - 1,
383                       dc->w.DCOrgY + top,
384                       ell_width, ell_height, 0, 90 * 64 );
385         }
386         if (ell_width < right - left)
387         {
388             TSXFillRectangle( display, dc->u.x.drawable, dc->u.x.gc,
389                             dc->w.DCOrgX + left + ell_width / 2,
390                             dc->w.DCOrgY + top,
391                             right - left - ell_width, ell_height / 2 );
392             TSXFillRectangle( display, dc->u.x.drawable, dc->u.x.gc,
393                             dc->w.DCOrgX + left + ell_width / 2,
394                             dc->w.DCOrgY + bottom - (ell_height+1) / 2,
395                             right - left - ell_width,
396                             (ell_height+1) / 2 - 1 );
397         }
398         if  (ell_height < bottom - top)
399         {
400             TSXFillRectangle( display, dc->u.x.drawable, dc->u.x.gc,
401                             dc->w.DCOrgX + left,
402                             dc->w.DCOrgY + top + ell_height / 2,
403                             right - left - 1, bottom - top - ell_height );
404         }
405     }
406     if (DC_SetupGCForPen(dc)) {
407         if (ell_width > (right-left) )
408             if (ell_height > (bottom-top) )
409                 TSXDrawArc( display, dc->u.x.drawable, dc->u.x.gc,
410                       dc->w.DCOrgX + left, dc->w.DCOrgY + top,
411                       right - left - 1, bottom -top - 1, 0 , 360 * 64 );
412             else{
413                 TSXDrawArc( display, dc->u.x.drawable, dc->u.x.gc,
414                       dc->w.DCOrgX + left, dc->w.DCOrgY + top,
415                       right - left - 1, ell_height - 1, 0 , 180 * 64 );
416                 TSXDrawArc( display, dc->u.x.drawable, dc->u.x.gc,
417                       dc->w.DCOrgX + left, 
418                       dc->w.DCOrgY + bottom - ell_height,
419                       right - left - 1, ell_height - 1, 180 * 64 , 180 * 64 );
420             }
421         else if (ell_height > (bottom-top) ){
422                 TSXDrawArc( display, dc->u.x.drawable, dc->u.x.gc,
423                       dc->w.DCOrgX + left, dc->w.DCOrgY + top,
424                       ell_width - 1 , bottom - top - 1, 90 * 64 , 180 * 64 );
425                 TSXDrawArc( display, dc->u.x.drawable, dc->u.x.gc,
426                       dc->w.DCOrgX + right - ell_width, 
427                       dc->w.DCOrgY + top,
428                       ell_width - 1 , bottom - top - 1, 270 * 64 , 180 * 64 );
429         }else{
430             TSXDrawArc( display, dc->u.x.drawable, dc->u.x.gc,
431                       dc->w.DCOrgX + left, dc->w.DCOrgY + top,
432                       ell_width - 1, ell_height - 1, 90 * 64, 90 * 64 );
433             TSXDrawArc( display, dc->u.x.drawable, dc->u.x.gc,
434                       dc->w.DCOrgX + left, dc->w.DCOrgY + bottom - ell_height,
435                       ell_width - 1, ell_height - 1, 180 * 64, 90 * 64 );
436             TSXDrawArc( display, dc->u.x.drawable, dc->u.x.gc,
437                       dc->w.DCOrgX + right - ell_width,
438                       dc->w.DCOrgY + bottom - ell_height,
439                       ell_width - 1, ell_height - 1, 270 * 64, 90 * 64 );
440             TSXDrawArc( display, dc->u.x.drawable, dc->u.x.gc,
441                       dc->w.DCOrgX + right - ell_width, dc->w.DCOrgY + top,
442                       ell_width - 1, ell_height - 1, 0, 90 * 64 );
443         }
444         if (ell_width < right - left)
445         {
446             TSXDrawLine( display, dc->u.x.drawable, dc->u.x.gc, 
447                        dc->w.DCOrgX + left + ell_width / 2 - 2,
448                        dc->w.DCOrgY + top,
449                        dc->w.DCOrgX + right - ell_width / 2,
450                        dc->w.DCOrgY + top);
451             TSXDrawLine( display, dc->u.x.drawable, dc->u.x.gc, 
452                        dc->w.DCOrgX + left + ell_width / 2 - 2,
453                        dc->w.DCOrgY + bottom - 1,
454                        dc->w.DCOrgX + right - ell_width / 2,
455                        dc->w.DCOrgY + bottom - 1);
456         }
457         if (ell_height < bottom - top)
458         {
459             TSXDrawLine( display, dc->u.x.drawable, dc->u.x.gc, 
460                        dc->w.DCOrgX + right - 1,
461                        dc->w.DCOrgY + top + ell_height / 2 - 1,
462                        dc->w.DCOrgX + right - 1,
463                        dc->w.DCOrgY + bottom - ell_height / 2);
464             TSXDrawLine( display, dc->u.x.drawable, dc->u.x.gc, 
465                        dc->w.DCOrgX + left,
466                        dc->w.DCOrgY + top + ell_height / 2 - 1,
467                        dc->w.DCOrgX + left,
468                        dc->w.DCOrgY + bottom - ell_height / 2);
469         }
470     }
471     dc->u.x.pen.width=oldwidth;
472     return TRUE;
473 }
474
475
476 /***********************************************************************
477  *           X11DRV_SetPixel
478  */
479 COLORREF
480 X11DRV_SetPixel( DC *dc, INT32 x, INT32 y, COLORREF color )
481 {
482     Pixel pixel;
483     
484     x = dc->w.DCOrgX + XLPTODP( dc, x );
485     y = dc->w.DCOrgY + YLPTODP( dc, y );
486     pixel = COLOR_ToPhysical( dc, color );
487     
488     TSXSetForeground( display, dc->u.x.gc, pixel );
489     TSXSetFunction( display, dc->u.x.gc, GXcopy );
490     TSXDrawPoint( display, dc->u.x.drawable, dc->u.x.gc, x, y );
491
492     /* inefficient but simple... */
493
494     return COLOR_ToLogical(pixel);
495 }
496
497
498 /***********************************************************************
499  *           X11DRV_GetPixel
500  */
501 COLORREF
502 X11DRV_GetPixel( DC *dc, INT32 x, INT32 y )
503 {
504     static Pixmap pixmap = 0;
505     XImage * image;
506     int pixel;
507
508     x = dc->w.DCOrgX + XLPTODP( dc, x );
509     y = dc->w.DCOrgY + YLPTODP( dc, y );
510     EnterCriticalSection( &X11DRV_CritSection );
511     if (dc->w.flags & DC_MEMORY)
512     {
513         image = XGetImage( display, dc->u.x.drawable, x, y, 1, 1,
514                            AllPlanes, ZPixmap );
515     }
516     else
517     {
518         /* If we are reading from the screen, use a temporary copy */
519         /* to avoid a BadMatch error */
520         if (!pixmap) pixmap = XCreatePixmap( display, rootWindow,
521                                              1, 1, dc->w.bitsPerPixel );
522         XCopyArea( display, dc->u.x.drawable, pixmap, BITMAP_colorGC,
523                    x, y, 1, 1, 0, 0 );
524         image = XGetImage( display, pixmap, 0, 0, 1, 1, AllPlanes, ZPixmap );
525     }
526     pixel = XGetPixel( image, 0, 0 );
527     XDestroyImage( image );
528     LeaveCriticalSection( &X11DRV_CritSection );
529     
530     return COLOR_ToLogical(pixel);
531 }
532
533
534 /***********************************************************************
535  *           X11DRV_PaintRgn
536  */
537 BOOL32
538 X11DRV_PaintRgn( DC *dc, HRGN32 hrgn )
539 {
540     RECT32 box;
541     HRGN32 tmpVisRgn, prevVisRgn;
542     HDC32  hdc = dc->hSelf; /* FIXME: should not mix dc/hdc this way */
543
544     if (!(tmpVisRgn = CreateRectRgn32( 0, 0, 0, 0 ))) return FALSE;
545
546       /* Transform region into device co-ords */
547     if (!REGION_LPTODP( hdc, tmpVisRgn, hrgn )) {
548         DeleteObject32( tmpVisRgn );
549         return FALSE;
550     }
551
552       /* Modify visible region */
553     if (!(prevVisRgn = SaveVisRgn( hdc ))) {
554         DeleteObject32( tmpVisRgn );
555         return FALSE;
556     }
557     CombineRgn32( tmpVisRgn, prevVisRgn, tmpVisRgn, RGN_AND );
558     SelectVisRgn( hdc, tmpVisRgn );
559     DeleteObject32( tmpVisRgn );
560
561       /* Fill the region */
562
563     GetRgnBox32( dc->w.hGCClipRgn, &box );
564     if (DC_SetupGCForBrush( dc ))
565         TSXFillRectangle( display, dc->u.x.drawable, dc->u.x.gc,
566                         dc->w.DCOrgX + box.left, dc->w.DCOrgY + box.top,
567                         box.right-box.left, box.bottom-box.top );
568
569       /* Restore the visible region */
570
571     RestoreVisRgn( hdc );
572     return TRUE;
573 }
574
575 /**********************************************************************
576  *          X11DRV_Polyline
577  */
578 BOOL32
579 X11DRV_Polyline( DC *dc, const LPPOINT32 pt, INT32 count )
580 {
581     register int i;
582
583     if (DC_SetupGCForPen( dc ))
584         for (i = 0; i < count-1; i ++)
585             TSXDrawLine (display, dc->u.x.drawable, dc->u.x.gc,  
586                        dc->w.DCOrgX + XLPTODP(dc, pt [i].x),
587                        dc->w.DCOrgY + YLPTODP(dc, pt [i].y),
588                        dc->w.DCOrgX + XLPTODP(dc, pt [i+1].x),
589                        dc->w.DCOrgY + YLPTODP(dc, pt [i+1].y));
590     return TRUE;
591 }
592
593
594 /**********************************************************************
595  *          X11DRV_Polygon
596  */
597 BOOL32
598 X11DRV_Polygon( DC *dc, LPPOINT32 pt, INT32 count )
599 {
600     register int i;
601     XPoint *points;
602
603     points = (XPoint *) xmalloc (sizeof (XPoint) * (count+1));
604     for (i = 0; i < count; i++)
605     {
606         points[i].x = dc->w.DCOrgX + XLPTODP( dc, pt[i].x );
607         points[i].y = dc->w.DCOrgY + YLPTODP( dc, pt[i].y );
608     }
609     points[count] = points[0];
610
611     if (DC_SetupGCForBrush( dc ))
612         TSXFillPolygon( display, dc->u.x.drawable, dc->u.x.gc,
613                      points, count+1, Complex, CoordModeOrigin);
614
615     if (DC_SetupGCForPen ( dc ))
616         TSXDrawLines( display, dc->u.x.drawable, dc->u.x.gc,
617                    points, count+1, CoordModeOrigin );
618
619     free( points );
620     return TRUE;
621 }
622
623
624 /**********************************************************************
625  *          X11DRV_PolyPolygon
626  */
627 BOOL32 
628 X11DRV_PolyPolygon( DC *dc, LPPOINT32 pt, LPINT32 counts, UINT32 polygons)
629 {
630     HRGN32 hrgn;
631
632       /* FIXME: The points should be converted to device coords before */
633       /* creating the region. But as CreatePolyPolygonRgn is not */
634       /* really correct either, it doesn't matter much... */
635       /* At least the outline will be correct :-) */
636     hrgn = CreatePolyPolygonRgn32( pt, counts, polygons, dc->w.polyFillMode );
637     X11DRV_PaintRgn( dc, hrgn );
638     DeleteObject32( hrgn );
639
640       /* Draw the outline of the polygons */
641
642     if (DC_SetupGCForPen ( dc ))
643     {
644         int i, j, max = 0;
645         XPoint *points;
646
647         for (i = 0; i < polygons; i++) if (counts[i] > max) max = counts[i];
648         points = (XPoint *) xmalloc( sizeof(XPoint) * (max+1) );
649
650         for (i = 0; i < polygons; i++)
651         {
652             for (j = 0; j < counts[i]; j++)
653             {
654                 points[j].x = dc->w.DCOrgX + XLPTODP( dc, pt->x );
655                 points[j].y = dc->w.DCOrgY + YLPTODP( dc, pt->y );
656                 pt++;
657             }
658             points[j] = points[0];
659             TSXDrawLines( display, dc->u.x.drawable, dc->u.x.gc,
660                         points, j + 1, CoordModeOrigin );
661         }
662         free( points );
663     }
664     return TRUE;
665 }
666
667
668 /**********************************************************************
669  *          X11DRV_PolyPolyline
670  */
671 BOOL32 
672 X11DRV_PolyPolyline( DC *dc, LPPOINT32 pt, LPINT32 counts, UINT32 polylines )
673 {
674     if (DC_SetupGCForPen ( dc ))
675     {
676         int i, j, max = 0;
677         XPoint *points;
678
679         for (i = 0; i < polylines; i++) if (counts[i] > max) max = counts[i];
680         points = (XPoint *) xmalloc( sizeof(XPoint) * (max+1) );
681
682         for (i = 0; i < polylines; i++)
683         {
684             for (j = 0; j < counts[i]; j++)
685             {
686                 points[j].x = dc->w.DCOrgX + XLPTODP( dc, pt->x );
687                 points[j].y = dc->w.DCOrgY + YLPTODP( dc, pt->y );
688                 pt++;
689             }
690             points[j] = points[0];
691             TSXDrawLines( display, dc->u.x.drawable, dc->u.x.gc,
692                         points, j + 1, CoordModeOrigin );
693         }
694         free( points );
695     }
696     return TRUE;
697 }
698
699
700 /**********************************************************************
701  *          X11DRV_InternalFloodFill
702  *
703  * Internal helper function for flood fill.
704  * (xorg,yorg) is the origin of the X image relative to the drawable.
705  * (x,y) is relative to the origin of the X image.
706  */
707 static void X11DRV_InternalFloodFill(XImage *image, DC *dc,
708                                      int x, int y,
709                                      int xOrg, int yOrg,
710                                      Pixel pixel, WORD fillType )
711 {
712     int left, right;
713
714 #define TO_FLOOD(x,y)  ((fillType == FLOODFILLBORDER) ? \
715                         (XGetPixel(image,x,y) != pixel) : \
716                         (XGetPixel(image,x,y) == pixel))
717
718     if (!TO_FLOOD(x,y)) return;
719
720       /* Find left and right boundaries */
721
722     left = right = x;
723     while ((left > 0) && TO_FLOOD( left-1, y )) left--;
724     while ((right < image->width) && TO_FLOOD( right, y )) right++;
725     XFillRectangle( display, dc->u.x.drawable, dc->u.x.gc,
726                     xOrg + left, yOrg + y, right-left, 1 );
727
728       /* Set the pixels of this line so we don't fill it again */
729
730     for (x = left; x < right; x++)
731     {
732         if (fillType == FLOODFILLBORDER) XPutPixel( image, x, y, pixel );
733         else XPutPixel( image, x, y, ~pixel );
734     }
735
736       /* Fill the line above */
737
738     if (--y >= 0)
739     {
740         x = left;
741         while (x < right)
742         {
743             while ((x < right) && !TO_FLOOD(x,y)) x++;
744             if (x >= right) break;
745             while ((x < right) && TO_FLOOD(x,y)) x++;
746             X11DRV_InternalFloodFill(image, dc, x-1, y,
747                                      xOrg, yOrg, pixel, fillType );
748         }
749     }
750
751       /* Fill the line below */
752
753     if ((y += 2) < image->height)
754     {
755         x = left;
756         while (x < right)
757         {
758             while ((x < right) && !TO_FLOOD(x,y)) x++;
759             if (x >= right) break;
760             while ((x < right) && TO_FLOOD(x,y)) x++;
761             X11DRV_InternalFloodFill(image, dc, x-1, y,
762                                      xOrg, yOrg, pixel, fillType );
763         }
764     }
765 #undef TO_FLOOD    
766 }
767
768
769 /**********************************************************************
770  *          X11DRV_DoFloodFill
771  *
772  * Main flood-fill routine.
773  *
774  * The Xlib critical section must be entered before calling this function.
775  */
776
777 struct FloodFill_params
778 {
779     DC      *dc;
780     INT32    x;
781     INT32    y;
782     COLORREF color;
783     UINT32   fillType;
784 };
785
786 static BOOL32 X11DRV_DoFloodFill( const struct FloodFill_params *params )
787 {
788     XImage *image;
789     RECT32 rect;
790     DC *dc = params->dc;
791
792     if (GetRgnBox32( dc->w.hGCClipRgn, &rect ) == ERROR) return FALSE;
793
794     if (!(image = XGetImage( display, dc->u.x.drawable,
795                              dc->w.DCOrgX + rect.left,
796                              dc->w.DCOrgY + rect.top,
797                              rect.right - rect.left,
798                              rect.bottom - rect.top,
799                              AllPlanes, ZPixmap ))) return FALSE;
800
801     if (DC_SetupGCForBrush( dc ))
802     {
803           /* ROP mode is always GXcopy for flood-fill */
804         XSetFunction( display, dc->u.x.gc, GXcopy );
805         X11DRV_InternalFloodFill(image, dc,
806                                  XLPTODP(dc,params->x) - rect.left,
807                                  YLPTODP(dc,params->y) - rect.top,
808                                  dc->w.DCOrgX + rect.left,
809                                  dc->w.DCOrgY + rect.top,
810                                  COLOR_ToPhysical( dc, params->color ),
811                                  params->fillType );
812     }
813
814     XDestroyImage( image );
815     return TRUE;
816 }
817
818
819 /**********************************************************************
820  *          X11DRV_ExtFloodFill
821  */
822 BOOL32
823 X11DRV_ExtFloodFill( DC *dc, INT32 x, INT32 y, COLORREF color,
824                      UINT32 fillType )
825 {
826     BOOL32 result;
827     struct FloodFill_params params = { dc, x, y, color, fillType };
828
829     TRACE(graphics, "X11DRV_ExtFloodFill %d,%d %06lx %d\n",
830                       x, y, color, fillType );
831
832     if (!PtVisible32( dc->hSelf, x, y )) return FALSE;
833     EnterCriticalSection( &X11DRV_CritSection );
834     result = CALL_LARGE_STACK( X11DRV_DoFloodFill, &params );
835     LeaveCriticalSection( &X11DRV_CritSection );
836     return result;
837 }