winex11.drv: Associate the real DC transformation with cached font data.
[wine] / dlls / winex11.drv / graphics.c
1 /*
2  * X11 graphics driver graphics functions
3  *
4  * Copyright 1993,1994 Alexandre Julliard
5  * Copyright 1998 Huw Davies
6  *
7  * This library is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Lesser General Public
9  * License as published by the Free Software Foundation; either
10  * version 2.1 of the License, or (at your option) any later version.
11  *
12  * This library is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * Lesser General Public License for more details.
16  *
17  * You should have received a copy of the GNU Lesser General Public
18  * License along with this library; if not, write to the Free Software
19  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
20  */
21
22 /*
23  * FIXME: only some of these functions obey the GM_ADVANCED
24  * graphics mode
25  */
26
27 #include "config.h"
28
29 #include <stdarg.h>
30 #include <math.h>
31 #ifdef HAVE_FLOAT_H
32 # include <float.h>
33 #endif
34 #include <stdlib.h>
35 #ifndef PI
36 #define PI M_PI
37 #endif
38 #include <string.h>
39 #include <limits.h>
40
41 #include "windef.h"
42 #include "winbase.h"
43 #include "winreg.h"
44
45 #include "x11drv.h"
46 #include "x11font.h"
47 #include "wine/debug.h"
48 #include "wine/unicode.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 /* get the rectangle in device coordinates, with optional mirroring */
77 static RECT get_device_rect( HDC hdc, int left, int top, int right, int bottom )
78 {
79     RECT rect;
80
81     rect.left   = left;
82     rect.top    = top;
83     rect.right  = right;
84     rect.bottom = bottom;
85     if (GetLayout( hdc ) & LAYOUT_RTL)
86     {
87         /* shift the rectangle so that the right border is included after mirroring */
88         /* it would be more correct to do this after LPtoDP but that's not what Windows does */
89         rect.left--;
90         rect.right--;
91     }
92     LPtoDP( hdc, (POINT *)&rect, 2 );
93     if (rect.left > rect.right)
94     {
95         int tmp = rect.left;
96         rect.left = rect.right;
97         rect.right = tmp;
98     }
99     if (rect.top > rect.bottom)
100     {
101         int tmp = rect.top;
102         rect.top = rect.bottom;
103         rect.bottom = tmp;
104     }
105     return rect;
106 }
107
108 /***********************************************************************
109  *           X11DRV_GetRegionData
110  *
111  * Calls GetRegionData on the given region and converts the rectangle
112  * array to XRectangle format. The returned buffer must be freed by
113  * caller using HeapFree(GetProcessHeap(),...).
114  * If hdc_lptodp is not 0, the rectangles are converted through LPtoDP.
115  */
116 RGNDATA *X11DRV_GetRegionData( HRGN hrgn, HDC hdc_lptodp )
117 {
118     RGNDATA *data;
119     DWORD size;
120     unsigned int i;
121     RECT *rect, tmp;
122     XRectangle *xrect;
123
124     if (!(size = GetRegionData( hrgn, 0, NULL ))) return NULL;
125     if (sizeof(XRectangle) > sizeof(RECT))
126     {
127         /* add extra size for XRectangle array */
128         int count = (size - sizeof(RGNDATAHEADER)) / sizeof(RECT);
129         size += count * (sizeof(XRectangle) - sizeof(RECT));
130     }
131     if (!(data = HeapAlloc( GetProcessHeap(), 0, size ))) return NULL;
132     if (!GetRegionData( hrgn, size, data ))
133     {
134         HeapFree( GetProcessHeap(), 0, data );
135         return NULL;
136     }
137
138     rect = (RECT *)data->Buffer;
139     xrect = (XRectangle *)data->Buffer;
140     if (hdc_lptodp)  /* map to device coordinates */
141     {
142         LPtoDP( hdc_lptodp, (POINT *)rect, data->rdh.nCount * 2 );
143         for (i = 0; i < data->rdh.nCount; i++)
144         {
145             if (rect[i].right < rect[i].left)
146             {
147                 INT tmp = rect[i].right;
148                 rect[i].right = rect[i].left;
149                 rect[i].left = tmp;
150             }
151             if (rect[i].bottom < rect[i].top)
152             {
153                 INT tmp = rect[i].bottom;
154                 rect[i].bottom = rect[i].top;
155                 rect[i].top = tmp;
156             }
157         }
158     }
159
160     if (sizeof(XRectangle) > sizeof(RECT))
161     {
162         int j;
163         /* need to start from the end */
164         for (j = data->rdh.nCount-1; j >= 0; j--)
165         {
166             tmp = rect[j];
167             xrect[j].x      = max( min( tmp.left, SHRT_MAX), SHRT_MIN);
168             xrect[j].y      = max( min( tmp.top, SHRT_MAX), SHRT_MIN);
169             xrect[j].width  = max( min( tmp.right - xrect[j].x, USHRT_MAX), 0);
170             xrect[j].height = max( min( tmp.bottom - xrect[j].y, USHRT_MAX), 0);
171         }
172     }
173     else
174     {
175         for (i = 0; i < data->rdh.nCount; i++)
176         {
177             tmp = rect[i];
178             xrect[i].x      = max( min( tmp.left, SHRT_MAX), SHRT_MIN);
179             xrect[i].y      = max( min( tmp.top, SHRT_MAX), SHRT_MIN);
180             xrect[i].width  = max( min( tmp.right - xrect[i].x, USHRT_MAX), 0);
181             xrect[i].height = max( min( tmp.bottom - xrect[i].y, USHRT_MAX), 0);
182         }
183     }
184     return data;
185 }
186
187
188 /***********************************************************************
189  *           X11DRV_SetDeviceClipping
190  */
191 void CDECL X11DRV_SetDeviceClipping( X11DRV_PDEVICE *physDev, HRGN vis_rgn, HRGN clip_rgn )
192 {
193     RGNDATA *data;
194
195     CombineRgn( physDev->region, vis_rgn, clip_rgn, clip_rgn ? RGN_AND : RGN_COPY );
196     if (!(data = X11DRV_GetRegionData( physDev->region, 0 ))) return;
197
198     wine_tsx11_lock();
199     XSetClipRectangles( gdi_display, physDev->gc, physDev->dc_rect.left, physDev->dc_rect.top,
200                         (XRectangle *)data->Buffer, data->rdh.nCount, YXBanded );
201     wine_tsx11_unlock();
202
203     if (physDev->xrender) X11DRV_XRender_SetDeviceClipping(physDev, data);
204
205     HeapFree( GetProcessHeap(), 0, data );
206 }
207
208
209 /***********************************************************************
210  *           X11DRV_SetupGCForPatBlt
211  *
212  * Setup the GC for a PatBlt operation using current brush.
213  * If fMapColors is TRUE, X pixels are mapped to Windows colors.
214  * Return FALSE if brush is BS_NULL, TRUE otherwise.
215  */
216 BOOL X11DRV_SetupGCForPatBlt( X11DRV_PDEVICE *physDev, GC gc, BOOL fMapColors )
217 {
218     XGCValues val;
219     unsigned long mask;
220     Pixmap pixmap = 0;
221     POINT pt;
222
223     if (physDev->brush.style == BS_NULL) return FALSE;
224     if (physDev->brush.pixel == -1)
225     {
226         /* Special case used for monochrome pattern brushes.
227          * We need to swap foreground and background because
228          * Windows does it the wrong way...
229          */
230         val.foreground = physDev->backgroundPixel;
231         val.background = physDev->textPixel;
232     }
233     else
234     {
235         val.foreground = physDev->brush.pixel;
236         val.background = physDev->backgroundPixel;
237     }
238     if (fMapColors && X11DRV_PALETTE_XPixelToPalette)
239     {
240         val.foreground = X11DRV_PALETTE_XPixelToPalette[val.foreground];
241         val.background = X11DRV_PALETTE_XPixelToPalette[val.background];
242     }
243
244     val.function = X11DRV_XROPfunction[GetROP2(physDev->hdc)-1];
245     /*
246     ** Let's replace GXinvert by GXxor with (black xor white)
247     ** This solves the selection color and leak problems in excel
248     ** FIXME : Let's do that only if we work with X-pixels, not with Win-pixels
249     */
250     if (val.function == GXinvert)
251     {
252         val.foreground = (WhitePixel( gdi_display, DefaultScreen(gdi_display) ) ^
253                           BlackPixel( gdi_display, DefaultScreen(gdi_display) ));
254         val.function = GXxor;
255     }
256     val.fill_style = physDev->brush.fillStyle;
257     switch(val.fill_style)
258     {
259     case FillStippled:
260     case FillOpaqueStippled:
261         if (GetBkMode(physDev->hdc)==OPAQUE) val.fill_style = FillOpaqueStippled;
262         val.stipple = physDev->brush.pixmap;
263         mask = GCStipple;
264         break;
265
266     case FillTiled:
267         if (fMapColors && X11DRV_PALETTE_XPixelToPalette)
268         {
269             register int x, y;
270             XImage *image;
271             wine_tsx11_lock();
272             pixmap = XCreatePixmap( gdi_display, root_window, 8, 8, physDev->depth );
273             image = XGetImage( gdi_display, physDev->brush.pixmap, 0, 0, 8, 8,
274                                AllPlanes, ZPixmap );
275             for (y = 0; y < 8; y++)
276                 for (x = 0; x < 8; x++)
277                     XPutPixel( image, x, y,
278                                X11DRV_PALETTE_XPixelToPalette[XGetPixel( image, x, y)] );
279             XPutImage( gdi_display, pixmap, gc, image, 0, 0, 0, 0, 8, 8 );
280             XDestroyImage( image );
281             wine_tsx11_unlock();
282             val.tile = pixmap;
283         }
284         else val.tile = physDev->brush.pixmap;
285         mask = GCTile;
286         break;
287
288     default:
289         mask = 0;
290         break;
291     }
292     GetBrushOrgEx( physDev->hdc, &pt );
293     val.ts_x_origin = physDev->dc_rect.left + pt.x;
294     val.ts_y_origin = physDev->dc_rect.top + pt.y;
295     val.fill_rule = (GetPolyFillMode(physDev->hdc) == WINDING) ? WindingRule : EvenOddRule;
296     wine_tsx11_lock();
297     XChangeGC( gdi_display, gc,
298                GCFunction | GCForeground | GCBackground | GCFillStyle |
299                GCFillRule | GCTileStipXOrigin | GCTileStipYOrigin | mask,
300                &val );
301     if (pixmap) XFreePixmap( gdi_display, pixmap );
302     wine_tsx11_unlock();
303     return TRUE;
304 }
305
306
307 /***********************************************************************
308  *           X11DRV_SetupGCForBrush
309  *
310  * Setup physDev->gc for drawing operations using current brush.
311  * Return FALSE if brush is BS_NULL, TRUE otherwise.
312  */
313 BOOL X11DRV_SetupGCForBrush( X11DRV_PDEVICE *physDev )
314 {
315     return X11DRV_SetupGCForPatBlt( physDev, physDev->gc, FALSE );
316 }
317
318
319 /***********************************************************************
320  *           X11DRV_SetupGCForPen
321  *
322  * Setup physDev->gc for drawing operations using current pen.
323  * Return FALSE if pen is PS_NULL, TRUE otherwise.
324  */
325 static BOOL X11DRV_SetupGCForPen( X11DRV_PDEVICE *physDev )
326 {
327     XGCValues val;
328     UINT rop2 = GetROP2(physDev->hdc);
329
330     if (physDev->pen.style == PS_NULL) return FALSE;
331
332     switch (rop2)
333     {
334     case R2_BLACK :
335         val.foreground = BlackPixel( gdi_display, DefaultScreen(gdi_display) );
336         val.function = GXcopy;
337         break;
338     case R2_WHITE :
339         val.foreground = WhitePixel( gdi_display, DefaultScreen(gdi_display) );
340         val.function = GXcopy;
341         break;
342     case R2_XORPEN :
343         val.foreground = physDev->pen.pixel;
344         /* It is very unlikely someone wants to XOR with 0 */
345         /* This fixes the rubber-drawings in paintbrush */
346         if (val.foreground == 0)
347             val.foreground = (WhitePixel( gdi_display, DefaultScreen(gdi_display) ) ^
348                               BlackPixel( gdi_display, DefaultScreen(gdi_display) ));
349         val.function = GXxor;
350         break;
351     default :
352         val.foreground = physDev->pen.pixel;
353         val.function   = X11DRV_XROPfunction[rop2-1];
354     }
355     val.background = physDev->backgroundPixel;
356     val.fill_style = FillSolid;
357     val.line_width = physDev->pen.width;
358     if (val.line_width <= 1) {
359         val.cap_style = CapNotLast;
360     } else {
361         switch (physDev->pen.endcap)
362         {
363         case PS_ENDCAP_SQUARE:
364             val.cap_style = CapProjecting;
365             break;
366         case PS_ENDCAP_FLAT:
367             val.cap_style = CapButt;
368             break;
369         case PS_ENDCAP_ROUND:
370         default:
371             val.cap_style = CapRound;
372         }
373     }
374     switch (physDev->pen.linejoin)
375     {
376     case PS_JOIN_BEVEL:
377         val.join_style = JoinBevel;
378         break;
379     case PS_JOIN_MITER:
380         val.join_style = JoinMiter;
381         break;
382     case PS_JOIN_ROUND:
383     default:
384         val.join_style = JoinRound;
385     }
386
387     if (physDev->pen.dash_len)
388         val.line_style = ((GetBkMode(physDev->hdc) == OPAQUE) && (!physDev->pen.ext))
389                          ? LineDoubleDash : LineOnOffDash;
390     else
391         val.line_style = LineSolid;
392
393     wine_tsx11_lock();
394     if (physDev->pen.dash_len)
395         XSetDashes( gdi_display, physDev->gc, 0, physDev->pen.dashes, physDev->pen.dash_len );
396     XChangeGC( gdi_display, physDev->gc,
397                GCFunction | GCForeground | GCBackground | GCLineWidth |
398                GCLineStyle | GCCapStyle | GCJoinStyle | GCFillStyle, &val );
399     wine_tsx11_unlock();
400     return TRUE;
401 }
402
403
404 /***********************************************************************
405  *           X11DRV_SetupGCForText
406  *
407  * Setup physDev->gc for text drawing operations.
408  * Return FALSE if the font is null, TRUE otherwise.
409  */
410 BOOL X11DRV_SetupGCForText( X11DRV_PDEVICE *physDev )
411 {
412     XFontStruct* xfs = XFONT_GetFontStruct( physDev->font );
413
414     if( xfs )
415     {
416         XGCValues val;
417
418         val.function   = GXcopy;  /* Text is always GXcopy */
419         val.foreground = physDev->textPixel;
420         val.background = physDev->backgroundPixel;
421         val.fill_style = FillSolid;
422         val.font       = xfs->fid;
423
424         wine_tsx11_lock();
425         XChangeGC( gdi_display, physDev->gc,
426                    GCFunction | GCForeground | GCBackground | GCFillStyle |
427                    GCFont, &val );
428         wine_tsx11_unlock();
429         return TRUE;
430     }
431     WARN("Physical font failure\n" );
432     return FALSE;
433 }
434
435 /***********************************************************************
436  *           X11DRV_XWStoDS
437  *
438  * Performs a world-to-viewport transformation on the specified width.
439  */
440 INT X11DRV_XWStoDS( X11DRV_PDEVICE *physDev, INT width )
441 {
442     POINT pt[2];
443
444     pt[0].x = 0;
445     pt[0].y = 0;
446     pt[1].x = width;
447     pt[1].y = 0;
448     LPtoDP( physDev->hdc, pt, 2 );
449     return pt[1].x - pt[0].x;
450 }
451
452 /***********************************************************************
453  *           X11DRV_YWStoDS
454  *
455  * Performs a world-to-viewport transformation on the specified height.
456  */
457 INT X11DRV_YWStoDS( X11DRV_PDEVICE *physDev, INT height )
458 {
459     POINT pt[2];
460
461     pt[0].x = 0;
462     pt[0].y = 0;
463     pt[1].x = 0;
464     pt[1].y = height;
465     LPtoDP( physDev->hdc, pt, 2 );
466     return pt[1].y - pt[0].y;
467 }
468
469 /***********************************************************************
470  *           X11DRV_LineTo
471  */
472 BOOL CDECL
473 X11DRV_LineTo( X11DRV_PDEVICE *physDev, INT x, INT y )
474 {
475     POINT pt[2];
476
477     if (X11DRV_SetupGCForPen( physDev )) {
478         /* Update the pixmap from the DIB section */
479         X11DRV_LockDIBSection(physDev, DIB_Status_GdiMod);
480
481         GetCurrentPositionEx( physDev->hdc, &pt[0] );
482         pt[1].x = x;
483         pt[1].y = y;
484         LPtoDP( physDev->hdc, pt, 2 );
485
486         wine_tsx11_lock();
487         XDrawLine(gdi_display, physDev->drawable, physDev->gc,
488                   physDev->dc_rect.left + pt[0].x, physDev->dc_rect.top + pt[0].y,
489                   physDev->dc_rect.left + pt[1].x, physDev->dc_rect.top + pt[1].y );
490         wine_tsx11_unlock();
491
492         /* Update the DIBSection from the pixmap */
493         X11DRV_UnlockDIBSection(physDev, TRUE);
494     }
495     return TRUE;
496 }
497
498
499
500 /***********************************************************************
501  *           X11DRV_DrawArc
502  *
503  * Helper functions for Arc(), Chord() and Pie().
504  * 'lines' is the number of lines to draw: 0 for Arc, 1 for Chord, 2 for Pie.
505  *
506  */
507 static BOOL
508 X11DRV_DrawArc( X11DRV_PDEVICE *physDev, INT left, INT top, INT right,
509                 INT bottom, INT xstart, INT ystart,
510                 INT xend, INT yend, INT lines )
511 {
512     INT xcenter, ycenter, istart_angle, idiff_angle;
513     INT width, oldwidth;
514     double start_angle, end_angle;
515     XPoint points[4];
516     BOOL update = FALSE;
517     POINT start, end;
518     RECT rc = get_device_rect( physDev->hdc, left, top, right, bottom );
519
520     start.x = xstart;
521     start.y = ystart;
522     end.x = xend;
523     end.y = yend;
524     LPtoDP(physDev->hdc, &start, 1);
525     LPtoDP(physDev->hdc, &end, 1);
526
527     if ((rc.left == rc.right) || (rc.top == rc.bottom)
528             ||(lines && ((rc.right-rc.left==1)||(rc.bottom-rc.top==1)))) return TRUE;
529
530     if (GetArcDirection( physDev->hdc ) == AD_CLOCKWISE)
531       { POINT tmp = start; start = end; end = tmp; }
532
533     oldwidth = width = physDev->pen.width;
534     if (!width) width = 1;
535     if(physDev->pen.style == PS_NULL) width = 0;
536
537     if ((physDev->pen.style == PS_INSIDEFRAME))
538     {
539         if (2*width > (rc.right-rc.left)) width=(rc.right-rc.left + 1)/2;
540         if (2*width > (rc.bottom-rc.top)) width=(rc.bottom-rc.top + 1)/2;
541         rc.left   += width / 2;
542         rc.right  -= (width - 1) / 2;
543         rc.top    += width / 2;
544         rc.bottom -= (width - 1) / 2;
545     }
546     if(width == 0) width = 1; /* more accurate */
547     physDev->pen.width = width;
548
549     xcenter = (rc.right + rc.left) / 2;
550     ycenter = (rc.bottom + rc.top) / 2;
551     start_angle = atan2( (double)(ycenter-start.y)*(rc.right-rc.left),
552                          (double)(start.x-xcenter)*(rc.bottom-rc.top) );
553     end_angle   = atan2( (double)(ycenter-end.y)*(rc.right-rc.left),
554                          (double)(end.x-xcenter)*(rc.bottom-rc.top) );
555     if ((start.x==end.x)&&(start.y==end.y))
556       { /* A lazy program delivers xstart=xend=ystart=yend=0) */
557         start_angle = 0;
558         end_angle = 2* PI;
559       }
560     else /* notorious cases */
561       if ((start_angle == PI)&&( end_angle <0))
562         start_angle = - PI;
563     else
564       if ((end_angle == PI)&&( start_angle <0))
565         end_angle = - PI;
566     istart_angle = (INT)(start_angle * 180 * 64 / PI + 0.5);
567     idiff_angle  = (INT)((end_angle - start_angle) * 180 * 64 / PI + 0.5);
568     if (idiff_angle <= 0) idiff_angle += 360 * 64;
569
570     /* Update the pixmap from the DIB section */
571     X11DRV_LockDIBSection(physDev, DIB_Status_GdiMod);
572
573       /* Fill arc with brush if Chord() or Pie() */
574
575     if ((lines > 0) && X11DRV_SetupGCForBrush( physDev )) {
576         wine_tsx11_lock();
577         XSetArcMode( gdi_display, physDev->gc, (lines==1) ? ArcChord : ArcPieSlice);
578         XFillArc( gdi_display, physDev->drawable, physDev->gc,
579                   physDev->dc_rect.left + rc.left, physDev->dc_rect.top + rc.top,
580                   rc.right-rc.left-1, rc.bottom-rc.top-1, istart_angle, idiff_angle );
581         wine_tsx11_unlock();
582         update = TRUE;
583     }
584
585       /* Draw arc and lines */
586
587     if (X11DRV_SetupGCForPen( physDev ))
588     {
589         wine_tsx11_lock();
590         XDrawArc( gdi_display, physDev->drawable, physDev->gc,
591                   physDev->dc_rect.left + rc.left, physDev->dc_rect.top + rc.top,
592                   rc.right-rc.left-1, rc.bottom-rc.top-1, istart_angle, idiff_angle );
593         if (lines) {
594             /* use the truncated values */
595             start_angle=(double)istart_angle*PI/64./180.;
596             end_angle=(double)(istart_angle+idiff_angle)*PI/64./180.;
597             /* calculate the endpoints and round correctly */
598             points[0].x = (int) floor(physDev->dc_rect.left + (rc.right+rc.left)/2.0 +
599                     cos(start_angle) * (rc.right-rc.left-width*2+2) / 2. + 0.5);
600             points[0].y = (int) floor(physDev->dc_rect.top + (rc.top+rc.bottom)/2.0 -
601                     sin(start_angle) * (rc.bottom-rc.top-width*2+2) / 2. + 0.5);
602             points[1].x = (int) floor(physDev->dc_rect.left + (rc.right+rc.left)/2.0 +
603                     cos(end_angle) * (rc.right-rc.left-width*2+2) / 2. + 0.5);
604             points[1].y = (int) floor(physDev->dc_rect.top + (rc.top+rc.bottom)/2.0 -
605                     sin(end_angle) * (rc.bottom-rc.top-width*2+2) / 2. + 0.5);
606
607             /* OK, this stuff is optimized for Xfree86
608              * which is probably the server most used by
609              * wine users. Other X servers will not
610              * display correctly. (eXceed for instance)
611              * so if you feel you must make changes, make sure that
612              * you either use Xfree86 or separate your changes
613              * from these (compile switch or whatever)
614              */
615             if (lines == 2) {
616                 INT dx1,dy1;
617                 points[3] = points[1];
618                 points[1].x = physDev->dc_rect.left + xcenter;
619                 points[1].y = physDev->dc_rect.top + ycenter;
620                 points[2] = points[1];
621                 dx1=points[1].x-points[0].x;
622                 dy1=points[1].y-points[0].y;
623                 if(((rc.top-rc.bottom) | -2) == -2)
624                     if(dy1>0) points[1].y--;
625                 if(dx1<0) {
626                     if (((-dx1)*64)<=ABS(dy1)*37) points[0].x--;
627                     if(((-dx1*9))<(dy1*16)) points[0].y--;
628                     if( dy1<0 && ((dx1*9)) < (dy1*16)) points[0].y--;
629                 } else {
630                     if(dy1 < 0)  points[0].y--;
631                     if(((rc.right-rc.left) | -2) == -2) points[1].x--;
632                 }
633                 dx1=points[3].x-points[2].x;
634                 dy1=points[3].y-points[2].y;
635                 if(((rc.top-rc.bottom) | -2 ) == -2)
636                     if(dy1 < 0) points[2].y--;
637                 if( dx1<0){
638                     if( dy1>0) points[3].y--;
639                     if(((rc.right-rc.left) | -2) == -2 ) points[2].x--;
640                 }else {
641                     points[3].y--;
642                     if( dx1 * 64 < dy1 * -37 ) points[3].x--;
643                 }
644                 lines++;
645             }
646             XDrawLines( gdi_display, physDev->drawable, physDev->gc,
647                         points, lines+1, CoordModeOrigin );
648         }
649         wine_tsx11_unlock();
650         update = TRUE;
651     }
652
653     /* Update the DIBSection of the pixmap */
654     X11DRV_UnlockDIBSection(physDev, update);
655
656     physDev->pen.width = oldwidth;
657     return TRUE;
658 }
659
660
661 /***********************************************************************
662  *           X11DRV_Arc
663  */
664 BOOL CDECL
665 X11DRV_Arc( X11DRV_PDEVICE *physDev, INT left, INT top, INT right, INT bottom,
666             INT xstart, INT ystart, INT xend, INT yend )
667 {
668     return X11DRV_DrawArc( physDev, left, top, right, bottom,
669                            xstart, ystart, xend, yend, 0 );
670 }
671
672
673 /***********************************************************************
674  *           X11DRV_Pie
675  */
676 BOOL CDECL
677 X11DRV_Pie( X11DRV_PDEVICE *physDev, INT left, INT top, INT right, INT bottom,
678             INT xstart, INT ystart, INT xend, INT yend )
679 {
680     return X11DRV_DrawArc( physDev, left, top, right, bottom,
681                            xstart, ystart, xend, yend, 2 );
682 }
683
684 /***********************************************************************
685  *           X11DRV_Chord
686  */
687 BOOL CDECL
688 X11DRV_Chord( X11DRV_PDEVICE *physDev, INT left, INT top, INT right, INT bottom,
689               INT xstart, INT ystart, INT xend, INT yend )
690 {
691     return X11DRV_DrawArc( physDev, left, top, right, bottom,
692                            xstart, ystart, xend, yend, 1 );
693 }
694
695
696 /***********************************************************************
697  *           X11DRV_Ellipse
698  */
699 BOOL CDECL
700 X11DRV_Ellipse( X11DRV_PDEVICE *physDev, INT left, INT top, INT right, INT bottom )
701 {
702     INT width, oldwidth;
703     BOOL update = FALSE;
704     RECT rc = get_device_rect( physDev->hdc, left, top, right, bottom );
705
706     if ((rc.left == rc.right) || (rc.top == rc.bottom)) return TRUE;
707
708     oldwidth = width = physDev->pen.width;
709     if (!width) width = 1;
710     if(physDev->pen.style == PS_NULL) width = 0;
711
712     if ((physDev->pen.style == PS_INSIDEFRAME))
713     {
714         if (2*width > (rc.right-rc.left)) width=(rc.right-rc.left + 1)/2;
715         if (2*width > (rc.bottom-rc.top)) width=(rc.bottom-rc.top + 1)/2;
716         rc.left   += width / 2;
717         rc.right  -= (width - 1) / 2;
718         rc.top    += width / 2;
719         rc.bottom -= (width - 1) / 2;
720     }
721     if(width == 0) width = 1; /* more accurate */
722     physDev->pen.width = width;
723
724     /* Update the pixmap from the DIB section */
725     X11DRV_LockDIBSection(physDev, DIB_Status_GdiMod);
726
727     if (X11DRV_SetupGCForBrush( physDev ))
728     {
729         wine_tsx11_lock();
730         XFillArc( gdi_display, physDev->drawable, physDev->gc,
731                   physDev->dc_rect.left + rc.left, physDev->dc_rect.top + rc.top,
732                   rc.right-rc.left-1, rc.bottom-rc.top-1, 0, 360*64 );
733         wine_tsx11_unlock();
734         update = TRUE;
735     }
736     if (X11DRV_SetupGCForPen( physDev ))
737     {
738         wine_tsx11_lock();
739         XDrawArc( gdi_display, physDev->drawable, physDev->gc,
740                   physDev->dc_rect.left + rc.left, physDev->dc_rect.top + rc.top,
741                   rc.right-rc.left-1, rc.bottom-rc.top-1, 0, 360*64 );
742         wine_tsx11_unlock();
743         update = TRUE;
744     }
745
746     /* Update the DIBSection from the pixmap */
747     X11DRV_UnlockDIBSection(physDev, update);
748
749     physDev->pen.width = oldwidth;
750     return TRUE;
751 }
752
753
754 /***********************************************************************
755  *           X11DRV_Rectangle
756  */
757 BOOL CDECL
758 X11DRV_Rectangle(X11DRV_PDEVICE *physDev, INT left, INT top, INT right, INT bottom)
759 {
760     INT width, oldwidth, oldjoinstyle;
761     BOOL update = FALSE;
762     RECT rc = get_device_rect( physDev->hdc, left, top, right, bottom );
763
764     TRACE("(%d %d %d %d)\n", left, top, right, bottom);
765
766     if ((rc.left == rc.right) || (rc.top == rc.bottom)) return TRUE;
767
768     oldwidth = width = physDev->pen.width;
769     if (!width) width = 1;
770     if(physDev->pen.style == PS_NULL) width = 0;
771
772     if ((physDev->pen.style == PS_INSIDEFRAME))
773     {
774         if (2*width > (rc.right-rc.left)) width=(rc.right-rc.left + 1)/2;
775         if (2*width > (rc.bottom-rc.top)) width=(rc.bottom-rc.top + 1)/2;
776         rc.left   += width / 2;
777         rc.right  -= (width - 1) / 2;
778         rc.top    += width / 2;
779         rc.bottom -= (width - 1) / 2;
780     }
781     if(width == 1) width = 0;
782     physDev->pen.width = width;
783     oldjoinstyle = physDev->pen.linejoin;
784     if(physDev->pen.type != PS_GEOMETRIC)
785         physDev->pen.linejoin = PS_JOIN_MITER;
786
787     /* Update the pixmap from the DIB section */
788     X11DRV_LockDIBSection(physDev, DIB_Status_GdiMod);
789
790     if ((rc.right > rc.left + width) && (rc.bottom > rc.top + width))
791     {
792         if (X11DRV_SetupGCForBrush( physDev ))
793         {
794             wine_tsx11_lock();
795             XFillRectangle( gdi_display, physDev->drawable, physDev->gc,
796                             physDev->dc_rect.left + rc.left + (width + 1) / 2,
797                             physDev->dc_rect.top + rc.top + (width + 1) / 2,
798                             rc.right-rc.left-width-1, rc.bottom-rc.top-width-1);
799             wine_tsx11_unlock();
800             update = TRUE;
801         }
802     }
803     if (X11DRV_SetupGCForPen( physDev ))
804     {
805         wine_tsx11_lock();
806         XDrawRectangle( gdi_display, physDev->drawable, physDev->gc,
807                         physDev->dc_rect.left + rc.left, physDev->dc_rect.top + rc.top,
808                         rc.right-rc.left-1, rc.bottom-rc.top-1 );
809         wine_tsx11_unlock();
810         update = TRUE;
811     }
812
813     /* Update the DIBSection from the pixmap */
814     X11DRV_UnlockDIBSection(physDev, update);
815
816     physDev->pen.width = oldwidth;
817     physDev->pen.linejoin = oldjoinstyle;
818     return TRUE;
819 }
820
821 /***********************************************************************
822  *           X11DRV_RoundRect
823  */
824 BOOL CDECL
825 X11DRV_RoundRect( X11DRV_PDEVICE *physDev, INT left, INT top, INT right,
826                   INT bottom, INT ell_width, INT ell_height )
827 {
828     INT width, oldwidth, oldendcap;
829     BOOL update = FALSE;
830     POINT pts[2];
831     RECT rc = get_device_rect( physDev->hdc, left, top, right, bottom );
832
833     TRACE("(%d %d %d %d  %d %d\n",
834         left, top, right, bottom, ell_width, ell_height);
835
836     if ((rc.left == rc.right) || (rc.top == rc.bottom))
837         return TRUE;
838
839     /* Make sure ell_width and ell_height are >= 1 otherwise XDrawArc gets
840        called with width/height < 0 */
841     pts[0].x = pts[0].y = 0;
842     pts[1].x = ell_width;
843     pts[1].y = ell_height;
844     LPtoDP(physDev->hdc, pts, 2);
845     ell_width  = max(abs( pts[1].x - pts[0].x ), 1);
846     ell_height = max(abs( pts[1].y - pts[0].y ), 1);
847
848     oldwidth = width = physDev->pen.width;
849     oldendcap = physDev->pen.endcap;
850     if (!width) width = 1;
851     if(physDev->pen.style == PS_NULL) width = 0;
852
853     if ((physDev->pen.style == PS_INSIDEFRAME))
854     {
855         if (2*width > (rc.right-rc.left)) width=(rc.right-rc.left + 1)/2;
856         if (2*width > (rc.bottom-rc.top)) width=(rc.bottom-rc.top + 1)/2;
857         rc.left   += width / 2;
858         rc.right  -= (width - 1) / 2;
859         rc.top    += width / 2;
860         rc.bottom -= (width - 1) / 2;
861     }
862     if(width == 0) width = 1;
863     physDev->pen.width = width;
864     physDev->pen.endcap = PS_ENDCAP_SQUARE;
865
866     /* Update the pixmap from the DIB section */
867     X11DRV_LockDIBSection(physDev, DIB_Status_GdiMod);
868
869     if (X11DRV_SetupGCForBrush( physDev ))
870     {
871         wine_tsx11_lock();
872         if (ell_width > (rc.right-rc.left) )
873             if (ell_height > (rc.bottom-rc.top) )
874                 XFillArc( gdi_display, physDev->drawable, physDev->gc,
875                           physDev->dc_rect.left + rc.left, physDev->dc_rect.top + rc.top,
876                           rc.right - rc.left - 1, rc.bottom - rc.top - 1,
877                           0, 360 * 64 );
878             else{
879                 XFillArc( gdi_display, physDev->drawable, physDev->gc,
880                           physDev->dc_rect.left + rc.left, physDev->dc_rect.top + rc.top,
881                           rc.right - rc.left - 1, ell_height, 0, 180 * 64 );
882                 XFillArc( gdi_display, physDev->drawable, physDev->gc,
883                           physDev->dc_rect.left + rc.left,
884                           physDev->dc_rect.top + rc.bottom - ell_height - 1,
885                           rc.right - rc.left - 1, ell_height, 180 * 64,
886                           180 * 64 );
887             }
888         else if (ell_height > (rc.bottom-rc.top) ){
889             XFillArc( gdi_display, physDev->drawable, physDev->gc,
890                       physDev->dc_rect.left + rc.left, physDev->dc_rect.top + rc.top,
891                       ell_width, rc.bottom - rc.top - 1, 90 * 64, 180 * 64 );
892             XFillArc( gdi_display, physDev->drawable, physDev->gc,
893                       physDev->dc_rect.left + rc.right - ell_width - 1, physDev->dc_rect.top + rc.top,
894                       ell_width, rc.bottom - rc.top - 1, 270 * 64, 180 * 64 );
895         }else{
896             XFillArc( gdi_display, physDev->drawable, physDev->gc,
897                       physDev->dc_rect.left + rc.left, physDev->dc_rect.top + rc.top,
898                       ell_width, ell_height, 90 * 64, 90 * 64 );
899             XFillArc( gdi_display, physDev->drawable, physDev->gc,
900                       physDev->dc_rect.left + rc.left,
901                       physDev->dc_rect.top + rc.bottom - ell_height - 1,
902                       ell_width, ell_height, 180 * 64, 90 * 64 );
903             XFillArc( gdi_display, physDev->drawable, physDev->gc,
904                       physDev->dc_rect.left + rc.right - ell_width - 1,
905                       physDev->dc_rect.top + rc.bottom - ell_height - 1,
906                       ell_width, ell_height, 270 * 64, 90 * 64 );
907             XFillArc( gdi_display, physDev->drawable, physDev->gc,
908                       physDev->dc_rect.left + rc.right - ell_width - 1,
909                       physDev->dc_rect.top + rc.top,
910                       ell_width, ell_height, 0, 90 * 64 );
911         }
912         if (ell_width < rc.right - rc.left)
913         {
914             XFillRectangle( gdi_display, physDev->drawable, physDev->gc,
915                             physDev->dc_rect.left + rc.left + (ell_width + 1) / 2,
916                             physDev->dc_rect.top + rc.top + 1,
917                             rc.right - rc.left - ell_width - 1,
918                             (ell_height + 1) / 2 - 1);
919             XFillRectangle( gdi_display, physDev->drawable, physDev->gc,
920                             physDev->dc_rect.left + rc.left + (ell_width + 1) / 2,
921                             physDev->dc_rect.top + rc.bottom - (ell_height) / 2 - 1,
922                             rc.right - rc.left - ell_width - 1,
923                             (ell_height) / 2 );
924         }
925         if  (ell_height < rc.bottom - rc.top)
926         {
927             XFillRectangle( gdi_display, physDev->drawable, physDev->gc,
928                             physDev->dc_rect.left + rc.left + 1,
929                             physDev->dc_rect.top + rc.top + (ell_height + 1) / 2,
930                             rc.right - rc.left - 2,
931                             rc.bottom - rc.top - ell_height - 1);
932         }
933         wine_tsx11_unlock();
934         update = TRUE;
935     }
936     /* FIXME: this could be done with on X call
937      * more efficient and probably more correct
938      * on any X server: XDrawArcs will draw
939      * straight horizontal and vertical lines
940      * if width or height are zero.
941      *
942      * BTW this stuff is optimized for an Xfree86 server
943      * read the comments inside the X11DRV_DrawArc function
944      */
945     if (X11DRV_SetupGCForPen( physDev ))
946     {
947         wine_tsx11_lock();
948         if (ell_width > (rc.right-rc.left) )
949             if (ell_height > (rc.bottom-rc.top) )
950                 XDrawArc( gdi_display, physDev->drawable, physDev->gc,
951                           physDev->dc_rect.left + rc.left, physDev->dc_rect.top + rc.top,
952                           rc.right - rc.left - 1, rc.bottom - rc.top - 1, 0 , 360 * 64 );
953             else{
954                 XDrawArc( gdi_display, physDev->drawable, physDev->gc,
955                           physDev->dc_rect.left + rc.left, physDev->dc_rect.top + rc.top,
956                           rc.right - rc.left - 1, ell_height - 1, 0 , 180 * 64 );
957                 XDrawArc( gdi_display, physDev->drawable, physDev->gc,
958                           physDev->dc_rect.left + rc.left,
959                           physDev->dc_rect.top + rc.bottom - ell_height,
960                           rc.right - rc.left - 1, ell_height - 1, 180 * 64 , 180 * 64 );
961             }
962         else if (ell_height > (rc.bottom-rc.top) ){
963             XDrawArc( gdi_display, physDev->drawable, physDev->gc,
964                       physDev->dc_rect.left + rc.left, physDev->dc_rect.top + rc.top,
965                       ell_width - 1 , rc.bottom - rc.top - 1, 90 * 64 , 180 * 64 );
966             XDrawArc( gdi_display, physDev->drawable, physDev->gc,
967                       physDev->dc_rect.left + rc.right - ell_width,
968                       physDev->dc_rect.top + rc.top,
969                       ell_width - 1 , rc.bottom - rc.top - 1, 270 * 64 , 180 * 64 );
970         }else{
971             XDrawArc( gdi_display, physDev->drawable, physDev->gc,
972                       physDev->dc_rect.left + rc.left, physDev->dc_rect.top + rc.top,
973                       ell_width - 1, ell_height - 1, 90 * 64, 90 * 64 );
974             XDrawArc( gdi_display, physDev->drawable, physDev->gc,
975                       physDev->dc_rect.left + rc.left, physDev->dc_rect.top + rc.bottom - ell_height,
976                       ell_width - 1, ell_height - 1, 180 * 64, 90 * 64 );
977             XDrawArc( gdi_display, physDev->drawable, physDev->gc,
978                       physDev->dc_rect.left + rc.right - ell_width,
979                       physDev->dc_rect.top + rc.bottom - ell_height,
980                       ell_width - 1, ell_height - 1, 270 * 64, 90 * 64 );
981             XDrawArc( gdi_display, physDev->drawable, physDev->gc,
982                       physDev->dc_rect.left + rc.right - ell_width, physDev->dc_rect.top + rc.top,
983                       ell_width - 1, ell_height - 1, 0, 90 * 64 );
984         }
985         if (ell_width < rc.right - rc.left)
986         {
987             XDrawLine( gdi_display, physDev->drawable, physDev->gc,
988                        physDev->dc_rect.left + rc.left + ell_width / 2,
989                        physDev->dc_rect.top + rc.top,
990                        physDev->dc_rect.left + rc.right - (ell_width+1) / 2,
991                        physDev->dc_rect.top + rc.top);
992             XDrawLine( gdi_display, physDev->drawable, physDev->gc,
993                        physDev->dc_rect.left + rc.left + ell_width / 2 ,
994                        physDev->dc_rect.top + rc.bottom - 1,
995                        physDev->dc_rect.left + rc.right - (ell_width+1)/ 2,
996                        physDev->dc_rect.top + rc.bottom - 1);
997         }
998         if (ell_height < rc.bottom - rc.top)
999         {
1000             XDrawLine( gdi_display, physDev->drawable, physDev->gc,
1001                        physDev->dc_rect.left + rc.right - 1,
1002                        physDev->dc_rect.top + rc.top + ell_height / 2,
1003                        physDev->dc_rect.left + rc.right - 1,
1004                        physDev->dc_rect.top + rc.bottom - (ell_height+1) / 2);
1005             XDrawLine( gdi_display, physDev->drawable, physDev->gc,
1006                        physDev->dc_rect.left + rc.left,
1007                        physDev->dc_rect.top + rc.top + ell_height / 2,
1008                        physDev->dc_rect.left + rc.left,
1009                        physDev->dc_rect.top + rc.bottom - (ell_height+1) / 2);
1010         }
1011         wine_tsx11_unlock();
1012         update = TRUE;
1013     }
1014     /* Update the DIBSection from the pixmap */
1015     X11DRV_UnlockDIBSection(physDev, update);
1016
1017     physDev->pen.width = oldwidth;
1018     physDev->pen.endcap = oldendcap;
1019     return TRUE;
1020 }
1021
1022
1023 /***********************************************************************
1024  *           X11DRV_SetPixel
1025  */
1026 COLORREF CDECL
1027 X11DRV_SetPixel( X11DRV_PDEVICE *physDev, INT x, INT y, COLORREF color )
1028 {
1029     unsigned long pixel;
1030     POINT pt;
1031
1032     pt.x = x;
1033     pt.y = y;
1034     LPtoDP( physDev->hdc, &pt, 1 );
1035     pixel = X11DRV_PALETTE_ToPhysical( physDev, color );
1036
1037     /* Update the pixmap from the DIB section */
1038     X11DRV_LockDIBSection(physDev, DIB_Status_GdiMod);
1039
1040     /* inefficient but simple... */
1041     wine_tsx11_lock();
1042     XSetForeground( gdi_display, physDev->gc, pixel );
1043     XSetFunction( gdi_display, physDev->gc, GXcopy );
1044     XDrawPoint( gdi_display, physDev->drawable, physDev->gc,
1045                 physDev->dc_rect.left + pt.x, physDev->dc_rect.top + pt.y );
1046     wine_tsx11_unlock();
1047
1048     /* Update the DIBSection from the pixmap */
1049     X11DRV_UnlockDIBSection(physDev, TRUE);
1050
1051     return X11DRV_PALETTE_ToLogical(physDev, pixel);
1052 }
1053
1054
1055 /***********************************************************************
1056  *           X11DRV_GetPixel
1057  */
1058 COLORREF CDECL
1059 X11DRV_GetPixel( X11DRV_PDEVICE *physDev, INT x, INT y )
1060 {
1061     static Pixmap pixmap = 0;
1062     XImage * image;
1063     int pixel;
1064     POINT pt;
1065     BOOL memdc = (GetObjectType(physDev->hdc) == OBJ_MEMDC);
1066
1067     pt.x = x;
1068     pt.y = y;
1069     LPtoDP( physDev->hdc, &pt, 1 );
1070
1071     /* Update the pixmap from the DIB section */
1072     X11DRV_LockDIBSection(physDev, DIB_Status_GdiMod);
1073
1074     wine_tsx11_lock();
1075     if (memdc)
1076     {
1077         image = XGetImage( gdi_display, physDev->drawable,
1078                            physDev->dc_rect.left + pt.x, physDev->dc_rect.top + pt.y,
1079                            1, 1, AllPlanes, ZPixmap );
1080     }
1081     else
1082     {
1083         /* If we are reading from the screen, use a temporary copy */
1084         /* to avoid a BadMatch error */
1085         if (!pixmap) pixmap = XCreatePixmap( gdi_display, root_window,
1086                                              1, 1, physDev->depth );
1087         XCopyArea( gdi_display, physDev->drawable, pixmap, get_bitmap_gc(physDev->depth),
1088                    physDev->dc_rect.left + pt.x, physDev->dc_rect.top + pt.y, 1, 1, 0, 0 );
1089         image = XGetImage( gdi_display, pixmap, 0, 0, 1, 1, AllPlanes, ZPixmap );
1090     }
1091     pixel = XGetPixel( image, 0, 0 );
1092     XDestroyImage( image );
1093     wine_tsx11_unlock();
1094
1095     /* Update the DIBSection from the pixmap */
1096     X11DRV_UnlockDIBSection(physDev, FALSE);
1097     if( physDev->depth > 1)
1098         pixel = X11DRV_PALETTE_ToLogical(physDev, pixel);
1099     else
1100         /* monochrome bitmaps return black or white */
1101         if( pixel) pixel = 0xffffff;
1102     return pixel;
1103
1104 }
1105
1106
1107 /***********************************************************************
1108  *           X11DRV_PaintRgn
1109  */
1110 BOOL CDECL
1111 X11DRV_PaintRgn( X11DRV_PDEVICE *physDev, HRGN hrgn )
1112 {
1113     if (X11DRV_SetupGCForBrush( physDev ))
1114     {
1115         unsigned int i;
1116         XRectangle *rect;
1117         RGNDATA *data = X11DRV_GetRegionData( hrgn, physDev->hdc );
1118
1119         if (!data) return FALSE;
1120         rect = (XRectangle *)data->Buffer;
1121         for (i = 0; i < data->rdh.nCount; i++)
1122         {
1123             rect[i].x += physDev->dc_rect.left;
1124             rect[i].y += physDev->dc_rect.top;
1125         }
1126
1127         X11DRV_LockDIBSection(physDev, DIB_Status_GdiMod);
1128         wine_tsx11_lock();
1129         XFillRectangles( gdi_display, physDev->drawable, physDev->gc, rect, data->rdh.nCount );
1130         wine_tsx11_unlock();
1131         X11DRV_UnlockDIBSection(physDev, TRUE);
1132         HeapFree( GetProcessHeap(), 0, data );
1133     }
1134     return TRUE;
1135 }
1136
1137 /**********************************************************************
1138  *          X11DRV_Polyline
1139  */
1140 BOOL CDECL
1141 X11DRV_Polyline( X11DRV_PDEVICE *physDev, const POINT* pt, INT count )
1142 {
1143     int i;
1144     XPoint *points;
1145
1146     if (!(points = HeapAlloc( GetProcessHeap(), 0, sizeof(XPoint) * count )))
1147     {
1148         WARN("No memory to convert POINTs to XPoints!\n");
1149         return FALSE;
1150     }
1151     for (i = 0; i < count; i++)
1152     {
1153         POINT tmp = pt[i];
1154         LPtoDP(physDev->hdc, &tmp, 1);
1155         points[i].x = physDev->dc_rect.left + tmp.x;
1156         points[i].y = physDev->dc_rect.top + tmp.y;
1157     }
1158
1159     if (X11DRV_SetupGCForPen ( physDev ))
1160     {
1161         X11DRV_LockDIBSection(physDev, DIB_Status_GdiMod);
1162         wine_tsx11_lock();
1163         XDrawLines( gdi_display, physDev->drawable, physDev->gc,
1164                     points, count, CoordModeOrigin );
1165         wine_tsx11_unlock();
1166         X11DRV_UnlockDIBSection(physDev, TRUE);
1167     }
1168
1169     HeapFree( GetProcessHeap(), 0, points );
1170     return TRUE;
1171 }
1172
1173
1174 /**********************************************************************
1175  *          X11DRV_Polygon
1176  */
1177 BOOL CDECL
1178 X11DRV_Polygon( X11DRV_PDEVICE *physDev, const POINT* pt, INT count )
1179 {
1180     register int i;
1181     XPoint *points;
1182     BOOL update = FALSE;
1183
1184     if (!(points = HeapAlloc( GetProcessHeap(), 0, sizeof(XPoint) * (count+1) )))
1185     {
1186         WARN("No memory to convert POINTs to XPoints!\n");
1187         return FALSE;
1188     }
1189     for (i = 0; i < count; i++)
1190     {
1191         POINT tmp = pt[i];
1192         LPtoDP(physDev->hdc, &tmp, 1);
1193         points[i].x = physDev->dc_rect.left + tmp.x;
1194         points[i].y = physDev->dc_rect.top + tmp.y;
1195     }
1196     points[count] = points[0];
1197
1198     /* Update the pixmap from the DIB section */
1199     X11DRV_LockDIBSection(physDev, DIB_Status_GdiMod);
1200
1201     if (X11DRV_SetupGCForBrush( physDev ))
1202     {
1203         wine_tsx11_lock();
1204         XFillPolygon( gdi_display, physDev->drawable, physDev->gc,
1205                       points, count+1, Complex, CoordModeOrigin);
1206         wine_tsx11_unlock();
1207         update = TRUE;
1208     }
1209     if (X11DRV_SetupGCForPen ( physDev ))
1210     {
1211         wine_tsx11_lock();
1212         XDrawLines( gdi_display, physDev->drawable, physDev->gc,
1213                     points, count+1, CoordModeOrigin );
1214         wine_tsx11_unlock();
1215         update = TRUE;
1216     }
1217
1218     /* Update the DIBSection from the pixmap */
1219     X11DRV_UnlockDIBSection(physDev, update);
1220
1221     HeapFree( GetProcessHeap(), 0, points );
1222     return TRUE;
1223 }
1224
1225
1226 /**********************************************************************
1227  *          X11DRV_PolyPolygon
1228  */
1229 BOOL CDECL
1230 X11DRV_PolyPolygon( X11DRV_PDEVICE *physDev, const POINT* pt, const INT* counts, UINT polygons)
1231 {
1232     HRGN hrgn;
1233
1234     /* FIXME: The points should be converted to device coords before */
1235     /* creating the region. */
1236
1237     hrgn = CreatePolyPolygonRgn( pt, counts, polygons, GetPolyFillMode( physDev->hdc ) );
1238     X11DRV_PaintRgn( physDev, hrgn );
1239     DeleteObject( hrgn );
1240
1241       /* Draw the outline of the polygons */
1242
1243     if (X11DRV_SetupGCForPen ( physDev ))
1244     {
1245         unsigned int i;
1246         int j, max = 0;
1247         XPoint *points;
1248
1249         /* Update the pixmap from the DIB section */
1250         X11DRV_LockDIBSection(physDev, DIB_Status_GdiMod);
1251
1252         for (i = 0; i < polygons; i++) if (counts[i] > max) max = counts[i];
1253         if (!(points = HeapAlloc( GetProcessHeap(), 0, sizeof(XPoint) * (max+1) )))
1254         {
1255             WARN("No memory to convert POINTs to XPoints!\n");
1256             return FALSE;
1257         }
1258         for (i = 0; i < polygons; i++)
1259         {
1260             for (j = 0; j < counts[i]; j++)
1261             {
1262                 POINT tmp = *pt;
1263                 LPtoDP(physDev->hdc, &tmp, 1);
1264                 points[j].x = physDev->dc_rect.left + tmp.x;
1265                 points[j].y = physDev->dc_rect.top + tmp.y;
1266                 pt++;
1267             }
1268             points[j] = points[0];
1269             wine_tsx11_lock();
1270             XDrawLines( gdi_display, physDev->drawable, physDev->gc,
1271                         points, j + 1, CoordModeOrigin );
1272             wine_tsx11_unlock();
1273         }
1274
1275         /* Update the DIBSection of the dc's bitmap */
1276         X11DRV_UnlockDIBSection(physDev, TRUE);
1277
1278         HeapFree( GetProcessHeap(), 0, points );
1279     }
1280     return TRUE;
1281 }
1282
1283
1284 /**********************************************************************
1285  *          X11DRV_PolyPolyline
1286  */
1287 BOOL CDECL
1288 X11DRV_PolyPolyline( X11DRV_PDEVICE *physDev, const POINT* pt, const DWORD* counts, DWORD polylines )
1289 {
1290     if (X11DRV_SetupGCForPen ( physDev ))
1291     {
1292         unsigned int i, j, max = 0;
1293         XPoint *points;
1294
1295         /* Update the pixmap from the DIB section */
1296         X11DRV_LockDIBSection(physDev, DIB_Status_GdiMod);
1297
1298         for (i = 0; i < polylines; i++) if (counts[i] > max) max = counts[i];
1299         if (!(points = HeapAlloc( GetProcessHeap(), 0, sizeof(XPoint) * max )))
1300         {
1301             WARN("No memory to convert POINTs to XPoints!\n");
1302             return FALSE;
1303         }
1304         for (i = 0; i < polylines; i++)
1305         {
1306             for (j = 0; j < counts[i]; j++)
1307             {
1308                 POINT tmp = *pt;
1309                 LPtoDP(physDev->hdc, &tmp, 1);
1310                 points[j].x = physDev->dc_rect.left + tmp.x;
1311                 points[j].y = physDev->dc_rect.top + tmp.y;
1312                 pt++;
1313             }
1314             wine_tsx11_lock();
1315             XDrawLines( gdi_display, physDev->drawable, physDev->gc,
1316                         points, j, CoordModeOrigin );
1317             wine_tsx11_unlock();
1318         }
1319
1320         /* Update the DIBSection of the dc's bitmap */
1321         X11DRV_UnlockDIBSection(physDev, TRUE);
1322
1323         HeapFree( GetProcessHeap(), 0, points );
1324     }
1325     return TRUE;
1326 }
1327
1328
1329 /**********************************************************************
1330  *          X11DRV_InternalFloodFill
1331  *
1332  * Internal helper function for flood fill.
1333  * (xorg,yorg) is the origin of the X image relative to the drawable.
1334  * (x,y) is relative to the origin of the X image.
1335  */
1336 static void X11DRV_InternalFloodFill(XImage *image, X11DRV_PDEVICE *physDev,
1337                                      int x, int y,
1338                                      int xOrg, int yOrg,
1339                                      unsigned long pixel, WORD fillType )
1340 {
1341     int left, right;
1342
1343 #define TO_FLOOD(x,y)  ((fillType == FLOODFILLBORDER) ? \
1344                         (XGetPixel(image,x,y) != pixel) : \
1345                         (XGetPixel(image,x,y) == pixel))
1346
1347     if (!TO_FLOOD(x,y)) return;
1348
1349       /* Find left and right boundaries */
1350
1351     left = right = x;
1352     while ((left > 0) && TO_FLOOD( left-1, y )) left--;
1353     while ((right < image->width) && TO_FLOOD( right, y )) right++;
1354     XFillRectangle( gdi_display, physDev->drawable, physDev->gc,
1355                     xOrg + left, yOrg + y, right-left, 1 );
1356
1357       /* Set the pixels of this line so we don't fill it again */
1358
1359     for (x = left; x < right; x++)
1360     {
1361         if (fillType == FLOODFILLBORDER) XPutPixel( image, x, y, pixel );
1362         else XPutPixel( image, x, y, ~pixel );
1363     }
1364
1365       /* Fill the line above */
1366
1367     if (--y >= 0)
1368     {
1369         x = left;
1370         while (x < right)
1371         {
1372             while ((x < right) && !TO_FLOOD(x,y)) x++;
1373             if (x >= right) break;
1374             while ((x < right) && TO_FLOOD(x,y)) x++;
1375             X11DRV_InternalFloodFill(image, physDev, x-1, y,
1376                                      xOrg, yOrg, pixel, fillType );
1377         }
1378     }
1379
1380       /* Fill the line below */
1381
1382     if ((y += 2) < image->height)
1383     {
1384         x = left;
1385         while (x < right)
1386         {
1387             while ((x < right) && !TO_FLOOD(x,y)) x++;
1388             if (x >= right) break;
1389             while ((x < right) && TO_FLOOD(x,y)) x++;
1390             X11DRV_InternalFloodFill(image, physDev, x-1, y,
1391                                      xOrg, yOrg, pixel, fillType );
1392         }
1393     }
1394 #undef TO_FLOOD
1395 }
1396
1397
1398 static int ExtFloodFillXGetImageErrorHandler( Display *dpy, XErrorEvent *event, void *arg )
1399 {
1400     return (event->request_code == X_GetImage && event->error_code == BadMatch);
1401 }
1402
1403 /**********************************************************************
1404  *          X11DRV_ExtFloodFill
1405  */
1406 BOOL CDECL
1407 X11DRV_ExtFloodFill( X11DRV_PDEVICE *physDev, INT x, INT y, COLORREF color,
1408                      UINT fillType )
1409 {
1410     XImage *image;
1411     RECT rect;
1412     POINT pt;
1413
1414     TRACE("X11DRV_ExtFloodFill %d,%d %06x %d\n", x, y, color, fillType );
1415
1416     pt.x = x;
1417     pt.y = y;
1418     LPtoDP( physDev->hdc, &pt, 1 );
1419     if (!PtInRegion( physDev->region, pt.x, pt.y )) return FALSE;
1420     GetRgnBox( physDev->region, &rect );
1421
1422     X11DRV_expect_error( gdi_display, ExtFloodFillXGetImageErrorHandler, NULL );
1423     image = XGetImage( gdi_display, physDev->drawable,
1424                        physDev->dc_rect.left + rect.left, physDev->dc_rect.top + rect.top,
1425                        rect.right - rect.left, rect.bottom - rect.top,
1426                        AllPlanes, ZPixmap );
1427     if(X11DRV_check_error()) image = NULL;
1428     if (!image) return FALSE;
1429
1430     if (X11DRV_SetupGCForBrush( physDev ))
1431     {
1432         unsigned long pixel = X11DRV_PALETTE_ToPhysical( physDev, color );
1433
1434         /* Update the pixmap from the DIB section */
1435         X11DRV_LockDIBSection(physDev, DIB_Status_GdiMod);
1436
1437           /* ROP mode is always GXcopy for flood-fill */
1438         wine_tsx11_lock();
1439         XSetFunction( gdi_display, physDev->gc, GXcopy );
1440         X11DRV_InternalFloodFill(image, physDev,
1441                                  pt.x - rect.left,
1442                                  pt.y - rect.top,
1443                                  physDev->dc_rect.left + rect.left,
1444                                  physDev->dc_rect.top + rect.top,
1445                                  pixel, fillType );
1446         wine_tsx11_unlock();
1447         /* Update the DIBSection of the dc's bitmap */
1448         X11DRV_UnlockDIBSection(physDev, TRUE);
1449     }
1450
1451     wine_tsx11_lock();
1452     XDestroyImage( image );
1453     wine_tsx11_unlock();
1454     return TRUE;
1455 }
1456
1457 /**********************************************************************
1458  *          X11DRV_SetBkColor
1459  */
1460 COLORREF CDECL
1461 X11DRV_SetBkColor( X11DRV_PDEVICE *physDev, COLORREF color )
1462 {
1463     physDev->backgroundPixel = X11DRV_PALETTE_ToPhysical( physDev, color );
1464     return color;
1465 }
1466
1467 /**********************************************************************
1468  *          X11DRV_SetTextColor
1469  */
1470 COLORREF CDECL
1471 X11DRV_SetTextColor( X11DRV_PDEVICE *physDev, COLORREF color )
1472 {
1473     physDev->textPixel = X11DRV_PALETTE_ToPhysical( physDev, color );
1474     return color;
1475 }
1476
1477
1478 static unsigned char *get_icm_profile( unsigned long *size )
1479 {
1480     Atom type;
1481     int format;
1482     unsigned long count, remaining;
1483     unsigned char *profile, *ret = NULL;
1484
1485     wine_tsx11_lock();
1486     XGetWindowProperty( gdi_display, DefaultRootWindow(gdi_display),
1487                         x11drv_atom(_ICC_PROFILE), 0, ~0UL, False, AnyPropertyType,
1488                         &type, &format, &count, &remaining, &profile );
1489     *size = get_property_size( format, count );
1490     if (format && count)
1491     {
1492         if ((ret = HeapAlloc( GetProcessHeap(), 0, *size ))) memcpy( ret, profile, *size );
1493         XFree( profile );
1494     }
1495     wine_tsx11_unlock();
1496     return ret;
1497 }
1498
1499 typedef struct
1500 {
1501     unsigned int unknown[6];
1502     unsigned int state[5];
1503     unsigned int count[2];
1504     unsigned char buffer[64];
1505 } sha_ctx;
1506
1507 extern void WINAPI A_SHAInit( sha_ctx * );
1508 extern void WINAPI A_SHAUpdate( sha_ctx *, const unsigned char *, unsigned int );
1509 extern void WINAPI A_SHAFinal( sha_ctx *, unsigned char * );
1510
1511 static const WCHAR mntr_key[] =
1512     {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
1513      'W','i','n','d','o','w','s',' ','N','T','\\','C','u','r','r','e','n','t',
1514      'V','e','r','s','i','o','n','\\','I','C','M','\\','m','n','t','r',0};
1515
1516 static const WCHAR color_path[] =
1517     {'\\','s','p','o','o','l','\\','d','r','i','v','e','r','s','\\','c','o','l','o','r','\\',0};
1518
1519 /***********************************************************************
1520  *              GetICMProfile (X11DRV.@)
1521  */
1522 BOOL CDECL X11DRV_GetICMProfile( X11DRV_PDEVICE *physDev, LPDWORD size, LPWSTR filename )
1523 {
1524     static const WCHAR srgb[] =
1525         {'s','R','G','B',' ','C','o','l','o','r',' ','S','p','a','c','e',' ',
1526          'P','r','o','f','i','l','e','.','i','c','m',0};
1527     HKEY hkey;
1528     DWORD required, len;
1529     WCHAR profile[MAX_PATH], fullname[2*MAX_PATH + sizeof(color_path)/sizeof(WCHAR)];
1530     unsigned char *buffer;
1531     unsigned long buflen;
1532
1533     if (!size) return FALSE;
1534
1535     GetSystemDirectoryW( fullname, MAX_PATH );
1536     strcatW( fullname, color_path );
1537
1538     len = sizeof(profile)/sizeof(WCHAR);
1539     if (!RegCreateKeyExW( HKEY_LOCAL_MACHINE, mntr_key, 0, NULL, 0, KEY_ALL_ACCESS, NULL, &hkey, NULL ) &&
1540         !RegEnumValueW( hkey, 0, profile, &len, NULL, NULL, NULL, NULL )) /* FIXME handle multiple values */
1541     {
1542         strcatW( fullname, profile );
1543         RegCloseKey( hkey );
1544     }
1545     else if ((buffer = get_icm_profile( &buflen )))
1546     {
1547         static const WCHAR fmt[] = {'%','0','2','x',0};
1548         static const WCHAR icm[] = {'.','i','c','m',0};
1549
1550         unsigned char sha1sum[20];
1551         unsigned int i;
1552         sha_ctx ctx;
1553         HANDLE file;
1554
1555         A_SHAInit( &ctx );
1556         A_SHAUpdate( &ctx, buffer, buflen );
1557         A_SHAFinal( &ctx, sha1sum );
1558
1559         for (i = 0; i < sizeof(sha1sum); i++) sprintfW( &profile[i * 2], fmt, sha1sum[i] );
1560         memcpy( &profile[i * 2], icm, sizeof(icm) );
1561
1562         strcatW( fullname, profile );
1563         file = CreateFileW( fullname, GENERIC_WRITE, 0, NULL, CREATE_NEW, 0, 0 );
1564         if (file != INVALID_HANDLE_VALUE)
1565         {
1566             DWORD written;
1567
1568             if (!WriteFile( file, buffer, buflen, &written, NULL ) || written != buflen)
1569                 ERR( "Unable to write color profile\n" );
1570             CloseHandle( file );
1571         }
1572         HeapFree( GetProcessHeap(), 0, buffer );
1573     }
1574     else strcatW( fullname, srgb );
1575
1576     required = strlenW( fullname ) + 1;
1577     if (*size < required)
1578     {
1579         *size = required;
1580         SetLastError( ERROR_INSUFFICIENT_BUFFER );
1581         return FALSE;
1582     }
1583     if (filename)
1584     {
1585         strcpyW( filename, fullname );
1586         if (GetFileAttributesW( filename ) == INVALID_FILE_ATTRIBUTES)
1587             WARN( "color profile not found\n" );
1588     }
1589     *size = required;
1590     return TRUE;
1591 }
1592
1593 /***********************************************************************
1594  *              EnumICMProfiles (X11DRV.@)
1595  */
1596 INT CDECL X11DRV_EnumICMProfiles( X11DRV_PDEVICE *physDev, ICMENUMPROCW proc, LPARAM lparam )
1597 {
1598     HKEY hkey;
1599     DWORD len_sysdir, len_path, len, index = 0;
1600     WCHAR sysdir[MAX_PATH], *profile;
1601     LONG res;
1602     INT ret;
1603
1604     TRACE("%p, %p, %ld\n", physDev, proc, lparam);
1605
1606     if (RegOpenKeyExW( HKEY_LOCAL_MACHINE, mntr_key, 0, KEY_ALL_ACCESS, &hkey ))
1607         return -1;
1608
1609     len_sysdir = GetSystemDirectoryW( sysdir, MAX_PATH );
1610     len_path = len_sysdir + sizeof(color_path) / sizeof(color_path[0]) - 1;
1611     len = 64;
1612     for (;;)
1613     {
1614         if (!(profile = HeapAlloc( GetProcessHeap(), 0, (len_path + len) * sizeof(WCHAR) )))
1615         {
1616             RegCloseKey( hkey );
1617             return -1;
1618         }
1619         res = RegEnumValueW( hkey, index, profile + len_path, &len, NULL, NULL, NULL, NULL );
1620         while (res == ERROR_MORE_DATA)
1621         {
1622             len *= 2;
1623             HeapFree( GetProcessHeap(), 0, profile );
1624             if (!(profile = HeapAlloc( GetProcessHeap(), 0, (len_path + len) * sizeof(WCHAR) )))
1625             {
1626                 RegCloseKey( hkey );
1627                 return -1;
1628             }
1629             res = RegEnumValueW( hkey, index, profile + len_path, &len, NULL, NULL, NULL, NULL );
1630         }
1631         if (res != ERROR_SUCCESS)
1632         {
1633             HeapFree( GetProcessHeap(), 0, profile );
1634             break;
1635         }
1636         memcpy( profile, sysdir, len_sysdir * sizeof(WCHAR) );
1637         memcpy( profile + len_sysdir, color_path, sizeof(color_path) - sizeof(WCHAR) );
1638         ret = proc( profile, lparam );
1639         HeapFree( GetProcessHeap(), 0, profile );
1640         if (!ret) break;
1641         index++;
1642     }
1643     RegCloseKey( hkey );
1644     return -1;
1645 }