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