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