Stop X11DRV_RoundRect calling XDrawArc with -ve width/height params
[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 #define ABS(x)    ((x)<0?(-(x)):(x))
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  */
83 static BOOL32
84 X11DRV_DrawArc( DC *dc, INT32 left, INT32 top, INT32 right,
85                 INT32 bottom, INT32 xstart, INT32 ystart,
86                 INT32 xend, INT32 yend, INT32 lines )
87 {
88     INT32 xcenter, ycenter, istart_angle, idiff_angle;
89     INT32 width, oldwidth, oldendcap;
90     double start_angle, end_angle;
91     XPoint points[4];
92
93     left   = XLPTODP( dc, left );
94     top    = YLPTODP( dc, top );
95     right  = XLPTODP( dc, right );
96     bottom = YLPTODP( dc, bottom );
97     xstart = XLPTODP( dc, xstart );
98     ystart = YLPTODP( dc, ystart );
99     xend   = XLPTODP( dc, xend );
100     yend   = YLPTODP( dc, yend );
101
102     if (right < left) { INT32 tmp = right; right = left; left = tmp; }
103     if (bottom < top) { INT32 tmp = bottom; bottom = top; top = tmp; }
104     if ((left == right) || (top == bottom)
105             ||(lines && ((right-left==1)||(bottom-top==1)))) return TRUE;
106
107     oldwidth = width = dc->u.x.pen.width;
108     oldendcap= dc->u.x.pen.endcap;
109     if (!width) width = 1;
110     if(dc->u.x.pen.style == PS_NULL) width = 0;
111
112     if ((dc->u.x.pen.style == PS_INSIDEFRAME))
113     {
114         if (2*width > (right-left)) width=(right-left + 1)/2;
115         if (2*width > (bottom-top)) width=(bottom-top + 1)/2;
116         left   += width / 2;
117         right  -= (width - 1) / 2;
118         top    += width / 2;
119         bottom -= (width - 1) / 2;
120     }
121     if(width == 0) width=1; /* more accurate */
122     dc->u.x.pen.width=width;
123     dc->u.x.pen.endcap=PS_ENDCAP_SQUARE;
124
125     xcenter = (right + left) / 2;
126     ycenter = (bottom + top) / 2;
127     start_angle = atan2( (double)(ycenter-ystart)*(right-left),
128                          (double)(xstart-xcenter)*(bottom-top) );
129     end_angle   = atan2( (double)(ycenter-yend)*(right-left),
130                          (double)(xend-xcenter)*(bottom-top) );
131     if ((xstart==xend)&&(ystart==yend))
132       { /* A lazy program delivers xstart=xend=ystart=yend=0) */
133         start_angle = 0;
134         end_angle = 2* PI;
135       }
136     else /* notorious cases */
137       if ((start_angle == PI)&&( end_angle <0))
138         start_angle = - PI;
139     else
140       if ((end_angle == PI)&&( start_angle <0))
141         end_angle = - PI;
142     istart_angle = (INT32)(start_angle * 180 * 64 / PI + 0.5);
143     idiff_angle  = (INT32)((end_angle - start_angle) * 180 * 64 / PI + 0.5);
144     if (idiff_angle <= 0) idiff_angle += 360 * 64;
145
146       /* Fill arc with brush if Chord() or Pie() */
147
148     if ((lines > 0) && DC_SetupGCForBrush( dc )) {
149         TSXSetArcMode( display, dc->u.x.gc, (lines==1) ? ArcChord : ArcPieSlice);
150         TSXFillArc( display, dc->u.x.drawable, dc->u.x.gc,
151                  dc->w.DCOrgX + left, dc->w.DCOrgY + top,
152                  right-left-1, bottom-top-1, istart_angle, idiff_angle );
153     }
154
155       /* Draw arc and lines */
156
157     if (DC_SetupGCForPen( dc )){
158     TSXDrawArc( display, dc->u.x.drawable, dc->u.x.gc,
159               dc->w.DCOrgX + left, dc->w.DCOrgY + top,
160               right-left-1, bottom-top-1, istart_angle, idiff_angle );
161         if (lines) {
162             /* use the truncated values */
163             start_angle=(double)istart_angle*PI/64./180.;
164             end_angle=(double)(istart_angle+idiff_angle)*PI/64./180.;
165             /* calculate the endpoints and round correctly */
166             points[0].x = (int) floor(dc->w.DCOrgX + (right+left)/2.0 +
167                     cos(start_angle) * (right-left-width*2+2) / 2. + 0.5);
168             points[0].y = (int) floor(dc->w.DCOrgY + (top+bottom)/2.0 -
169                     sin(start_angle) * (bottom-top-width*2+2) / 2. + 0.5);
170             points[1].x = (int) floor(dc->w.DCOrgX + (right+left)/2.0 +
171                     cos(end_angle) * (right-left-width*2+2) / 2. + 0.5);
172             points[1].y = (int) floor(dc->w.DCOrgY + (top+bottom)/2.0 -
173                     sin(end_angle) * (bottom-top-width*2+2) / 2. + 0.5);
174                     
175             /* OK this stuff is optimized for Xfree86 
176              * which is probably the most used server by
177              * wine users. Other X servers will not 
178              * display correctly. (eXceed for instance)
179              * so if you feel you must change make sure that
180              * you either use Xfree86 or seperate your changes 
181              * from these (compile switch or whatever)
182              */
183             if (lines == 2) {
184                 INT32 dx1,dy1;
185                 points[3] = points[1];
186         points[1].x = dc->w.DCOrgX + xcenter;
187         points[1].y = dc->w.DCOrgY + ycenter;
188                 points[2] = points[1];
189                 dx1=points[1].x-points[0].x;
190                 dy1=points[1].y-points[0].y;
191                 if(((top-bottom) | -2) == -2)
192                     if(dy1>0) points[1].y--;
193                 if(dx1<0) {
194                     if (((-dx1)*64)<=ABS(dy1)*37) points[0].x--;
195                     if(((-dx1*9))<(dy1*16)) points[0].y--;
196                     if( dy1<0 && ((dx1*9)) < (dy1*16)) points[0].y--;
197                 } else {
198                     if(dy1 < 0)  points[0].y--;
199                     if(((right-left) | -2) == -2) points[1].x--;
200                 }
201                 dx1=points[3].x-points[2].x;
202                 dy1=points[3].y-points[2].y;
203                 if(((top-bottom) | -2 ) == -2)
204                     if(dy1 < 0) points[2].y--;
205                 if( dx1<0){ 
206                     if( dy1>0) points[3].y--;
207                     if(((right-left) | -2) == -2 ) points[2].x--;
208                 }else {
209                     points[3].y--;
210                     if( dx1 * 64 < dy1 * -37 ) points[3].x--;
211                 }
212                 lines++;
213     }
214     TSXDrawLines( display, dc->u.x.drawable, dc->u.x.gc,
215                 points, lines+1, CoordModeOrigin );
216         }
217     }
218     dc->u.x.pen.width=oldwidth;
219     dc->u.x.pen.endcap=oldendcap;
220     return TRUE;
221 }
222
223
224 /***********************************************************************
225  *           X11DRV_Arc
226  */
227 BOOL32
228 X11DRV_Arc( DC *dc, INT32 left, INT32 top, INT32 right, INT32 bottom,
229             INT32 xstart, INT32 ystart, INT32 xend, INT32 yend )
230 {
231     return X11DRV_DrawArc( dc, left, top, right, bottom,
232                            xstart, ystart, xend, yend, 0 );
233 }
234
235
236 /***********************************************************************
237  *           X11DRV_Pie
238  */
239 BOOL32
240 X11DRV_Pie( DC *dc, INT32 left, INT32 top, INT32 right, INT32 bottom,
241             INT32 xstart, INT32 ystart, INT32 xend, INT32 yend )
242 {
243     return X11DRV_DrawArc( dc, left, top, right, bottom,
244                            xstart, ystart, xend, yend, 2 );
245 }
246
247 /***********************************************************************
248  *           X11DRV_Chord
249  */
250 BOOL32
251 X11DRV_Chord( DC *dc, INT32 left, INT32 top, INT32 right, INT32 bottom,
252               INT32 xstart, INT32 ystart, INT32 xend, INT32 yend )
253 {
254     return X11DRV_DrawArc( dc, left, top, right, bottom,
255                            xstart, ystart, xend, yend, 1 );
256 }
257
258
259 /***********************************************************************
260  *           X11DRV_Ellipse
261  */
262 BOOL32
263 X11DRV_Ellipse( DC *dc, INT32 left, INT32 top, INT32 right, INT32 bottom )
264 {
265     INT32 width, oldwidth;
266     left   = XLPTODP( dc, left );
267     top    = YLPTODP( dc, top );
268     right  = XLPTODP( dc, right );
269     bottom = YLPTODP( dc, bottom );
270     if ((left == right) || (top == bottom)) return TRUE;
271
272     if (right < left) { INT32 tmp = right; right = left; left = tmp; }
273     if (bottom < top) { INT32 tmp = bottom; bottom = top; top = tmp; }
274     
275     oldwidth = width = dc->u.x.pen.width;
276     if (!width) width = 1;
277     if(dc->u.x.pen.style == PS_NULL) width = 0;
278
279     if ((dc->u.x.pen.style == PS_INSIDEFRAME))
280     {
281         if (2*width > (right-left)) width=(right-left + 1)/2;
282         if (2*width > (bottom-top)) width=(bottom-top + 1)/2;
283         left   += width / 2;
284         right  -= (width - 1) / 2;
285         top    += width / 2;
286         bottom -= (width - 1) / 2;
287     }
288     if(width == 0) width=1; /* more accurate */
289     dc->u.x.pen.width=width;
290
291     if (DC_SetupGCForBrush( dc ))
292         TSXFillArc( 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, 0, 360*64 );
295     if (DC_SetupGCForPen( dc ))
296         TSXDrawArc( display, dc->u.x.drawable, dc->u.x.gc,
297                   dc->w.DCOrgX + left, dc->w.DCOrgY + top,
298                   right-left-1, bottom-top-1, 0, 360*64 );
299     dc->u.x.pen.width=oldwidth;
300     return TRUE;
301 }
302
303
304 /***********************************************************************
305  *           X11DRV_Rectangle
306  */
307 BOOL32
308 X11DRV_Rectangle(DC *dc, INT32 left, INT32 top, INT32 right, INT32 bottom)
309 {
310     INT32 width, oldwidth, oldjoinstyle;
311
312     TRACE(graphics, "(%d %d %d %d)\n", 
313         left, top, right, bottom);
314
315     left   = XLPTODP( dc, left );
316     top    = YLPTODP( dc, top );
317     right  = XLPTODP( dc, right );
318     bottom = YLPTODP( dc, bottom );
319
320     if ((left == right) || (top == bottom)) return TRUE;
321
322     if (right < left) { INT32 tmp = right; right = left; left = tmp; }
323     if (bottom < top) { INT32 tmp = bottom; bottom = top; top = tmp; }
324
325     oldwidth = width = dc->u.x.pen.width;
326     if (!width) width = 1;
327     if(dc->u.x.pen.style == PS_NULL) width = 0;
328
329     if ((dc->u.x.pen.style == PS_INSIDEFRAME))
330     {
331         if (2*width > (right-left)) width=(right-left + 1)/2;
332         if (2*width > (bottom-top)) width=(bottom-top + 1)/2;
333         left   += width / 2;
334         right  -= (width - 1) / 2;
335         top    += width / 2;
336         bottom -= (width - 1) / 2;
337     }
338     if(width == 1) width=0;
339     dc->u.x.pen.width=width;
340     oldjoinstyle=dc->u.x.pen.linejoin;
341     if(dc->u.x.pen.type!=PS_GEOMETRIC)
342             dc->u.x.pen.linejoin=PS_JOIN_MITER;
343
344     if ((right > left + width) && (bottom > top + width))
345     {
346         if (DC_SetupGCForBrush( dc ))
347             TSXFillRectangle( display, dc->u.x.drawable, dc->u.x.gc,
348                             dc->w.DCOrgX + left + (width + 1) / 2,
349                             dc->w.DCOrgY + top + (width + 1) / 2,
350                             right-left-width-1, bottom-top-width-1);
351     }
352     if (DC_SetupGCForPen( dc ))
353         TSXDrawRectangle( display, dc->u.x.drawable, dc->u.x.gc,
354                         dc->w.DCOrgX + left, dc->w.DCOrgY + top,
355                         right-left-1, bottom-top-1 );
356
357     dc->u.x.pen.width=oldwidth;
358     dc->u.x.pen.linejoin=oldjoinstyle;
359     return TRUE;
360 }
361
362 /***********************************************************************
363  *           X11DRV_RoundRect
364  */
365 BOOL32
366 X11DRV_RoundRect( DC *dc, INT32 left, INT32 top, INT32 right,
367                   INT32 bottom, INT32 ell_width, INT32 ell_height )
368 {
369     INT32 width, oldwidth, oldendcap;
370
371     TRACE(graphics, "(%d %d %d %d  %d %d\n", 
372         left, top, right, bottom, ell_width, ell_height);
373
374     left   = XLPTODP( dc, left );
375     top    = YLPTODP( dc, top );
376     right  = XLPTODP( dc, right );
377     bottom = YLPTODP( dc, bottom );
378
379     if ((left == right) || (top == bottom))
380         return TRUE;
381
382     /* Make sure ell_width and ell_height are >= 1 otherwise XDrawArc gets
383        called with width/height < 0 */
384     ell_width  = MAX(abs( ell_width * dc->vportExtX / dc->wndExtX ), 1);
385     ell_height = MAX(abs( ell_height * dc->vportExtY / dc->wndExtY ), 1);
386
387     /* Fix the coordinates */
388
389     if (right < left) { INT32 tmp = right; right = left; left = tmp; }
390     if (bottom < top) { INT32 tmp = bottom; bottom = top; top = tmp; }
391
392     oldwidth=width = dc->u.x.pen.width;
393     oldendcap = dc->u.x.pen.endcap;
394     if (!width) width = 1;
395     if(dc->u.x.pen.style == PS_NULL) width = 0;
396
397     if ((dc->u.x.pen.style == PS_INSIDEFRAME))
398     {
399         if (2*width > (right-left)) width=(right-left + 1)/2;
400         if (2*width > (bottom-top)) width=(bottom-top + 1)/2;
401         left   += width / 2;
402         right  -= (width - 1) / 2;
403         top    += width / 2;
404         bottom -= (width - 1) / 2;
405     }
406     if(width == 0) width=1;
407     dc->u.x.pen.width=width;
408     dc->u.x.pen.endcap=PS_ENDCAP_SQUARE;
409
410     if (DC_SetupGCForBrush( dc ))
411     {
412         if (ell_width > (right-left) )
413             if (ell_height > (bottom-top) )
414                     TSXFillArc( display, dc->u.x.drawable, dc->u.x.gc,
415                               dc->w.DCOrgX + left, dc->w.DCOrgY + top,
416                               right - left - 1, bottom - top - 1,
417                               0, 360 * 64 );
418             else{
419                     TSXFillArc( display, dc->u.x.drawable, dc->u.x.gc,
420                               dc->w.DCOrgX + left, dc->w.DCOrgY + top,
421                               right - left - 1, ell_height, 0, 180 * 64 );
422                     TSXFillArc( display, dc->u.x.drawable, dc->u.x.gc,
423                               dc->w.DCOrgX + left,
424                               dc->w.DCOrgY + bottom - ell_height - 1,
425                               right - left - 1, ell_height, 180 * 64, 180 * 64 );
426            }
427         else if (ell_height > (bottom-top) ){
428                 TSXFillArc( display, dc->u.x.drawable, dc->u.x.gc,
429                       dc->w.DCOrgX + left, dc->w.DCOrgY + top,
430                       ell_width, bottom - top - 1, 90 * 64, 180 * 64 );
431                 TSXFillArc( display, dc->u.x.drawable, dc->u.x.gc,
432                       dc->w.DCOrgX + right - ell_width -1, dc->w.DCOrgY + top,
433                       ell_width, bottom - top - 1, 270 * 64, 180 * 64 );
434         }else{
435                 TSXFillArc( display, dc->u.x.drawable, dc->u.x.gc,
436                       dc->w.DCOrgX + left, dc->w.DCOrgY + top,
437                       ell_width, ell_height, 90 * 64, 90 * 64 );
438                 TSXFillArc( display, dc->u.x.drawable, dc->u.x.gc,
439                       dc->w.DCOrgX + left,
440                       dc->w.DCOrgY + bottom - ell_height - 1,
441                       ell_width, ell_height, 180 * 64, 90 * 64 );
442                 TSXFillArc( display, dc->u.x.drawable, dc->u.x.gc,
443                       dc->w.DCOrgX + right - ell_width - 1,
444                       dc->w.DCOrgY + bottom - ell_height - 1,
445                       ell_width, ell_height, 270 * 64, 90 * 64 );
446                 TSXFillArc( display, dc->u.x.drawable, dc->u.x.gc,
447                       dc->w.DCOrgX + right - ell_width - 1,
448                       dc->w.DCOrgY + top,
449                       ell_width, ell_height, 0, 90 * 64 );
450         }
451         if (ell_width < right - left)
452         {
453             TSXFillRectangle( display, dc->u.x.drawable, dc->u.x.gc,
454                             dc->w.DCOrgX + left + (ell_width + 1) / 2,
455                             dc->w.DCOrgY + top + 1,
456                             right - left - ell_width - 1,
457                             (ell_height + 1) / 2 - 1);
458             TSXFillRectangle( display, dc->u.x.drawable, dc->u.x.gc,
459                             dc->w.DCOrgX + left + (ell_width + 1) / 2,
460                             dc->w.DCOrgY + bottom - (ell_height) / 2 - 1,
461                             right - left - ell_width - 1,
462                             (ell_height) / 2 );
463         }
464         if  (ell_height < bottom - top)
465         {
466             TSXFillRectangle( display, dc->u.x.drawable, dc->u.x.gc,
467                             dc->w.DCOrgX + left + 1,
468                             dc->w.DCOrgY + top + (ell_height + 1) / 2,
469                             right - left - 2,
470                             bottom - top - ell_height - 1);
471         }
472     }
473     /* FIXME: this could be done with on X call
474      * more efficient and probably more correct
475      * on any X server: XDrawArcs will draw
476      * straight horizontal and vertical lines
477      * if width or height are zero.
478      *
479      * BTW this stuff is optimized for an Xfree86 server
480      * read the comments inside the X11DRV_DrawArc function
481      */
482     if (DC_SetupGCForPen(dc)) {
483         if (ell_width > (right-left) )
484             if (ell_height > (bottom-top) )
485                 TSXDrawArc( display, dc->u.x.drawable, dc->u.x.gc,
486                       dc->w.DCOrgX + left, dc->w.DCOrgY + top,
487                       right - left - 1, bottom -top - 1, 0 , 360 * 64 );
488             else{
489                 TSXDrawArc( display, dc->u.x.drawable, dc->u.x.gc,
490                       dc->w.DCOrgX + left, dc->w.DCOrgY + top,
491                       right - left - 1, ell_height - 1, 0 , 180 * 64 );
492                 TSXDrawArc( display, dc->u.x.drawable, dc->u.x.gc,
493                       dc->w.DCOrgX + left, 
494                       dc->w.DCOrgY + bottom - ell_height,
495                       right - left - 1, ell_height - 1, 180 * 64 , 180 * 64 );
496             }
497         else if (ell_height > (bottom-top) ){
498                 TSXDrawArc( display, dc->u.x.drawable, dc->u.x.gc,
499                       dc->w.DCOrgX + left, dc->w.DCOrgY + top,
500                       ell_width - 1 , bottom - top - 1, 90 * 64 , 180 * 64 );
501                 TSXDrawArc( display, dc->u.x.drawable, dc->u.x.gc,
502                       dc->w.DCOrgX + right - ell_width, 
503                       dc->w.DCOrgY + top,
504                       ell_width - 1 , bottom - top - 1, 270 * 64 , 180 * 64 );
505         }else{
506             TSXDrawArc( display, dc->u.x.drawable, dc->u.x.gc,
507                       dc->w.DCOrgX + left, dc->w.DCOrgY + top,
508                       ell_width - 1, ell_height - 1, 90 * 64, 90 * 64 );
509             TSXDrawArc( display, dc->u.x.drawable, dc->u.x.gc,
510                       dc->w.DCOrgX + left, dc->w.DCOrgY + bottom - ell_height,
511                       ell_width - 1, ell_height - 1, 180 * 64, 90 * 64 );
512             TSXDrawArc( display, dc->u.x.drawable, dc->u.x.gc,
513                       dc->w.DCOrgX + right - ell_width,
514                       dc->w.DCOrgY + bottom - ell_height,
515                       ell_width - 1, ell_height - 1, 270 * 64, 90 * 64 );
516             TSXDrawArc( display, dc->u.x.drawable, dc->u.x.gc,
517                       dc->w.DCOrgX + right - ell_width, dc->w.DCOrgY + top,
518                       ell_width - 1, ell_height - 1, 0, 90 * 64 );
519         }
520         if (ell_width < right - left)
521         {
522             TSXDrawLine( display, dc->u.x.drawable, dc->u.x.gc, 
523                dc->w.DCOrgX + left + ell_width / 2,
524                        dc->w.DCOrgY + top,
525                dc->w.DCOrgX + right - (ell_width+1) / 2,
526                        dc->w.DCOrgY + top);
527             TSXDrawLine( display, dc->u.x.drawable, dc->u.x.gc, 
528                dc->w.DCOrgX + left + ell_width / 2 ,
529                        dc->w.DCOrgY + bottom - 1,
530                dc->w.DCOrgX + right - (ell_width+1)/ 2,
531                        dc->w.DCOrgY + bottom - 1);
532         }
533         if (ell_height < bottom - top)
534         {
535             TSXDrawLine( display, dc->u.x.drawable, dc->u.x.gc, 
536                        dc->w.DCOrgX + right - 1,
537                dc->w.DCOrgY + top + ell_height / 2,
538                        dc->w.DCOrgX + right - 1,
539                dc->w.DCOrgY + bottom - (ell_height+1) / 2);
540             TSXDrawLine( display, dc->u.x.drawable, dc->u.x.gc, 
541                        dc->w.DCOrgX + left,
542                dc->w.DCOrgY + top + ell_height / 2,
543                        dc->w.DCOrgX + left,
544                dc->w.DCOrgY + bottom - (ell_height+1) / 2);
545         }
546     }
547     dc->u.x.pen.width=oldwidth;
548     dc->u.x.pen.endcap=oldendcap;
549     return TRUE;
550 }
551
552
553 /***********************************************************************
554  *           X11DRV_SetPixel
555  */
556 COLORREF
557 X11DRV_SetPixel( DC *dc, INT32 x, INT32 y, COLORREF color )
558 {
559     Pixel pixel;
560     
561     x = dc->w.DCOrgX + XLPTODP( dc, x );
562     y = dc->w.DCOrgY + YLPTODP( dc, y );
563     pixel = COLOR_ToPhysical( dc, color );
564     
565     TSXSetForeground( display, dc->u.x.gc, pixel );
566     TSXSetFunction( display, dc->u.x.gc, GXcopy );
567     TSXDrawPoint( display, dc->u.x.drawable, dc->u.x.gc, x, y );
568
569     /* inefficient but simple... */
570
571     return COLOR_ToLogical(pixel);
572 }
573
574
575 /***********************************************************************
576  *           X11DRV_GetPixel
577  */
578 COLORREF
579 X11DRV_GetPixel( DC *dc, INT32 x, INT32 y )
580 {
581     static Pixmap pixmap = 0;
582     XImage * image;
583     int pixel;
584
585     x = dc->w.DCOrgX + XLPTODP( dc, x );
586     y = dc->w.DCOrgY + YLPTODP( dc, y );
587     EnterCriticalSection( &X11DRV_CritSection );
588     if (dc->w.flags & DC_MEMORY)
589     {
590         image = XGetImage( display, dc->u.x.drawable, x, y, 1, 1,
591                            AllPlanes, ZPixmap );
592     }
593     else
594     {
595         /* If we are reading from the screen, use a temporary copy */
596         /* to avoid a BadMatch error */
597         if (!pixmap) pixmap = XCreatePixmap( display, rootWindow,
598                                              1, 1, dc->w.bitsPerPixel );
599         XCopyArea( display, dc->u.x.drawable, pixmap, BITMAP_colorGC,
600                    x, y, 1, 1, 0, 0 );
601         image = XGetImage( display, pixmap, 0, 0, 1, 1, AllPlanes, ZPixmap );
602     }
603     pixel = XGetPixel( image, 0, 0 );
604     XDestroyImage( image );
605     LeaveCriticalSection( &X11DRV_CritSection );
606     
607     return COLOR_ToLogical(pixel);
608 }
609
610
611 /***********************************************************************
612  *           X11DRV_PaintRgn
613  */
614 BOOL32
615 X11DRV_PaintRgn( DC *dc, HRGN32 hrgn )
616 {
617     RECT32 box;
618     HRGN32 tmpVisRgn, prevVisRgn;
619     HDC32  hdc = dc->hSelf; /* FIXME: should not mix dc/hdc this way */
620
621     if (!(tmpVisRgn = CreateRectRgn32( 0, 0, 0, 0 ))) return FALSE;
622
623       /* Transform region into device co-ords */
624     if (  !REGION_LPTODP( hdc, tmpVisRgn, hrgn )
625         || OffsetRgn32( tmpVisRgn, dc->w.DCOrgX, dc->w.DCOrgY ) == ERROR) {
626         DeleteObject32( tmpVisRgn );
627         return FALSE;
628     }
629
630       /* Modify visible region */
631     if (!(prevVisRgn = SaveVisRgn( hdc ))) {
632         DeleteObject32( tmpVisRgn );
633         return FALSE;
634     }
635     CombineRgn32( tmpVisRgn, prevVisRgn, tmpVisRgn, RGN_AND );
636     SelectVisRgn( hdc, tmpVisRgn );
637     DeleteObject32( tmpVisRgn );
638
639       /* Fill the region */
640
641     GetRgnBox32( dc->w.hGCClipRgn, &box );
642     if (DC_SetupGCForBrush( dc ))
643         TSXFillRectangle( display, dc->u.x.drawable, dc->u.x.gc,
644                           box.left, box.top,
645                           box.right-box.left, box.bottom-box.top );
646
647       /* Restore the visible region */
648
649     RestoreVisRgn( hdc );
650     return TRUE;
651 }
652
653 /**********************************************************************
654  *          X11DRV_Polyline
655  */
656 BOOL32
657 X11DRV_Polyline( DC *dc, const POINT32* pt, INT32 count )
658 {
659     INT32 oldwidth;
660     register int i;
661     XPoint *points;
662     if((oldwidth=dc->u.x.pen.width)==0) dc->u.x.pen.width=1;
663
664     points = (XPoint *) xmalloc (sizeof (XPoint) * (count));
665     for (i = 0; i < count; i++)
666     {
667     points[i].x = dc->w.DCOrgX + XLPTODP( dc, pt[i].x );
668     points[i].y = dc->w.DCOrgY + YLPTODP( dc, pt[i].y );
669     }
670
671     if (DC_SetupGCForPen ( dc ))
672     TSXDrawLines( display, dc->u.x.drawable, dc->u.x.gc,
673            points, count, CoordModeOrigin );
674
675     free( points );
676     dc->u.x.pen.width=oldwidth;
677     return TRUE;
678 }
679
680
681 /**********************************************************************
682  *          X11DRV_Polygon
683  */
684 BOOL32
685 X11DRV_Polygon( DC *dc, const POINT32* pt, INT32 count )
686 {
687     register int i;
688     XPoint *points;
689
690     points = (XPoint *) xmalloc (sizeof (XPoint) * (count+1));
691     for (i = 0; i < count; i++)
692     {
693         points[i].x = dc->w.DCOrgX + XLPTODP( dc, pt[i].x );
694         points[i].y = dc->w.DCOrgY + YLPTODP( dc, pt[i].y );
695     }
696     points[count] = points[0];
697
698     if (DC_SetupGCForBrush( dc ))
699         TSXFillPolygon( display, dc->u.x.drawable, dc->u.x.gc,
700                      points, count+1, Complex, CoordModeOrigin);
701
702     if (DC_SetupGCForPen ( dc ))
703         TSXDrawLines( display, dc->u.x.drawable, dc->u.x.gc,
704                    points, count+1, CoordModeOrigin );
705
706     free( points );
707     return TRUE;
708 }
709
710
711 /**********************************************************************
712  *          X11DRV_PolyPolygon
713  */
714 BOOL32 
715 X11DRV_PolyPolygon( DC *dc, const POINT32* pt, const INT32* counts, UINT32 polygons)
716 {
717     HRGN32 hrgn;
718
719       /* FIXME: The points should be converted to device coords before */
720       /* creating the region. But as CreatePolyPolygonRgn is not */
721       /* really correct either, it doesn't matter much... */
722       /* At least the outline will be correct :-) */
723     hrgn = CreatePolyPolygonRgn32( pt, counts, polygons, dc->w.polyFillMode );
724     X11DRV_PaintRgn( dc, hrgn );
725     DeleteObject32( hrgn );
726
727       /* Draw the outline of the polygons */
728
729     if (DC_SetupGCForPen ( dc ))
730     {
731         int i, j, max = 0;
732         XPoint *points;
733
734         for (i = 0; i < polygons; i++) if (counts[i] > max) max = counts[i];
735         points = (XPoint *) xmalloc( sizeof(XPoint) * (max+1) );
736
737         for (i = 0; i < polygons; i++)
738         {
739             for (j = 0; j < counts[i]; j++)
740             {
741                 points[j].x = dc->w.DCOrgX + XLPTODP( dc, pt->x );
742                 points[j].y = dc->w.DCOrgY + YLPTODP( dc, pt->y );
743                 pt++;
744             }
745             points[j] = points[0];
746             TSXDrawLines( display, dc->u.x.drawable, dc->u.x.gc,
747                         points, j + 1, CoordModeOrigin );
748         }
749         free( points );
750     }
751     return TRUE;
752 }
753
754
755 /**********************************************************************
756  *          X11DRV_PolyPolyline
757  */
758 BOOL32 
759 X11DRV_PolyPolyline( DC *dc, const POINT32* pt, const DWORD* counts, DWORD polylines )
760 {
761     if (DC_SetupGCForPen ( dc ))
762     {
763         int i, j, max = 0;
764         XPoint *points;
765
766         for (i = 0; i < polylines; i++) if (counts[i] > max) max = counts[i];
767         points = (XPoint *) xmalloc( sizeof(XPoint) * (max+1) );
768
769         for (i = 0; i < polylines; i++)
770         {
771             for (j = 0; j < counts[i]; j++)
772             {
773                 points[j].x = dc->w.DCOrgX + XLPTODP( dc, pt->x );
774                 points[j].y = dc->w.DCOrgY + YLPTODP( dc, pt->y );
775                 pt++;
776             }
777             points[j] = points[0];
778             TSXDrawLines( display, dc->u.x.drawable, dc->u.x.gc,
779                         points, j + 1, CoordModeOrigin );
780         }
781         free( points );
782     }
783     return TRUE;
784 }
785
786
787 /**********************************************************************
788  *          X11DRV_InternalFloodFill
789  *
790  * Internal helper function for flood fill.
791  * (xorg,yorg) is the origin of the X image relative to the drawable.
792  * (x,y) is relative to the origin of the X image.
793  */
794 static void X11DRV_InternalFloodFill(XImage *image, DC *dc,
795                                      int x, int y,
796                                      int xOrg, int yOrg,
797                                      Pixel pixel, WORD fillType )
798 {
799     int left, right;
800
801 #define TO_FLOOD(x,y)  ((fillType == FLOODFILLBORDER) ? \
802                         (XGetPixel(image,x,y) != pixel) : \
803                         (XGetPixel(image,x,y) == pixel))
804
805     if (!TO_FLOOD(x,y)) return;
806
807       /* Find left and right boundaries */
808
809     left = right = x;
810     while ((left > 0) && TO_FLOOD( left-1, y )) left--;
811     while ((right < image->width) && TO_FLOOD( right, y )) right++;
812     XFillRectangle( display, dc->u.x.drawable, dc->u.x.gc,
813                     xOrg + left, yOrg + y, right-left, 1 );
814
815       /* Set the pixels of this line so we don't fill it again */
816
817     for (x = left; x < right; x++)
818     {
819         if (fillType == FLOODFILLBORDER) XPutPixel( image, x, y, pixel );
820         else XPutPixel( image, x, y, ~pixel );
821     }
822
823       /* Fill the line above */
824
825     if (--y >= 0)
826     {
827         x = left;
828         while (x < right)
829         {
830             while ((x < right) && !TO_FLOOD(x,y)) x++;
831             if (x >= right) break;
832             while ((x < right) && TO_FLOOD(x,y)) x++;
833             X11DRV_InternalFloodFill(image, dc, x-1, y,
834                                      xOrg, yOrg, pixel, fillType );
835         }
836     }
837
838       /* Fill the line below */
839
840     if ((y += 2) < image->height)
841     {
842         x = left;
843         while (x < right)
844         {
845             while ((x < right) && !TO_FLOOD(x,y)) x++;
846             if (x >= right) break;
847             while ((x < right) && TO_FLOOD(x,y)) x++;
848             X11DRV_InternalFloodFill(image, dc, x-1, y,
849                                      xOrg, yOrg, pixel, fillType );
850         }
851     }
852 #undef TO_FLOOD    
853 }
854
855
856 /**********************************************************************
857  *          X11DRV_DoFloodFill
858  *
859  * Main flood-fill routine.
860  *
861  * The Xlib critical section must be entered before calling this function.
862  */
863
864 struct FloodFill_params
865 {
866     DC      *dc;
867     INT32    x;
868     INT32    y;
869     COLORREF color;
870     UINT32   fillType;
871 };
872
873 static BOOL32 X11DRV_DoFloodFill( const struct FloodFill_params *params )
874 {
875     XImage *image;
876     RECT32 rect;
877     DC *dc = params->dc;
878
879     if (GetRgnBox32( dc->w.hGCClipRgn, &rect ) == ERROR) return FALSE;
880
881     if (!(image = XGetImage( display, dc->u.x.drawable,
882                              rect.left,
883                              rect.top,
884                              rect.right - rect.left,
885                              rect.bottom - rect.top,
886                              AllPlanes, ZPixmap ))) return FALSE;
887
888     if (DC_SetupGCForBrush( dc ))
889     {
890           /* ROP mode is always GXcopy for flood-fill */
891         XSetFunction( display, dc->u.x.gc, GXcopy );
892         X11DRV_InternalFloodFill(image, dc,
893                                  XLPTODP(dc,params->x) + dc->w.DCOrgX - rect.left,
894                                  YLPTODP(dc,params->y) + dc->w.DCOrgY - rect.top,
895                                  rect.left,
896                                  rect.top,
897                                  COLOR_ToPhysical( dc, params->color ),
898                                  params->fillType );
899     }
900
901     XDestroyImage( image );
902     return TRUE;
903 }
904
905
906 /**********************************************************************
907  *          X11DRV_ExtFloodFill
908  */
909 BOOL32
910 X11DRV_ExtFloodFill( DC *dc, INT32 x, INT32 y, COLORREF color,
911                      UINT32 fillType )
912 {
913     BOOL32 result;
914     struct FloodFill_params params = { dc, x, y, color, fillType };
915
916     TRACE(graphics, "X11DRV_ExtFloodFill %d,%d %06lx %d\n",
917                       x, y, color, fillType );
918
919     if (!PtVisible32( dc->hSelf, x, y )) return FALSE;
920     EnterCriticalSection( &X11DRV_CritSection );
921     result = CALL_LARGE_STACK( X11DRV_DoFloodFill, &params );
922     LeaveCriticalSection( &X11DRV_CritSection );
923     return result;
924 }
925
926 /******************************************************************
927  * 
928  *   *Very* simple bezier drawing code, 
929  *
930  *   It uses a recursive algorithm to divide the curve in a series
931  *   of straight line segements. Not ideal but for me sufficient.
932  *   If you are in need for something better look for some incremental
933  *   algorithm.
934  *
935  *   7 July 1998 Rein Klazes
936  */
937
938  /* 
939   * some macro definitions for bezier drawing
940   *
941   * to avoid trucation errors the coordinates are
942   * shifted upwards. When used in drawing they are
943   * shifted down again, including correct rounding
944   * and avoiding floating point arithmatic
945   * 4 bits should allow 27 bits coordinates which I saw
946   * somewere in the win32 doc's
947   * 
948   */
949
950 #define BEZIERSHIFTBITS 4
951 #define BEZIERSHIFTUP(x)    ((x)<<BEZIERSHIFTBITS)
952 #define BEZIERPIXEL        BEZIERSHIFTUP(1)    
953 #define BEZIERSHIFTDOWN(x)  (((x)+(1<<(BEZIERSHIFTBITS-1)))>>BEZIERSHIFTBITS)
954 /* maximum depth of recursion */
955 #define BEZIERMAXDEPTH  8
956
957 /* size of array to store points on */
958 /* enough for one curve */
959 #define BEZMAXPOINTS    (150)
960
961 /* calculate Bezier average, in this case the middle 
962  * correctly rounded...
963  * */
964
965 #define BEZIERMIDDLE(Mid, P1, P2) \
966     (Mid).x=((P1).x+(P2).x + 1)/2;\
967     (Mid).y=((P1).y+(P2).y + 1)/2;
968     
969 /**********************************************************
970 * BezierCheck helper function to check
971 * that recursion can be terminated
972 *       Points[0] and Points[3] are begin and endpoint
973 *       Points[1] and Points[2] are control points
974 *       level is the recursion depth
975 *       returns true if the recusion can be terminated
976 */
977 static BOOL32 BezierCheck( int level, POINT32 *Points)
978
979     INT32 dx, dy;
980     dx=Points[3].x-Points[0].x;
981     dy=Points[3].y-Points[0].y;
982     if(ABS(dy)<=ABS(dx)){/* shallow line */
983         /* check that control points are between begin and end */
984         if(Points[1].x < Points[0].x){
985             if(Points[1].x < Points[3].x)
986                 return FALSE;
987         }else
988             if(Points[1].x > Points[3].x)
989                 return FALSE;
990         if(Points[2].x < Points[0].x){
991             if(Points[2].x < Points[3].x)
992                 return FALSE;
993         }else
994             if(Points[2].x > Points[3].x)
995                 return FALSE;
996         dx=BEZIERSHIFTDOWN(dx);
997         if(!dx) return TRUE;
998         if(abs(Points[1].y-Points[0].y-(dy/dx)*
999                 BEZIERSHIFTDOWN(Points[1].x-Points[0].x)) > BEZIERPIXEL ||
1000            abs(Points[2].y-Points[0].y-(dy/dx)*
1001                    BEZIERSHIFTDOWN(Points[2].x-Points[0].x)) > BEZIERPIXEL )
1002             return FALSE;
1003         else
1004             return TRUE;
1005     }else{ /* steep line */
1006         /* check that control points are between begin and end */
1007         if(Points[1].y < Points[0].y){
1008             if(Points[1].y < Points[3].y)
1009                 return FALSE;
1010         }else
1011             if(Points[1].y > Points[3].y)
1012                 return FALSE;
1013         if(Points[2].y < Points[0].y){
1014             if(Points[2].y < Points[3].y)
1015                 return FALSE;
1016         }else
1017             if(Points[2].y > Points[3].y)
1018                 return FALSE;
1019         dy=BEZIERSHIFTDOWN(dy);
1020         if(!dy) return TRUE;
1021         if(abs(Points[1].x-Points[0].x-(dx/dy)*
1022                 BEZIERSHIFTDOWN(Points[1].y-Points[0].y)) > BEZIERPIXEL ||
1023            abs(Points[2].x-Points[0].x-(dx/dy)*
1024                    BEZIERSHIFTDOWN(Points[2].y-Points[0].y)) > BEZIERPIXEL )
1025             return FALSE;
1026         else
1027             return TRUE;
1028     }
1029 }
1030     
1031 /***********************************************************************
1032  *           X11DRV_Bezier
1033  *   Draw a -what microsoft calls- bezier curve
1034  *   The routine recursively devides the curve
1035  *   in two parts until a straight line can be drawn
1036  *
1037  *   level      recusion depth counted backwards
1038  *   dc         device context
1039  *   Points     array of begin(0), end(3) and control points(1 and 2)
1040  *   XPoints    array with points calculated sofar
1041  *   *pIx       nr points calculated sofar
1042  *   
1043  */
1044 static void X11DRV_Bezier(int level, DC * dc, POINT32 *Points, 
1045                           XPoint* xpoints, unsigned int* pIx)
1046 {
1047     if(*pIx == BEZMAXPOINTS){
1048         TSXDrawLines( display, dc->u.x.drawable, dc->u.x.gc,
1049                     xpoints, *pIx, CoordModeOrigin );
1050         *pIx=0;
1051     }
1052     if(!level || BezierCheck(level, Points)) {
1053         if(*pIx == 0){
1054             xpoints[*pIx].x= dc->w.DCOrgX + BEZIERSHIFTDOWN(Points[0].x);
1055             xpoints[*pIx].y= dc->w.DCOrgY + BEZIERSHIFTDOWN(Points[0].y);
1056             *pIx=1;
1057         }
1058         xpoints[*pIx].x= dc->w.DCOrgX + BEZIERSHIFTDOWN(Points[3].x);
1059         xpoints[*pIx].y= dc->w.DCOrgY + BEZIERSHIFTDOWN(Points[3].y);
1060         (*pIx) ++;
1061     } else {
1062         POINT32 Points2[4]; /* for the second recursive call */
1063         Points2[3]=Points[3];
1064         BEZIERMIDDLE(Points2[2], Points[2], Points[3]);
1065         BEZIERMIDDLE(Points2[0], Points[1], Points[2]);
1066         BEZIERMIDDLE(Points2[1],Points2[0],Points2[2]);
1067
1068         BEZIERMIDDLE(Points[1], Points[0],  Points[1]);
1069         BEZIERMIDDLE(Points[2], Points[1], Points2[0]);
1070         BEZIERMIDDLE(Points[3], Points[2], Points2[1]);
1071
1072         Points2[0]=Points[3];
1073
1074         /* do the two halves */
1075         X11DRV_Bezier(level-1, dc, Points, xpoints, pIx);
1076         X11DRV_Bezier(level-1, dc, Points2, xpoints, pIx);
1077     }
1078 }
1079
1080 /***********************************************************************
1081  *           X11DRV_PolyBezier
1082  *      Implement functionality for PolyBezier and PolyBezierTo
1083  *      calls. 
1084  *      [i] dc pointer to device context
1085  *      [i] start, first point in curve
1086  *      [i] BezierPoints , array of point filled with rest of the points
1087  *      [i] count, number of points in BezierPoints, must be a 
1088  *          multiple of 3.
1089  */
1090 BOOL32
1091 X11DRV_PolyBezier(DC *dc, POINT32 start, const POINT32* BezierPoints, DWORD count)
1092 {
1093     POINT32 Points[4]; 
1094     int i;
1095     unsigned int ix=0;
1096     XPoint* xpoints;
1097     TRACE(graphics, "dc=%04x count=%ld %d,%d - %d,%d - %d,%d -%d,%d \n", 
1098             (int)dc, count,
1099             start.x, start.y,
1100             (Points+0)->x, (Points+0)->y, 
1101             (Points+1)->x, (Points+1)->y, 
1102             (Points+2)->x, (Points+2)->y); 
1103     if(!count || count % 3){/* paranoid */
1104         WARN(graphics," bad value for count : %ld\n", count);
1105         return FALSE; 
1106     }
1107     xpoints=(XPoint*) xmalloc( sizeof(XPoint)*BEZMAXPOINTS);
1108     Points[3].x=BEZIERSHIFTUP(XLPTODP(dc,start.x));
1109     Points[3].y=BEZIERSHIFTUP(YLPTODP(dc,start.y));
1110     while(count){
1111         Points[0]=Points[3];
1112         for(i=1;i<4;i++) {
1113             Points[i].x= BEZIERSHIFTUP(XLPTODP(dc,BezierPoints->x));
1114             Points[i].y= BEZIERSHIFTUP(YLPTODP(dc,BezierPoints->y));
1115             BezierPoints++;
1116         }
1117         X11DRV_Bezier(BEZIERMAXDEPTH , dc, Points, xpoints, &ix );
1118         count -=3;
1119     }
1120     if( ix) TSXDrawLines( display, dc->u.x.drawable, dc->u.x.gc,
1121                 xpoints, ix, CoordModeOrigin );
1122     free(xpoints);
1123     return TRUE;
1124 }
1125
1126 /**********************************************************************
1127  *          X11DRV_SetBkColor
1128  */
1129 COLORREF
1130 X11DRV_SetBkColor( DC *dc, COLORREF color )
1131 {
1132     X11DRV_PDEVICE *physDev = (X11DRV_PDEVICE *)dc->physDev;
1133     COLORREF oldColor;
1134
1135     oldColor = dc->w.backgroundColor;
1136     dc->w.backgroundColor = color;
1137
1138     physDev->backgroundPixel = COLOR_ToPhysical( dc, color );
1139
1140     return oldColor;
1141 }
1142
1143 /**********************************************************************
1144  *          X11DRV_SetTextColor
1145  */
1146 COLORREF
1147 X11DRV_SetTextColor( DC *dc, COLORREF color )
1148 {
1149     X11DRV_PDEVICE *physDev = (X11DRV_PDEVICE *)dc->physDev;
1150     COLORREF oldColor;
1151
1152     oldColor = dc->w.textColor;
1153     dc->w.textColor = color;
1154
1155     physDev->textPixel = COLOR_ToPhysical( dc, color );
1156
1157     return oldColor;
1158 }