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