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