Windows doesnt allow dashed and dotted lines > 1.
[wine] / graphics / x11drv / graphics.c
1 /*
2  * X11 graphics driver graphics functions
3  *
4  * Copyright 1993,1994 Alexandre Julliard
5  */
6
7 /*
8  * FIXME: none of these functions obey the GM_ADVANCED
9  * graphics mode
10  */
11
12 #include "config.h"
13
14 #ifndef X_DISPLAY_MISSING
15
16 #include <X11/Intrinsic.h>
17 #include "ts_xlib.h"
18 #include "ts_xutil.h"
19
20 #include <math.h>
21 #ifdef HAVE_FLOAT_H
22 # include <float.h>
23 #endif
24 #include <stdlib.h>
25 #ifndef PI
26 #define PI M_PI
27 #endif
28 #include <string.h>
29
30 #include "x11drv.h"
31 #include "x11font.h"
32 #include "bitmap.h"
33 #include "gdi.h"
34 #include "dc.h"
35 #include "monitor.h"
36 #include "bitmap.h"
37 #include "callback.h"
38 #include "metafile.h"
39 #include "palette.h"
40 #include "color.h"
41 #include "region.h"
42 #include "struct32.h"
43 #include "debug.h"
44 #include "xmalloc.h"
45
46 #define ABS(x)    ((x)<0?(-(x)):(x))
47
48   /* ROP code to GC function conversion */
49 const int X11DRV_XROPfunction[16] =
50 {
51     GXclear,        /* R2_BLACK */
52     GXnor,          /* R2_NOTMERGEPEN */
53     GXandInverted,  /* R2_MASKNOTPEN */
54     GXcopyInverted, /* R2_NOTCOPYPEN */
55     GXandReverse,   /* R2_MASKPENNOT */
56     GXinvert,       /* R2_NOT */
57     GXxor,          /* R2_XORPEN */
58     GXnand,         /* R2_NOTMASKPEN */
59     GXand,          /* R2_MASKPEN */
60     GXequiv,        /* R2_NOTXORPEN */
61     GXnoop,         /* R2_NOP */
62     GXorInverted,   /* R2_MERGENOTPEN */
63     GXcopy,         /* R2_COPYPEN */
64     GXorReverse,    /* R2_MERGEPENNOT */
65     GXor,           /* R2_MERGEPEN */
66     GXset           /* R2_WHITE */
67 };
68
69
70 /***********************************************************************
71  *           X11DRV_SetupGCForPatBlt
72  *
73  * Setup the GC for a PatBlt operation using current brush.
74  * If fMapColors is TRUE, X pixels are mapped to Windows colors.
75  * Return FALSE if brush is BS_NULL, TRUE otherwise.
76  */
77 BOOL X11DRV_SetupGCForPatBlt( DC * dc, GC gc, BOOL fMapColors )
78 {
79     XGCValues val;
80     unsigned long mask;
81     Pixmap pixmap = 0;
82     X11DRV_PDEVICE *physDev = (X11DRV_PDEVICE *)dc->physDev;
83
84     if (physDev->brush.style == BS_NULL) return FALSE;
85     if (physDev->brush.pixel == -1)
86     {
87         /* Special case used for monochrome pattern brushes.
88          * We need to swap foreground and background because
89          * Windows does it the wrong way...
90          */
91         val.foreground = physDev->backgroundPixel;
92         val.background = physDev->textPixel;
93     }
94     else
95     {
96         val.foreground = physDev->brush.pixel;
97         val.background = physDev->backgroundPixel;
98     }
99     if (fMapColors && COLOR_PixelToPalette)
100     {
101         val.foreground = COLOR_PixelToPalette[val.foreground];
102         val.background = COLOR_PixelToPalette[val.background];
103     }
104
105     if (dc->w.flags & DC_DIRTY) CLIPPING_UpdateGCRegion(dc);
106
107     val.function = X11DRV_XROPfunction[dc->w.ROPmode-1];
108     /*
109     ** Let's replace GXinvert by GXxor with (black xor white)
110     ** This solves the selection color and leak problems in excel
111     ** FIXME : Let's do that only if we work with X-pixels, not with Win-pixels
112     */
113     if (val.function == GXinvert)
114         {
115         val.foreground = BlackPixelOfScreen(X11DRV_GetXScreen()) ^ WhitePixelOfScreen(X11DRV_GetXScreen());
116         val.function = GXxor;
117         }
118     val.fill_style = physDev->brush.fillStyle;
119     switch(val.fill_style)
120     {
121     case FillStippled:
122     case FillOpaqueStippled:
123         if (dc->w.backgroundMode==OPAQUE) val.fill_style = FillOpaqueStippled;
124         val.stipple = physDev->brush.pixmap;
125         mask = GCStipple;
126         break;
127
128     case FillTiled:
129         if (fMapColors && COLOR_PixelToPalette)
130         {
131             register int x, y;
132             XImage *image;
133             EnterCriticalSection( &X11DRV_CritSection );
134             pixmap = XCreatePixmap( display, 
135                                     X11DRV_GetXRootWindow(), 
136                                     8, 8, 
137                                     MONITOR_GetDepth(&MONITOR_PrimaryMonitor) );
138             image = XGetImage( display, physDev->brush.pixmap, 0, 0, 8, 8,
139                                AllPlanes, ZPixmap );
140             for (y = 0; y < 8; y++)
141                 for (x = 0; x < 8; x++)
142                     XPutPixel( image, x, y,
143                                COLOR_PixelToPalette[XGetPixel( image, x, y)] );
144             XPutImage( display, pixmap, gc, image, 0, 0, 0, 0, 8, 8 );
145             XDestroyImage( image );
146             LeaveCriticalSection( &X11DRV_CritSection );
147             val.tile = pixmap;
148         }
149         else val.tile = physDev->brush.pixmap;
150         mask = GCTile;
151         break;
152
153     default:
154         mask = 0;
155         break;
156     }
157     val.ts_x_origin = dc->w.DCOrgX + dc->w.brushOrgX;
158     val.ts_y_origin = dc->w.DCOrgY + dc->w.brushOrgY;
159     val.fill_rule = (dc->w.polyFillMode==WINDING) ? WindingRule : EvenOddRule;
160     TSXChangeGC( display, gc, 
161                GCFunction | GCForeground | GCBackground | GCFillStyle |
162                GCFillRule | GCTileStipXOrigin | GCTileStipYOrigin | mask,
163                &val );
164     if (pixmap) TSXFreePixmap( display, pixmap );
165     return TRUE;
166 }
167
168
169 /***********************************************************************
170  *           X11DRV_SetupGCForBrush
171  *
172  * Setup physDev->gc for drawing operations using current brush.
173  * Return FALSE if brush is BS_NULL, TRUE otherwise.
174  */
175 BOOL X11DRV_SetupGCForBrush( DC * dc )
176 {
177     X11DRV_PDEVICE *physDev = (X11DRV_PDEVICE *)dc->physDev;
178     return X11DRV_SetupGCForPatBlt( dc, physDev->gc, FALSE );
179 }
180
181
182 /***********************************************************************
183  *           X11DRV_SetupGCForPen
184  *
185  * Setup physDev->gc for drawing operations using current pen.
186  * Return FALSE if pen is PS_NULL, TRUE otherwise.
187  */
188 BOOL X11DRV_SetupGCForPen( DC * dc )
189 {
190     XGCValues val;
191     X11DRV_PDEVICE *physDev = (X11DRV_PDEVICE *)dc->physDev;
192
193     if (physDev->pen.style == PS_NULL) return FALSE;
194
195     if (dc->w.flags & DC_DIRTY) CLIPPING_UpdateGCRegion(dc); 
196
197     switch (dc->w.ROPmode)
198     {
199     case R2_BLACK :
200         val.foreground = BlackPixelOfScreen( X11DRV_GetXScreen() );
201         val.function = GXcopy;
202         break;
203     case R2_WHITE :
204         val.foreground = WhitePixelOfScreen( X11DRV_GetXScreen() );
205         val.function = GXcopy;
206         break;
207     case R2_XORPEN :
208         val.foreground = physDev->pen.pixel;
209         /* It is very unlikely someone wants to XOR with 0 */
210         /* This fixes the rubber-drawings in paintbrush */
211         if (val.foreground == 0)
212             val.foreground = BlackPixelOfScreen( X11DRV_GetXScreen() )
213                             ^ WhitePixelOfScreen( X11DRV_GetXScreen() );
214         val.function = GXxor;
215         break;
216     default :
217         val.foreground = physDev->pen.pixel;
218         val.function   = X11DRV_XROPfunction[dc->w.ROPmode-1];
219     }
220     val.background = physDev->backgroundPixel;
221     val.fill_style = FillSolid;
222     if ((physDev->pen.width <= 1) &&
223         (physDev->pen.style != PS_SOLID) &&
224         (physDev->pen.style != PS_INSIDEFRAME))
225     {
226         TSXSetDashes( display, physDev->gc, 0, physDev->pen.dashes,
227                       physDev->pen.dash_len );
228         val.line_style = (dc->w.backgroundMode == OPAQUE) ?
229                               LineDoubleDash : LineOnOffDash;
230     }
231     else val.line_style = LineSolid;
232     val.line_width = physDev->pen.width;
233     if (val.line_width <= 1) {
234         val.cap_style = CapNotLast;
235     } else {
236         switch (physDev->pen.endcap)
237         {
238         case PS_ENDCAP_SQUARE:
239             val.cap_style = CapProjecting;
240             break;
241         case PS_ENDCAP_FLAT:
242             val.cap_style = CapButt;
243             break;
244         case PS_ENDCAP_ROUND:
245         default:
246             val.cap_style = CapRound;
247         }
248     }
249     switch (physDev->pen.linejoin)
250     {
251     case PS_JOIN_BEVEL:
252         val.join_style = JoinBevel;
253         break;
254     case PS_JOIN_MITER:
255         val.join_style = JoinMiter;
256         break;
257     case PS_JOIN_ROUND:
258     default:
259         val.join_style = JoinRound;
260     }
261     TSXChangeGC( display, physDev->gc, 
262                GCFunction | GCForeground | GCBackground | GCLineWidth |
263                GCLineStyle | GCCapStyle | GCJoinStyle | GCFillStyle, &val );
264     return TRUE;
265 }
266
267
268 /***********************************************************************
269  *           X11DRV_SetupGCForText
270  *
271  * Setup physDev->gc for text drawing operations.
272  * Return FALSE if the font is null, TRUE otherwise.
273  */
274 BOOL X11DRV_SetupGCForText( DC * dc )
275 {
276     X11DRV_PDEVICE *physDev = (X11DRV_PDEVICE *)dc->physDev;
277     XFontStruct* xfs = XFONT_GetFontStruct( physDev->font );
278
279     if( xfs )
280     {
281         XGCValues val;
282
283         if (dc->w.flags & DC_DIRTY) CLIPPING_UpdateGCRegion(dc);
284
285         val.function   = GXcopy;  /* Text is always GXcopy */
286         val.foreground = physDev->textPixel;
287         val.background = physDev->backgroundPixel;
288         val.fill_style = FillSolid;
289         val.font       = xfs->fid;
290
291         TSXChangeGC( display, physDev->gc,
292                    GCFunction | GCForeground | GCBackground | GCFillStyle |
293                    GCFont, &val );
294         return TRUE;
295     } 
296     WARN(dc, "Physical font failure\n" );
297     return FALSE;
298 }
299
300
301 /**********************************************************************
302  *           X11DRV_MoveToEx
303  */
304 BOOL
305 X11DRV_MoveToEx(DC *dc,INT x,INT y,LPPOINT pt) {
306     if (pt)
307     {
308         pt->x = dc->w.CursPosX;
309         pt->y = dc->w.CursPosY;
310     }
311     dc->w.CursPosX = x;
312     dc->w.CursPosY = y;
313     return TRUE;
314 }
315
316 /***********************************************************************
317  *           X11DRV_LineTo
318  */
319 BOOL
320 X11DRV_LineTo( DC *dc, INT x, INT y )
321 {
322     X11DRV_PDEVICE *physDev = (X11DRV_PDEVICE *)dc->physDev;
323
324     if (X11DRV_SetupGCForPen( dc ))
325         TSXDrawLine(display, physDev->drawable, physDev->gc, 
326                   dc->w.DCOrgX + XLPTODP( dc, dc->w.CursPosX ),
327                   dc->w.DCOrgY + YLPTODP( dc, dc->w.CursPosY ),
328                   dc->w.DCOrgX + XLPTODP( dc, x ),
329                   dc->w.DCOrgY + YLPTODP( dc, y ) );
330     dc->w.CursPosX = x;
331     dc->w.CursPosY = y;
332     return TRUE;
333 }
334
335
336
337 /***********************************************************************
338  *           X11DRV_DrawArc
339  *
340  * Helper functions for Arc(), Chord() and Pie().
341  * 'lines' is the number of lines to draw: 0 for Arc, 1 for Chord, 2 for Pie.
342  *
343  */
344 static BOOL
345 X11DRV_DrawArc( DC *dc, INT left, INT top, INT right,
346                 INT bottom, INT xstart, INT ystart,
347                 INT xend, INT yend, INT lines )
348 {
349     INT xcenter, ycenter, istart_angle, idiff_angle;
350     INT width, oldwidth, oldendcap;
351     double start_angle, end_angle;
352     XPoint points[4];
353     X11DRV_PDEVICE *physDev = (X11DRV_PDEVICE *)dc->physDev;
354
355     left   = XLPTODP( dc, left );
356     top    = YLPTODP( dc, top );
357     right  = XLPTODP( dc, right );
358     bottom = YLPTODP( dc, bottom );
359     xstart = XLPTODP( dc, xstart );
360     ystart = YLPTODP( dc, ystart );
361     xend   = XLPTODP( dc, xend );
362     yend   = YLPTODP( dc, yend );
363
364     if (right < left) { INT tmp = right; right = left; left = tmp; }
365     if (bottom < top) { INT tmp = bottom; bottom = top; top = tmp; }
366     if ((left == right) || (top == bottom)
367             ||(lines && ((right-left==1)||(bottom-top==1)))) return TRUE;
368
369     oldwidth = width = physDev->pen.width;
370     oldendcap = physDev->pen.endcap;
371     if (!width) width = 1;
372     if(physDev->pen.style == PS_NULL) width = 0;
373
374     if ((physDev->pen.style == PS_INSIDEFRAME))
375     {
376         if (2*width > (right-left)) width=(right-left + 1)/2;
377         if (2*width > (bottom-top)) width=(bottom-top + 1)/2;
378         left   += width / 2;
379         right  -= (width - 1) / 2;
380         top    += width / 2;
381         bottom -= (width - 1) / 2;
382     }
383     if(width == 0) width = 1; /* more accurate */
384     physDev->pen.width = width;
385     physDev->pen.endcap = PS_ENDCAP_SQUARE;
386
387     xcenter = (right + left) / 2;
388     ycenter = (bottom + top) / 2;
389     start_angle = atan2( (double)(ycenter-ystart)*(right-left),
390                          (double)(xstart-xcenter)*(bottom-top) );
391     end_angle   = atan2( (double)(ycenter-yend)*(right-left),
392                          (double)(xend-xcenter)*(bottom-top) );
393     if ((xstart==xend)&&(ystart==yend))
394       { /* A lazy program delivers xstart=xend=ystart=yend=0) */
395         start_angle = 0;
396         end_angle = 2* PI;
397       }
398     else /* notorious cases */
399       if ((start_angle == PI)&&( end_angle <0))
400         start_angle = - PI;
401     else
402       if ((end_angle == PI)&&( start_angle <0))
403         end_angle = - PI;
404     istart_angle = (INT)(start_angle * 180 * 64 / PI + 0.5);
405     idiff_angle  = (INT)((end_angle - start_angle) * 180 * 64 / PI + 0.5);
406     if (idiff_angle <= 0) idiff_angle += 360 * 64;
407
408       /* Fill arc with brush if Chord() or Pie() */
409
410     if ((lines > 0) && X11DRV_SetupGCForBrush( dc )) {
411         TSXSetArcMode( display, physDev->gc,
412                        (lines==1) ? ArcChord : ArcPieSlice);
413         TSXFillArc( display, physDev->drawable, physDev->gc,
414                  dc->w.DCOrgX + left, dc->w.DCOrgY + top,
415                  right-left-1, bottom-top-1, istart_angle, idiff_angle );
416     }
417
418       /* Draw arc and lines */
419
420     if (X11DRV_SetupGCForPen( dc )){
421     TSXDrawArc( display, physDev->drawable, physDev->gc,
422               dc->w.DCOrgX + left, dc->w.DCOrgY + top,
423               right-left-1, bottom-top-1, istart_angle, idiff_angle );
424         if (lines) {
425             /* use the truncated values */
426             start_angle=(double)istart_angle*PI/64./180.;
427             end_angle=(double)(istart_angle+idiff_angle)*PI/64./180.;
428             /* calculate the endpoints and round correctly */
429             points[0].x = (int) floor(dc->w.DCOrgX + (right+left)/2.0 +
430                     cos(start_angle) * (right-left-width*2+2) / 2. + 0.5);
431             points[0].y = (int) floor(dc->w.DCOrgY + (top+bottom)/2.0 -
432                     sin(start_angle) * (bottom-top-width*2+2) / 2. + 0.5);
433             points[1].x = (int) floor(dc->w.DCOrgX + (right+left)/2.0 +
434                     cos(end_angle) * (right-left-width*2+2) / 2. + 0.5);
435             points[1].y = (int) floor(dc->w.DCOrgY + (top+bottom)/2.0 -
436                     sin(end_angle) * (bottom-top-width*2+2) / 2. + 0.5);
437                     
438             /* OK this stuff is optimized for Xfree86 
439              * which is probably the most used server by
440              * wine users. Other X servers will not 
441              * display correctly. (eXceed for instance)
442              * so if you feel you must change make sure that
443              * you either use Xfree86 or seperate your changes 
444              * from these (compile switch or whatever)
445              */
446             if (lines == 2) {
447                 INT dx1,dy1;
448                 points[3] = points[1];
449         points[1].x = dc->w.DCOrgX + xcenter;
450         points[1].y = dc->w.DCOrgY + ycenter;
451                 points[2] = points[1];
452                 dx1=points[1].x-points[0].x;
453                 dy1=points[1].y-points[0].y;
454                 if(((top-bottom) | -2) == -2)
455                     if(dy1>0) points[1].y--;
456                 if(dx1<0) {
457                     if (((-dx1)*64)<=ABS(dy1)*37) points[0].x--;
458                     if(((-dx1*9))<(dy1*16)) points[0].y--;
459                     if( dy1<0 && ((dx1*9)) < (dy1*16)) points[0].y--;
460                 } else {
461                     if(dy1 < 0)  points[0].y--;
462                     if(((right-left) | -2) == -2) points[1].x--;
463                 }
464                 dx1=points[3].x-points[2].x;
465                 dy1=points[3].y-points[2].y;
466                 if(((top-bottom) | -2 ) == -2)
467                     if(dy1 < 0) points[2].y--;
468                 if( dx1<0){ 
469                     if( dy1>0) points[3].y--;
470                     if(((right-left) | -2) == -2 ) points[2].x--;
471                 }else {
472                     points[3].y--;
473                     if( dx1 * 64 < dy1 * -37 ) points[3].x--;
474                 }
475                 lines++;
476     }
477     TSXDrawLines( display, physDev->drawable, physDev->gc,
478                 points, lines+1, CoordModeOrigin );
479         }
480     }
481     physDev->pen.width = oldwidth;
482     physDev->pen.endcap = oldendcap;
483     return TRUE;
484 }
485
486
487 /***********************************************************************
488  *           X11DRV_Arc
489  */
490 BOOL
491 X11DRV_Arc( DC *dc, INT left, INT top, INT right, INT bottom,
492             INT xstart, INT ystart, INT xend, INT yend )
493 {
494     return X11DRV_DrawArc( dc, left, top, right, bottom,
495                            xstart, ystart, xend, yend, 0 );
496 }
497
498
499 /***********************************************************************
500  *           X11DRV_Pie
501  */
502 BOOL
503 X11DRV_Pie( DC *dc, INT left, INT top, INT right, INT bottom,
504             INT xstart, INT ystart, INT xend, INT yend )
505 {
506     return X11DRV_DrawArc( dc, left, top, right, bottom,
507                            xstart, ystart, xend, yend, 2 );
508 }
509
510 /***********************************************************************
511  *           X11DRV_Chord
512  */
513 BOOL
514 X11DRV_Chord( DC *dc, INT left, INT top, INT right, INT bottom,
515               INT xstart, INT ystart, INT xend, INT yend )
516 {
517     return X11DRV_DrawArc( dc, left, top, right, bottom,
518                            xstart, ystart, xend, yend, 1 );
519 }
520
521
522 /***********************************************************************
523  *           X11DRV_Ellipse
524  */
525 BOOL
526 X11DRV_Ellipse( DC *dc, INT left, INT top, INT right, INT bottom )
527 {
528     INT width, oldwidth;
529     X11DRV_PDEVICE *physDev = (X11DRV_PDEVICE *)dc->physDev;
530
531     left   = XLPTODP( dc, left );
532     top    = YLPTODP( dc, top );
533     right  = XLPTODP( dc, right );
534     bottom = YLPTODP( dc, bottom );
535     if ((left == right) || (top == bottom)) return TRUE;
536
537     if (right < left) { INT tmp = right; right = left; left = tmp; }
538     if (bottom < top) { INT tmp = bottom; bottom = top; top = tmp; }
539     
540     oldwidth = width = physDev->pen.width;
541     if (!width) width = 1;
542     if(physDev->pen.style == PS_NULL) width = 0;
543
544     if ((physDev->pen.style == PS_INSIDEFRAME))
545     {
546         if (2*width > (right-left)) width=(right-left + 1)/2;
547         if (2*width > (bottom-top)) width=(bottom-top + 1)/2;
548         left   += width / 2;
549         right  -= (width - 1) / 2;
550         top    += width / 2;
551         bottom -= (width - 1) / 2;
552     }
553     if(width == 0) width = 1; /* more accurate */
554     physDev->pen.width = width;
555
556     if (X11DRV_SetupGCForBrush( dc ))
557         TSXFillArc( display, physDev->drawable, physDev->gc,
558                   dc->w.DCOrgX + left, dc->w.DCOrgY + top,
559                   right-left-1, bottom-top-1, 0, 360*64 );
560     if (X11DRV_SetupGCForPen( dc ))
561         TSXDrawArc( display, physDev->drawable, physDev->gc,
562                   dc->w.DCOrgX + left, dc->w.DCOrgY + top,
563                   right-left-1, bottom-top-1, 0, 360*64 );
564     physDev->pen.width = oldwidth;
565     return TRUE;
566 }
567
568
569 /***********************************************************************
570  *           X11DRV_Rectangle
571  */
572 BOOL
573 X11DRV_Rectangle(DC *dc, INT left, INT top, INT right, INT bottom)
574 {
575     INT width, oldwidth, oldjoinstyle;
576     X11DRV_PDEVICE *physDev = (X11DRV_PDEVICE *)dc->physDev;
577
578     TRACE(graphics, "(%d %d %d %d)\n", 
579         left, top, right, bottom);
580
581     left   = XLPTODP( dc, left );
582     top    = YLPTODP( dc, top );
583     right  = XLPTODP( dc, right );
584     bottom = YLPTODP( dc, bottom );
585
586     if ((left == right) || (top == bottom)) return TRUE;
587
588     if (right < left) { INT tmp = right; right = left; left = tmp; }
589     if (bottom < top) { INT tmp = bottom; bottom = top; top = tmp; }
590
591     oldwidth = width = physDev->pen.width;
592     if (!width) width = 1;
593     if(physDev->pen.style == PS_NULL) width = 0;
594
595     if ((physDev->pen.style == PS_INSIDEFRAME))
596     {
597         if (2*width > (right-left)) width=(right-left + 1)/2;
598         if (2*width > (bottom-top)) width=(bottom-top + 1)/2;
599         left   += width / 2;
600         right  -= (width - 1) / 2;
601         top    += width / 2;
602         bottom -= (width - 1) / 2;
603     }
604     if(width == 1) width = 0;
605     physDev->pen.width = width;
606     oldjoinstyle = physDev->pen.linejoin;
607     if(physDev->pen.type != PS_GEOMETRIC)
608         physDev->pen.linejoin = PS_JOIN_MITER;
609
610     if ((right > left + width) && (bottom > top + width))
611     {
612         if (X11DRV_SetupGCForBrush( dc ))
613             TSXFillRectangle( display, physDev->drawable, physDev->gc,
614                             dc->w.DCOrgX + left + (width + 1) / 2,
615                             dc->w.DCOrgY + top + (width + 1) / 2,
616                             right-left-width-1, bottom-top-width-1);
617     }
618     if (X11DRV_SetupGCForPen( dc ))
619         TSXDrawRectangle( display, physDev->drawable, physDev->gc,
620                         dc->w.DCOrgX + left, dc->w.DCOrgY + top,
621                         right-left-1, bottom-top-1 );
622
623     physDev->pen.width = oldwidth;
624     physDev->pen.linejoin = oldjoinstyle;
625     return TRUE;
626 }
627
628 /***********************************************************************
629  *           X11DRV_RoundRect
630  */
631 BOOL
632 X11DRV_RoundRect( DC *dc, INT left, INT top, INT right,
633                   INT bottom, INT ell_width, INT ell_height )
634 {
635     INT width, oldwidth, oldendcap;
636     X11DRV_PDEVICE *physDev = (X11DRV_PDEVICE *)dc->physDev;
637
638     TRACE(graphics, "(%d %d %d %d  %d %d\n", 
639         left, top, right, bottom, ell_width, ell_height);
640
641     left   = XLPTODP( dc, left );
642     top    = YLPTODP( dc, top );
643     right  = XLPTODP( dc, right );
644     bottom = YLPTODP( dc, bottom );
645
646     if ((left == right) || (top == bottom))
647         return TRUE;
648
649     /* Make sure ell_width and ell_height are >= 1 otherwise XDrawArc gets
650        called with width/height < 0 */
651     ell_width  = MAX(abs( ell_width * dc->vportExtX / dc->wndExtX ), 1);
652     ell_height = MAX(abs( ell_height * dc->vportExtY / dc->wndExtY ), 1);
653
654     /* Fix the coordinates */
655
656     if (right < left) { INT tmp = right; right = left; left = tmp; }
657     if (bottom < top) { INT tmp = bottom; bottom = top; top = tmp; }
658
659     oldwidth = width = physDev->pen.width;
660     oldendcap = physDev->pen.endcap;
661     if (!width) width = 1;
662     if(physDev->pen.style == PS_NULL) width = 0;
663
664     if ((physDev->pen.style == PS_INSIDEFRAME))
665     {
666         if (2*width > (right-left)) width=(right-left + 1)/2;
667         if (2*width > (bottom-top)) width=(bottom-top + 1)/2;
668         left   += width / 2;
669         right  -= (width - 1) / 2;
670         top    += width / 2;
671         bottom -= (width - 1) / 2;
672     }
673     if(width == 0) width = 1;
674     physDev->pen.width = width;
675     physDev->pen.endcap = PS_ENDCAP_SQUARE;
676
677     if (X11DRV_SetupGCForBrush( dc ))
678     {
679         if (ell_width > (right-left) )
680             if (ell_height > (bottom-top) )
681                     TSXFillArc( display, physDev->drawable, physDev->gc,
682                                 dc->w.DCOrgX + left, dc->w.DCOrgY + top,
683                                 right - left - 1, bottom - top - 1,
684                                 0, 360 * 64 );
685             else{
686                     TSXFillArc( display, physDev->drawable, physDev->gc,
687                                 dc->w.DCOrgX + left, dc->w.DCOrgY + top,
688                                 right - left - 1, ell_height, 0, 180 * 64 );
689                     TSXFillArc( display, physDev->drawable, physDev->gc,
690                                 dc->w.DCOrgX + left,
691                                 dc->w.DCOrgY + bottom - ell_height - 1,
692                                 right - left - 1, ell_height, 180 * 64,
693                                 180 * 64 );
694            }
695         else if (ell_height > (bottom-top) ){
696                 TSXFillArc( display, physDev->drawable, physDev->gc,
697                       dc->w.DCOrgX + left, dc->w.DCOrgY + top,
698                       ell_width, bottom - top - 1, 90 * 64, 180 * 64 );
699                 TSXFillArc( display, physDev->drawable, physDev->gc,
700                       dc->w.DCOrgX + right - ell_width -1, dc->w.DCOrgY + top,
701                       ell_width, bottom - top - 1, 270 * 64, 180 * 64 );
702         }else{
703                 TSXFillArc( display, physDev->drawable, physDev->gc,
704                       dc->w.DCOrgX + left, dc->w.DCOrgY + top,
705                       ell_width, ell_height, 90 * 64, 90 * 64 );
706                 TSXFillArc( display, physDev->drawable, physDev->gc,
707                       dc->w.DCOrgX + left,
708                       dc->w.DCOrgY + bottom - ell_height - 1,
709                       ell_width, ell_height, 180 * 64, 90 * 64 );
710                 TSXFillArc( display, physDev->drawable, physDev->gc,
711                       dc->w.DCOrgX + right - ell_width - 1,
712                       dc->w.DCOrgY + bottom - ell_height - 1,
713                       ell_width, ell_height, 270 * 64, 90 * 64 );
714                 TSXFillArc( display, physDev->drawable, physDev->gc,
715                       dc->w.DCOrgX + right - ell_width - 1,
716                       dc->w.DCOrgY + top,
717                       ell_width, ell_height, 0, 90 * 64 );
718         }
719         if (ell_width < right - left)
720         {
721             TSXFillRectangle( display, physDev->drawable, physDev->gc,
722                             dc->w.DCOrgX + left + (ell_width + 1) / 2,
723                             dc->w.DCOrgY + top + 1,
724                             right - left - ell_width - 1,
725                             (ell_height + 1) / 2 - 1);
726             TSXFillRectangle( display, physDev->drawable, physDev->gc,
727                             dc->w.DCOrgX + left + (ell_width + 1) / 2,
728                             dc->w.DCOrgY + bottom - (ell_height) / 2 - 1,
729                             right - left - ell_width - 1,
730                             (ell_height) / 2 );
731         }
732         if  (ell_height < bottom - top)
733         {
734             TSXFillRectangle( display, physDev->drawable, physDev->gc,
735                             dc->w.DCOrgX + left + 1,
736                             dc->w.DCOrgY + top + (ell_height + 1) / 2,
737                             right - left - 2,
738                             bottom - top - ell_height - 1);
739         }
740     }
741     /* FIXME: this could be done with on X call
742      * more efficient and probably more correct
743      * on any X server: XDrawArcs will draw
744      * straight horizontal and vertical lines
745      * if width or height are zero.
746      *
747      * BTW this stuff is optimized for an Xfree86 server
748      * read the comments inside the X11DRV_DrawArc function
749      */
750     if (X11DRV_SetupGCForPen(dc)) {
751         if (ell_width > (right-left) )
752             if (ell_height > (bottom-top) )
753                 TSXDrawArc( display, physDev->drawable, physDev->gc,
754                       dc->w.DCOrgX + left, dc->w.DCOrgY + top,
755                       right - left - 1, bottom -top - 1, 0 , 360 * 64 );
756             else{
757                 TSXDrawArc( display, physDev->drawable, physDev->gc,
758                       dc->w.DCOrgX + left, dc->w.DCOrgY + top,
759                       right - left - 1, ell_height - 1, 0 , 180 * 64 );
760                 TSXDrawArc( display, physDev->drawable, physDev->gc,
761                       dc->w.DCOrgX + left, 
762                       dc->w.DCOrgY + bottom - ell_height,
763                       right - left - 1, ell_height - 1, 180 * 64 , 180 * 64 );
764             }
765         else if (ell_height > (bottom-top) ){
766                 TSXDrawArc( display, physDev->drawable, physDev->gc,
767                       dc->w.DCOrgX + left, dc->w.DCOrgY + top,
768                       ell_width - 1 , bottom - top - 1, 90 * 64 , 180 * 64 );
769                 TSXDrawArc( display, physDev->drawable, physDev->gc,
770                       dc->w.DCOrgX + right - ell_width, 
771                       dc->w.DCOrgY + top,
772                       ell_width - 1 , bottom - top - 1, 270 * 64 , 180 * 64 );
773         }else{
774             TSXDrawArc( display, physDev->drawable, physDev->gc,
775                       dc->w.DCOrgX + left, dc->w.DCOrgY + top,
776                       ell_width - 1, ell_height - 1, 90 * 64, 90 * 64 );
777             TSXDrawArc( display, physDev->drawable, physDev->gc,
778                       dc->w.DCOrgX + left, dc->w.DCOrgY + bottom - ell_height,
779                       ell_width - 1, ell_height - 1, 180 * 64, 90 * 64 );
780             TSXDrawArc( display, physDev->drawable, physDev->gc,
781                       dc->w.DCOrgX + right - ell_width,
782                       dc->w.DCOrgY + bottom - ell_height,
783                       ell_width - 1, ell_height - 1, 270 * 64, 90 * 64 );
784             TSXDrawArc( display, physDev->drawable, physDev->gc,
785                       dc->w.DCOrgX + right - ell_width, dc->w.DCOrgY + top,
786                       ell_width - 1, ell_height - 1, 0, 90 * 64 );
787         }
788         if (ell_width < right - left)
789         {
790             TSXDrawLine( display, physDev->drawable, physDev->gc, 
791                dc->w.DCOrgX + left + ell_width / 2,
792                        dc->w.DCOrgY + top,
793                dc->w.DCOrgX + right - (ell_width+1) / 2,
794                        dc->w.DCOrgY + top);
795             TSXDrawLine( display, physDev->drawable, physDev->gc, 
796                dc->w.DCOrgX + left + ell_width / 2 ,
797                        dc->w.DCOrgY + bottom - 1,
798                dc->w.DCOrgX + right - (ell_width+1)/ 2,
799                        dc->w.DCOrgY + bottom - 1);
800         }
801         if (ell_height < bottom - top)
802         {
803             TSXDrawLine( display, physDev->drawable, physDev->gc, 
804                        dc->w.DCOrgX + right - 1,
805                dc->w.DCOrgY + top + ell_height / 2,
806                        dc->w.DCOrgX + right - 1,
807                dc->w.DCOrgY + bottom - (ell_height+1) / 2);
808             TSXDrawLine( display, physDev->drawable, physDev->gc, 
809                        dc->w.DCOrgX + left,
810                dc->w.DCOrgY + top + ell_height / 2,
811                        dc->w.DCOrgX + left,
812                dc->w.DCOrgY + bottom - (ell_height+1) / 2);
813         }
814     }
815     physDev->pen.width = oldwidth;
816     physDev->pen.endcap = oldendcap;
817     return TRUE;
818 }
819
820
821 /***********************************************************************
822  *           X11DRV_SetPixel
823  */
824 COLORREF
825 X11DRV_SetPixel( DC *dc, INT x, INT y, COLORREF color )
826 {
827     Pixel pixel;
828     X11DRV_PDEVICE *physDev = (X11DRV_PDEVICE *)dc->physDev;
829     
830     x = dc->w.DCOrgX + XLPTODP( dc, x );
831     y = dc->w.DCOrgY + YLPTODP( dc, y );
832     pixel = COLOR_ToPhysical( dc, color );
833     
834     TSXSetForeground( display, physDev->gc, pixel );
835     TSXSetFunction( display, physDev->gc, GXcopy );
836     TSXDrawPoint( display, physDev->drawable, physDev->gc, x, y );
837
838     /* inefficient but simple... */
839
840     return COLOR_ToLogical(pixel);
841 }
842
843
844 /***********************************************************************
845  *           X11DRV_GetPixel
846  */
847 COLORREF
848 X11DRV_GetPixel( DC *dc, INT x, INT y )
849 {
850     static Pixmap pixmap = 0;
851     XImage * image;
852     int pixel;
853     X11DRV_PDEVICE *physDev = (X11DRV_PDEVICE *)dc->physDev;
854
855     x = dc->w.DCOrgX + XLPTODP( dc, x );
856     y = dc->w.DCOrgY + YLPTODP( dc, y );
857     EnterCriticalSection( &X11DRV_CritSection );
858     if (dc->w.flags & DC_MEMORY)
859     {
860         image = XGetImage( display, physDev->drawable, x, y, 1, 1,
861                            AllPlanes, ZPixmap );
862     }
863     else
864     {
865         /* If we are reading from the screen, use a temporary copy */
866         /* to avoid a BadMatch error */
867         if (!pixmap) pixmap = XCreatePixmap( display, X11DRV_GetXRootWindow(),
868                                              1, 1, dc->w.bitsPerPixel );
869         XCopyArea( display, physDev->drawable, pixmap, BITMAP_colorGC,
870                    x, y, 1, 1, 0, 0 );
871         image = XGetImage( display, pixmap, 0, 0, 1, 1, AllPlanes, ZPixmap );
872     }
873     pixel = XGetPixel( image, 0, 0 );
874     XDestroyImage( image );
875     LeaveCriticalSection( &X11DRV_CritSection );
876     
877     return COLOR_ToLogical(pixel);
878 }
879
880
881 /***********************************************************************
882  *           X11DRV_PaintRgn
883  */
884 BOOL
885 X11DRV_PaintRgn( DC *dc, HRGN hrgn )
886 {
887     RECT box;
888     HRGN tmpVisRgn, prevVisRgn;
889     HDC  hdc = dc->hSelf; /* FIXME: should not mix dc/hdc this way */
890     X11DRV_PDEVICE *physDev = (X11DRV_PDEVICE *)dc->physDev;
891
892     if (!(tmpVisRgn = CreateRectRgn( 0, 0, 0, 0 ))) return FALSE;
893
894       /* Transform region into device co-ords */
895     if (  !REGION_LPTODP( hdc, tmpVisRgn, hrgn )
896         || OffsetRgn( tmpVisRgn, dc->w.DCOrgX, dc->w.DCOrgY ) == ERROR) {
897         DeleteObject( tmpVisRgn );
898         return FALSE;
899     }
900
901       /* Modify visible region */
902     if (!(prevVisRgn = SaveVisRgn16( hdc ))) {
903         DeleteObject( tmpVisRgn );
904         return FALSE;
905     }
906     CombineRgn( tmpVisRgn, prevVisRgn, tmpVisRgn, RGN_AND );
907     SelectVisRgn16( hdc, tmpVisRgn );
908     DeleteObject( tmpVisRgn );
909
910       /* Fill the region */
911
912     GetRgnBox( dc->w.hGCClipRgn, &box );
913     if (X11DRV_SetupGCForBrush( dc ))
914         TSXFillRectangle( display, physDev->drawable, physDev->gc,
915                           box.left, box.top,
916                           box.right-box.left, box.bottom-box.top );
917
918       /* Restore the visible region */
919
920     RestoreVisRgn16( hdc );
921     return TRUE;
922 }
923
924 /**********************************************************************
925  *          X11DRV_Polyline
926  */
927 BOOL
928 X11DRV_Polyline( DC *dc, const POINT* pt, INT count )
929 {
930     INT oldwidth;
931     register int i;
932     XPoint *points;
933     X11DRV_PDEVICE *physDev = (X11DRV_PDEVICE *)dc->physDev;
934
935     if((oldwidth = physDev->pen.width) == 0) physDev->pen.width = 1;
936
937     points = (XPoint *) xmalloc (sizeof (XPoint) * (count));
938     for (i = 0; i < count; i++)
939     {
940     points[i].x = dc->w.DCOrgX + XLPTODP( dc, pt[i].x );
941     points[i].y = dc->w.DCOrgY + YLPTODP( dc, pt[i].y );
942     }
943
944     if (X11DRV_SetupGCForPen ( dc ))
945     TSXDrawLines( display, physDev->drawable, physDev->gc,
946            points, count, CoordModeOrigin );
947
948     free( points );
949     physDev->pen.width = oldwidth;
950     return TRUE;
951 }
952
953
954 /**********************************************************************
955  *          X11DRV_Polygon
956  */
957 BOOL
958 X11DRV_Polygon( DC *dc, const POINT* pt, INT count )
959 {
960     register int i;
961     XPoint *points;
962     X11DRV_PDEVICE *physDev = (X11DRV_PDEVICE *)dc->physDev;
963
964     points = (XPoint *) xmalloc (sizeof (XPoint) * (count+1));
965     for (i = 0; i < count; i++)
966     {
967         points[i].x = dc->w.DCOrgX + XLPTODP( dc, pt[i].x );
968         points[i].y = dc->w.DCOrgY + YLPTODP( dc, pt[i].y );
969     }
970     points[count] = points[0];
971
972     if (X11DRV_SetupGCForBrush( dc ))
973         TSXFillPolygon( display, physDev->drawable, physDev->gc,
974                      points, count+1, Complex, CoordModeOrigin);
975
976     if (X11DRV_SetupGCForPen ( dc ))
977         TSXDrawLines( display, physDev->drawable, physDev->gc,
978                    points, count+1, CoordModeOrigin );
979
980     free( points );
981     return TRUE;
982 }
983
984
985 /**********************************************************************
986  *          X11DRV_PolyPolygon
987  */
988 BOOL 
989 X11DRV_PolyPolygon( DC *dc, const POINT* pt, const INT* counts, UINT polygons)
990 {
991     HRGN hrgn;
992     X11DRV_PDEVICE *physDev = (X11DRV_PDEVICE *)dc->physDev;
993
994     /* FIXME: The points should be converted to device coords before */
995     /* creating the region. */
996
997     hrgn = CreatePolyPolygonRgn( pt, counts, polygons, dc->w.polyFillMode );
998     X11DRV_PaintRgn( dc, hrgn );
999     DeleteObject( hrgn );
1000
1001       /* Draw the outline of the polygons */
1002
1003     if (X11DRV_SetupGCForPen ( dc ))
1004     {
1005         int i, j, max = 0;
1006         XPoint *points;
1007
1008         for (i = 0; i < polygons; i++) if (counts[i] > max) max = counts[i];
1009         points = (XPoint *) xmalloc( sizeof(XPoint) * (max+1) );
1010
1011         for (i = 0; i < polygons; i++)
1012         {
1013             for (j = 0; j < counts[i]; j++)
1014             {
1015                 points[j].x = dc->w.DCOrgX + XLPTODP( dc, pt->x );
1016                 points[j].y = dc->w.DCOrgY + YLPTODP( dc, pt->y );
1017                 pt++;
1018             }
1019             points[j] = points[0];
1020             TSXDrawLines( display, physDev->drawable, physDev->gc,
1021                         points, j + 1, CoordModeOrigin );
1022         }
1023         free( points );
1024     }
1025     return TRUE;
1026 }
1027
1028
1029 /**********************************************************************
1030  *          X11DRV_PolyPolyline
1031  */
1032 BOOL 
1033 X11DRV_PolyPolyline( DC *dc, const POINT* pt, const DWORD* counts, DWORD polylines )
1034 {
1035     X11DRV_PDEVICE *physDev = (X11DRV_PDEVICE *)dc->physDev;
1036     if (X11DRV_SetupGCForPen ( dc ))
1037     {
1038         int i, j, max = 0;
1039         XPoint *points;
1040
1041         for (i = 0; i < polylines; i++) if (counts[i] > max) max = counts[i];
1042         points = (XPoint *) xmalloc( sizeof(XPoint) * (max+1) );
1043
1044         for (i = 0; i < polylines; i++)
1045         {
1046             for (j = 0; j < counts[i]; j++)
1047             {
1048                 points[j].x = dc->w.DCOrgX + XLPTODP( dc, pt->x );
1049                 points[j].y = dc->w.DCOrgY + YLPTODP( dc, pt->y );
1050                 pt++;
1051             }
1052             points[j] = points[0];
1053             TSXDrawLines( display, physDev->drawable, physDev->gc,
1054                         points, j + 1, CoordModeOrigin );
1055         }
1056         free( points );
1057     }
1058     return TRUE;
1059 }
1060
1061
1062 /**********************************************************************
1063  *          X11DRV_InternalFloodFill
1064  *
1065  * Internal helper function for flood fill.
1066  * (xorg,yorg) is the origin of the X image relative to the drawable.
1067  * (x,y) is relative to the origin of the X image.
1068  */
1069 static void X11DRV_InternalFloodFill(XImage *image, DC *dc,
1070                                      int x, int y,
1071                                      int xOrg, int yOrg,
1072                                      Pixel pixel, WORD fillType )
1073 {
1074     X11DRV_PDEVICE *physDev = (X11DRV_PDEVICE *)dc->physDev;
1075     int left, right;
1076
1077 #define TO_FLOOD(x,y)  ((fillType == FLOODFILLBORDER) ? \
1078                         (XGetPixel(image,x,y) != pixel) : \
1079                         (XGetPixel(image,x,y) == pixel))
1080
1081     if (!TO_FLOOD(x,y)) return;
1082
1083       /* Find left and right boundaries */
1084
1085     left = right = x;
1086     while ((left > 0) && TO_FLOOD( left-1, y )) left--;
1087     while ((right < image->width) && TO_FLOOD( right, y )) right++;
1088     XFillRectangle( display, physDev->drawable, physDev->gc,
1089                     xOrg + left, yOrg + y, right-left, 1 );
1090
1091       /* Set the pixels of this line so we don't fill it again */
1092
1093     for (x = left; x < right; x++)
1094     {
1095         if (fillType == FLOODFILLBORDER) XPutPixel( image, x, y, pixel );
1096         else XPutPixel( image, x, y, ~pixel );
1097     }
1098
1099       /* Fill the line above */
1100
1101     if (--y >= 0)
1102     {
1103         x = left;
1104         while (x < right)
1105         {
1106             while ((x < right) && !TO_FLOOD(x,y)) x++;
1107             if (x >= right) break;
1108             while ((x < right) && TO_FLOOD(x,y)) x++;
1109             X11DRV_InternalFloodFill(image, dc, x-1, y,
1110                                      xOrg, yOrg, pixel, fillType );
1111         }
1112     }
1113
1114       /* Fill the line below */
1115
1116     if ((y += 2) < image->height)
1117     {
1118         x = left;
1119         while (x < right)
1120         {
1121             while ((x < right) && !TO_FLOOD(x,y)) x++;
1122             if (x >= right) break;
1123             while ((x < right) && TO_FLOOD(x,y)) x++;
1124             X11DRV_InternalFloodFill(image, dc, x-1, y,
1125                                      xOrg, yOrg, pixel, fillType );
1126         }
1127     }
1128 #undef TO_FLOOD    
1129 }
1130
1131
1132 /**********************************************************************
1133  *          X11DRV_DoFloodFill
1134  *
1135  * Main flood-fill routine.
1136  *
1137  * The Xlib critical section must be entered before calling this function.
1138  */
1139
1140 struct FloodFill_params
1141 {
1142     DC      *dc;
1143     INT    x;
1144     INT    y;
1145     COLORREF color;
1146     UINT   fillType;
1147 };
1148
1149 static BOOL X11DRV_DoFloodFill( const struct FloodFill_params *params )
1150 {
1151     XImage *image;
1152     RECT rect;
1153     DC *dc = params->dc;
1154     X11DRV_PDEVICE *physDev = (X11DRV_PDEVICE *)dc->physDev;
1155
1156     if (GetRgnBox( dc->w.hGCClipRgn, &rect ) == ERROR) return FALSE;
1157
1158     if (!(image = XGetImage( display, physDev->drawable,
1159                              rect.left,
1160                              rect.top,
1161                              rect.right - rect.left,
1162                              rect.bottom - rect.top,
1163                              AllPlanes, ZPixmap ))) return FALSE;
1164
1165     if (X11DRV_SetupGCForBrush( dc ))
1166     {
1167           /* ROP mode is always GXcopy for flood-fill */
1168         XSetFunction( display, physDev->gc, GXcopy );
1169         X11DRV_InternalFloodFill(image, dc,
1170                                  XLPTODP(dc,params->x) + dc->w.DCOrgX - rect.left,
1171                                  YLPTODP(dc,params->y) + dc->w.DCOrgY - rect.top,
1172                                  rect.left,
1173                                  rect.top,
1174                                  COLOR_ToPhysical( dc, params->color ),
1175                                  params->fillType );
1176     }
1177
1178     XDestroyImage( image );
1179     return TRUE;
1180 }
1181
1182
1183 /**********************************************************************
1184  *          X11DRV_ExtFloodFill
1185  */
1186 BOOL
1187 X11DRV_ExtFloodFill( DC *dc, INT x, INT y, COLORREF color,
1188                      UINT fillType )
1189 {
1190     BOOL result;
1191     struct FloodFill_params params = { dc, x, y, color, fillType };
1192
1193     TRACE(graphics, "X11DRV_ExtFloodFill %d,%d %06lx %d\n",
1194                       x, y, color, fillType );
1195
1196     if (!PtVisible( dc->hSelf, x, y )) return FALSE;
1197     EnterCriticalSection( &X11DRV_CritSection );
1198     result = CALL_LARGE_STACK( X11DRV_DoFloodFill, &params );
1199     LeaveCriticalSection( &X11DRV_CritSection );
1200     return result;
1201 }
1202
1203 /******************************************************************
1204  * 
1205  *   *Very* simple bezier drawing code, 
1206  *
1207  *   It uses a recursive algorithm to divide the curve in a series
1208  *   of straight line segements. Not ideal but for me sufficient.
1209  *   If you are in need for something better look for some incremental
1210  *   algorithm.
1211  *
1212  *   7 July 1998 Rein Klazes
1213  */
1214
1215  /* 
1216   * some macro definitions for bezier drawing
1217   *
1218   * to avoid trucation errors the coordinates are
1219   * shifted upwards. When used in drawing they are
1220   * shifted down again, including correct rounding
1221   * and avoiding floating point arithmatic
1222   * 4 bits should allow 27 bits coordinates which I saw
1223   * somewere in the win32 doc's
1224   * 
1225   */
1226
1227 #define BEZIERSHIFTBITS 4
1228 #define BEZIERSHIFTUP(x)    ((x)<<BEZIERSHIFTBITS)
1229 #define BEZIERPIXEL        BEZIERSHIFTUP(1)    
1230 #define BEZIERSHIFTDOWN(x)  (((x)+(1<<(BEZIERSHIFTBITS-1)))>>BEZIERSHIFTBITS)
1231 /* maximum depth of recursion */
1232 #define BEZIERMAXDEPTH  8
1233
1234 /* size of array to store points on */
1235 /* enough for one curve */
1236 #define BEZMAXPOINTS    (150)
1237
1238 /* calculate Bezier average, in this case the middle 
1239  * correctly rounded...
1240  * */
1241
1242 #define BEZIERMIDDLE(Mid, P1, P2) \
1243     (Mid).x=((P1).x+(P2).x + 1)/2;\
1244     (Mid).y=((P1).y+(P2).y + 1)/2;
1245     
1246 /**********************************************************
1247 * BezierCheck helper function to check
1248 * that recursion can be terminated
1249 *       Points[0] and Points[3] are begin and endpoint
1250 *       Points[1] and Points[2] are control points
1251 *       level is the recursion depth
1252 *       returns true if the recusion can be terminated
1253 */
1254 static BOOL BezierCheck( int level, POINT *Points)
1255
1256     INT dx, dy;
1257     dx=Points[3].x-Points[0].x;
1258     dy=Points[3].y-Points[0].y;
1259     if(ABS(dy)<=ABS(dx)){/* shallow line */
1260         /* check that control points are between begin and end */
1261         if(Points[1].x < Points[0].x){
1262             if(Points[1].x < Points[3].x)
1263                 return FALSE;
1264         }else
1265             if(Points[1].x > Points[3].x)
1266                 return FALSE;
1267         if(Points[2].x < Points[0].x){
1268             if(Points[2].x < Points[3].x)
1269                 return FALSE;
1270         }else
1271             if(Points[2].x > Points[3].x)
1272                 return FALSE;
1273         dx=BEZIERSHIFTDOWN(dx);
1274         if(!dx) return TRUE;
1275         if(abs(Points[1].y-Points[0].y-(dy/dx)*
1276                 BEZIERSHIFTDOWN(Points[1].x-Points[0].x)) > BEZIERPIXEL ||
1277            abs(Points[2].y-Points[0].y-(dy/dx)*
1278                    BEZIERSHIFTDOWN(Points[2].x-Points[0].x)) > BEZIERPIXEL )
1279             return FALSE;
1280         else
1281             return TRUE;
1282     }else{ /* steep line */
1283         /* check that control points are between begin and end */
1284         if(Points[1].y < Points[0].y){
1285             if(Points[1].y < Points[3].y)
1286                 return FALSE;
1287         }else
1288             if(Points[1].y > Points[3].y)
1289                 return FALSE;
1290         if(Points[2].y < Points[0].y){
1291             if(Points[2].y < Points[3].y)
1292                 return FALSE;
1293         }else
1294             if(Points[2].y > Points[3].y)
1295                 return FALSE;
1296         dy=BEZIERSHIFTDOWN(dy);
1297         if(!dy) return TRUE;
1298         if(abs(Points[1].x-Points[0].x-(dx/dy)*
1299                 BEZIERSHIFTDOWN(Points[1].y-Points[0].y)) > BEZIERPIXEL ||
1300            abs(Points[2].x-Points[0].x-(dx/dy)*
1301                    BEZIERSHIFTDOWN(Points[2].y-Points[0].y)) > BEZIERPIXEL )
1302             return FALSE;
1303         else
1304             return TRUE;
1305     }
1306 }
1307     
1308 /***********************************************************************
1309  *           X11DRV_Bezier
1310  *   Draw a -what microsoft calls- bezier curve
1311  *   The routine recursively devides the curve
1312  *   in two parts until a straight line can be drawn
1313  *
1314  *   level      recusion depth counted backwards
1315  *   dc         device context
1316  *   Points     array of begin(0), end(3) and control points(1 and 2)
1317  *   XPoints    array with points calculated sofar
1318  *   *pIx       nr points calculated sofar
1319  *   
1320  */
1321 static void X11DRV_Bezier(int level, DC * dc, POINT *Points, 
1322                           XPoint* xpoints, unsigned int* pIx)
1323 {
1324     X11DRV_PDEVICE *physDev = (X11DRV_PDEVICE *)dc->physDev;
1325
1326     if(*pIx == BEZMAXPOINTS){
1327         TSXDrawLines( display, physDev->drawable, physDev->gc,
1328                     xpoints, *pIx, CoordModeOrigin );
1329         *pIx=0;
1330     }
1331     if(!level || BezierCheck(level, Points)) {
1332         if(*pIx == 0){
1333             xpoints[*pIx].x= dc->w.DCOrgX + BEZIERSHIFTDOWN(Points[0].x);
1334             xpoints[*pIx].y= dc->w.DCOrgY + BEZIERSHIFTDOWN(Points[0].y);
1335             *pIx=1;
1336         }
1337         xpoints[*pIx].x= dc->w.DCOrgX + BEZIERSHIFTDOWN(Points[3].x);
1338         xpoints[*pIx].y= dc->w.DCOrgY + BEZIERSHIFTDOWN(Points[3].y);
1339         (*pIx) ++;
1340     } else {
1341         POINT Points2[4]; /* for the second recursive call */
1342         Points2[3]=Points[3];
1343         BEZIERMIDDLE(Points2[2], Points[2], Points[3]);
1344         BEZIERMIDDLE(Points2[0], Points[1], Points[2]);
1345         BEZIERMIDDLE(Points2[1],Points2[0],Points2[2]);
1346
1347         BEZIERMIDDLE(Points[1], Points[0],  Points[1]);
1348         BEZIERMIDDLE(Points[2], Points[1], Points2[0]);
1349         BEZIERMIDDLE(Points[3], Points[2], Points2[1]);
1350
1351         Points2[0]=Points[3];
1352
1353         /* do the two halves */
1354         X11DRV_Bezier(level-1, dc, Points, xpoints, pIx);
1355         X11DRV_Bezier(level-1, dc, Points2, xpoints, pIx);
1356     }
1357 }
1358
1359 /***********************************************************************
1360  *           X11DRV_PolyBezier
1361  *      Implement functionality for PolyBezier and PolyBezierTo
1362  *      calls. 
1363  *      [i] dc pointer to device context
1364  *      [i] start, first point in curve
1365  *      [i] BezierPoints , array of point filled with rest of the points
1366  *      [i] count, number of points in BezierPoints, must be a 
1367  *          multiple of 3.
1368  */
1369 BOOL
1370 X11DRV_PolyBezier(DC *dc, POINT start, const POINT* BezierPoints, DWORD count)
1371 {
1372     POINT Points[4]; 
1373     int i;
1374     unsigned int ix=0;
1375     XPoint* xpoints;
1376     X11DRV_PDEVICE *physDev = (X11DRV_PDEVICE *)dc->physDev;
1377
1378     TRACE(graphics, "dc=%p count=%ld %ld,%ld - %ld,%ld - %ld,%ld - %ld,%ld\n", 
1379             dc, count,
1380             start.x, start.y,
1381             (Points+0)->x, (Points+0)->y, 
1382             (Points+1)->x, (Points+1)->y, 
1383             (Points+2)->x, (Points+2)->y); 
1384     if(!count || count % 3){/* paranoid */
1385         WARN(graphics," bad value for count : %ld\n", count);
1386         return FALSE; 
1387     }
1388     xpoints=(XPoint*) xmalloc( sizeof(XPoint)*BEZMAXPOINTS);
1389     Points[3].x=BEZIERSHIFTUP(XLPTODP(dc,start.x));
1390     Points[3].y=BEZIERSHIFTUP(YLPTODP(dc,start.y));
1391     while(count){
1392         Points[0]=Points[3];
1393         for(i=1;i<4;i++) {
1394             Points[i].x= BEZIERSHIFTUP(XLPTODP(dc,BezierPoints->x));
1395             Points[i].y= BEZIERSHIFTUP(YLPTODP(dc,BezierPoints->y));
1396             BezierPoints++;
1397         }
1398         X11DRV_Bezier(BEZIERMAXDEPTH , dc, Points, xpoints, &ix );
1399         count -=3;
1400     }
1401     if( ix) TSXDrawLines( display, physDev->drawable, physDev->gc,
1402                           xpoints, ix, CoordModeOrigin );
1403     free(xpoints);
1404     return TRUE;
1405 }
1406
1407 /**********************************************************************
1408  *          X11DRV_SetBkColor
1409  */
1410 COLORREF
1411 X11DRV_SetBkColor( DC *dc, COLORREF color )
1412 {
1413     X11DRV_PDEVICE *physDev = (X11DRV_PDEVICE *)dc->physDev;
1414     COLORREF oldColor;
1415
1416     oldColor = dc->w.backgroundColor;
1417     dc->w.backgroundColor = color;
1418
1419     physDev->backgroundPixel = COLOR_ToPhysical( dc, color );
1420
1421     return oldColor;
1422 }
1423
1424 /**********************************************************************
1425  *          X11DRV_SetTextColor
1426  */
1427 COLORREF
1428 X11DRV_SetTextColor( DC *dc, COLORREF color )
1429 {
1430     X11DRV_PDEVICE *physDev = (X11DRV_PDEVICE *)dc->physDev;
1431     COLORREF oldColor;
1432
1433     oldColor = dc->w.textColor;
1434     dc->w.textColor = color;
1435
1436     physDev->textPixel = COLOR_ToPhysical( dc, color );
1437
1438     return oldColor;
1439 }
1440
1441 #endif /* !defined(X_DISPLAY_MISSING) */