winex11: Remove X11 locking around simple X calls.
[wine.git] / dlls / winex11.drv / graphics.c
blob3b2358c4c3373ebe79894457c641f058f4eb455e
1 /*
2 * X11 graphics driver graphics functions
4 * Copyright 1993,1994 Alexandre Julliard
5 * Copyright 1998 Huw Davies
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.
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.
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
23 * FIXME: only some of these functions obey the GM_ADVANCED
24 * graphics mode
27 #include "config.h"
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>
41 #include "windef.h"
42 #include "winbase.h"
43 #include "winreg.h"
45 #include "x11drv.h"
46 #include "wine/debug.h"
47 #include "wine/unicode.h"
49 WINE_DEFAULT_DEBUG_CHANNEL(graphics);
51 #define ABS(x) ((x)<0?(-(x)):(x))
53 /* ROP code to GC function conversion */
54 const int X11DRV_XROPfunction[16] =
56 GXclear, /* R2_BLACK */
57 GXnor, /* R2_NOTMERGEPEN */
58 GXandInverted, /* R2_MASKNOTPEN */
59 GXcopyInverted, /* R2_NOTCOPYPEN */
60 GXandReverse, /* R2_MASKPENNOT */
61 GXinvert, /* R2_NOT */
62 GXxor, /* R2_XORPEN */
63 GXnand, /* R2_NOTMASKPEN */
64 GXand, /* R2_MASKPEN */
65 GXequiv, /* R2_NOTXORPEN */
66 GXnoop, /* R2_NOP */
67 GXorInverted, /* R2_MERGENOTPEN */
68 GXcopy, /* R2_COPYPEN */
69 GXorReverse, /* R2_MERGEPENNOT */
70 GXor, /* R2_MERGEPEN */
71 GXset /* R2_WHITE */
75 /* get the rectangle in device coordinates, with optional mirroring */
76 static RECT get_device_rect( HDC hdc, int left, int top, int right, int bottom )
78 RECT rect;
80 rect.left = left;
81 rect.top = top;
82 rect.right = right;
83 rect.bottom = bottom;
84 if (GetLayout( hdc ) & LAYOUT_RTL)
86 /* shift the rectangle so that the right border is included after mirroring */
87 /* it would be more correct to do this after LPtoDP but that's not what Windows does */
88 rect.left--;
89 rect.right--;
91 LPtoDP( hdc, (POINT *)&rect, 2 );
92 if (rect.left > rect.right)
94 int tmp = rect.left;
95 rect.left = rect.right;
96 rect.right = tmp;
98 if (rect.top > rect.bottom)
100 int tmp = rect.top;
101 rect.top = rect.bottom;
102 rect.bottom = tmp;
104 return rect;
107 static void add_pen_device_bounds( X11DRV_PDEVICE *dev, const POINT *points, int count )
109 RECT bounds, rect;
110 int width = 0;
112 if (!dev->bounds) return;
113 reset_bounds( &bounds );
115 if (dev->pen.type & PS_GEOMETRIC || dev->pen.width > 1)
117 /* Windows uses some heuristics to estimate the distance from the point that will be painted */
118 width = dev->pen.width + 2;
119 if (dev->pen.linejoin == PS_JOIN_MITER)
121 width *= 5;
122 if (dev->pen.endcap == PS_ENDCAP_SQUARE) width = (width * 3 + 1) / 2;
124 else
126 if (dev->pen.endcap == PS_ENDCAP_SQUARE) width -= width / 4;
127 else width = (width + 1) / 2;
131 while (count-- > 0)
133 rect.left = points->x - width;
134 rect.top = points->y - width;
135 rect.right = points->x + width + 1;
136 rect.bottom = points->y + width + 1;
137 add_bounds_rect( &bounds, &rect );
138 points++;
141 add_device_bounds( dev, &bounds );
144 /***********************************************************************
145 * X11DRV_GetRegionData
147 * Calls GetRegionData on the given region and converts the rectangle
148 * array to XRectangle format. The returned buffer must be freed by
149 * caller using HeapFree(GetProcessHeap(),...).
150 * If hdc_lptodp is not 0, the rectangles are converted through LPtoDP.
152 RGNDATA *X11DRV_GetRegionData( HRGN hrgn, HDC hdc_lptodp )
154 RGNDATA *data;
155 DWORD size;
156 unsigned int i;
157 RECT *rect, tmp;
158 XRectangle *xrect;
160 if (!(size = GetRegionData( hrgn, 0, NULL ))) return NULL;
161 if (sizeof(XRectangle) > sizeof(RECT))
163 /* add extra size for XRectangle array */
164 int count = (size - sizeof(RGNDATAHEADER)) / sizeof(RECT);
165 size += count * (sizeof(XRectangle) - sizeof(RECT));
167 if (!(data = HeapAlloc( GetProcessHeap(), 0, size ))) return NULL;
168 if (!GetRegionData( hrgn, size, data ))
170 HeapFree( GetProcessHeap(), 0, data );
171 return NULL;
174 rect = (RECT *)data->Buffer;
175 xrect = (XRectangle *)data->Buffer;
176 if (hdc_lptodp) /* map to device coordinates */
178 LPtoDP( hdc_lptodp, (POINT *)rect, data->rdh.nCount * 2 );
179 for (i = 0; i < data->rdh.nCount; i++)
181 if (rect[i].right < rect[i].left)
183 INT tmp = rect[i].right;
184 rect[i].right = rect[i].left;
185 rect[i].left = tmp;
187 if (rect[i].bottom < rect[i].top)
189 INT tmp = rect[i].bottom;
190 rect[i].bottom = rect[i].top;
191 rect[i].top = tmp;
196 if (sizeof(XRectangle) > sizeof(RECT))
198 int j;
199 /* need to start from the end */
200 xrect += data->rdh.nCount;
201 for (j = data->rdh.nCount-1; j >= 0; j--)
203 tmp = rect[j];
204 if (tmp.left > SHRT_MAX) continue;
205 if (tmp.top > SHRT_MAX) continue;
206 if (tmp.right < SHRT_MIN) continue;
207 if (tmp.bottom < SHRT_MIN) continue;
208 xrect--;
209 xrect->x = max( min( tmp.left, SHRT_MAX), SHRT_MIN);
210 xrect->y = max( min( tmp.top, SHRT_MAX), SHRT_MIN);
211 xrect->width = max( min( tmp.right, SHRT_MAX ) - xrect->x, 0);
212 xrect->height = max( min( tmp.bottom, SHRT_MAX ) - xrect->y, 0);
214 if (xrect > (XRectangle *)data->Buffer)
216 data->rdh.nCount -= xrect - (XRectangle *)data->Buffer;
217 memmove( (XRectangle *)data->Buffer, xrect, data->rdh.nCount * sizeof(*xrect) );
220 else
222 for (i = 0; i < data->rdh.nCount; i++)
224 tmp = rect[i];
225 if (tmp.left > SHRT_MAX) continue;
226 if (tmp.top > SHRT_MAX) continue;
227 if (tmp.right < SHRT_MIN) continue;
228 if (tmp.bottom < SHRT_MIN) continue;
229 xrect->x = max( min( tmp.left, SHRT_MAX), SHRT_MIN);
230 xrect->y = max( min( tmp.top, SHRT_MAX), SHRT_MIN);
231 xrect->width = max( min( tmp.right, SHRT_MAX ) - xrect->x, 0);
232 xrect->height = max( min( tmp.bottom, SHRT_MAX ) - xrect->y, 0);
233 xrect++;
235 data->rdh.nCount = xrect - (XRectangle *)data->Buffer;
237 return data;
241 /***********************************************************************
242 * update_x11_clipping
244 static void update_x11_clipping( X11DRV_PDEVICE *physDev, HRGN rgn )
246 RGNDATA *data;
248 if (!rgn)
250 XSetClipMask( gdi_display, physDev->gc, None );
252 else if ((data = X11DRV_GetRegionData( rgn, 0 )))
254 XSetClipRectangles( gdi_display, physDev->gc, physDev->dc_rect.left, physDev->dc_rect.top,
255 (XRectangle *)data->Buffer, data->rdh.nCount, YXBanded );
256 HeapFree( GetProcessHeap(), 0, data );
261 /***********************************************************************
262 * add_extra_clipping_region
264 * Temporarily add a region to the current clipping region.
265 * The region must be restored with restore_clipping_region.
267 BOOL add_extra_clipping_region( X11DRV_PDEVICE *dev, HRGN rgn )
269 HRGN clip;
271 if (!rgn) return FALSE;
272 if (dev->region)
274 if (!(clip = CreateRectRgn( 0, 0, 0, 0 ))) return FALSE;
275 CombineRgn( clip, dev->region, rgn, RGN_AND );
276 update_x11_clipping( dev, clip );
277 DeleteObject( clip );
279 else update_x11_clipping( dev, rgn );
280 return TRUE;
284 /***********************************************************************
285 * restore_clipping_region
287 void restore_clipping_region( X11DRV_PDEVICE *dev )
289 update_x11_clipping( dev, dev->region );
293 /***********************************************************************
294 * X11DRV_SetDeviceClipping
296 void X11DRV_SetDeviceClipping( PHYSDEV dev, HRGN rgn )
298 X11DRV_PDEVICE *physDev = get_x11drv_dev( dev );
300 physDev->region = rgn;
301 update_x11_clipping( physDev, rgn );
305 /***********************************************************************
306 * X11DRV_SetupGCForPatBlt
308 * Setup the GC for a PatBlt operation using current brush.
309 * If fMapColors is TRUE, X pixels are mapped to Windows colors.
310 * Return FALSE if brush is BS_NULL, TRUE otherwise.
312 BOOL X11DRV_SetupGCForPatBlt( X11DRV_PDEVICE *physDev, GC gc, BOOL fMapColors )
314 XGCValues val;
315 unsigned long mask;
316 Pixmap pixmap = 0;
317 POINT pt;
319 if (physDev->brush.style == BS_NULL) return FALSE;
320 if (physDev->brush.pixel == -1)
322 /* Special case used for monochrome pattern brushes.
323 * We need to swap foreground and background because
324 * Windows does it the wrong way...
326 val.foreground = X11DRV_PALETTE_ToPhysical( physDev, GetBkColor(physDev->dev.hdc) );
327 val.background = X11DRV_PALETTE_ToPhysical( physDev, GetTextColor(physDev->dev.hdc) );
329 else
331 val.foreground = physDev->brush.pixel;
332 val.background = X11DRV_PALETTE_ToPhysical( physDev, GetBkColor(physDev->dev.hdc) );
334 if (fMapColors && X11DRV_PALETTE_XPixelToPalette)
336 val.foreground = X11DRV_PALETTE_XPixelToPalette[val.foreground];
337 val.background = X11DRV_PALETTE_XPixelToPalette[val.background];
340 val.function = X11DRV_XROPfunction[GetROP2(physDev->dev.hdc)-1];
342 ** Let's replace GXinvert by GXxor with (black xor white)
343 ** This solves the selection color and leak problems in excel
344 ** FIXME : Let's do that only if we work with X-pixels, not with Win-pixels
346 if (val.function == GXinvert)
348 val.foreground = (WhitePixel( gdi_display, DefaultScreen(gdi_display) ) ^
349 BlackPixel( gdi_display, DefaultScreen(gdi_display) ));
350 val.function = GXxor;
352 val.fill_style = physDev->brush.fillStyle;
353 switch(val.fill_style)
355 case FillStippled:
356 case FillOpaqueStippled:
357 if (GetBkMode(physDev->dev.hdc)==OPAQUE) val.fill_style = FillOpaqueStippled;
358 val.stipple = physDev->brush.pixmap;
359 mask = GCStipple;
360 break;
362 case FillTiled:
363 if (fMapColors && X11DRV_PALETTE_XPixelToPalette)
365 register int x, y;
366 XImage *image;
367 wine_tsx11_lock();
368 pixmap = XCreatePixmap( gdi_display, root_window, 8, 8, physDev->depth );
369 image = XGetImage( gdi_display, physDev->brush.pixmap, 0, 0, 8, 8,
370 AllPlanes, ZPixmap );
371 for (y = 0; y < 8; y++)
372 for (x = 0; x < 8; x++)
373 XPutPixel( image, x, y,
374 X11DRV_PALETTE_XPixelToPalette[XGetPixel( image, x, y)] );
375 XPutImage( gdi_display, pixmap, gc, image, 0, 0, 0, 0, 8, 8 );
376 XDestroyImage( image );
377 wine_tsx11_unlock();
378 val.tile = pixmap;
380 else val.tile = physDev->brush.pixmap;
381 mask = GCTile;
382 break;
384 default:
385 mask = 0;
386 break;
388 GetBrushOrgEx( physDev->dev.hdc, &pt );
389 val.ts_x_origin = physDev->dc_rect.left + pt.x;
390 val.ts_y_origin = physDev->dc_rect.top + pt.y;
391 val.fill_rule = (GetPolyFillMode(physDev->dev.hdc) == WINDING) ? WindingRule : EvenOddRule;
392 XChangeGC( gdi_display, gc,
393 GCFunction | GCForeground | GCBackground | GCFillStyle |
394 GCFillRule | GCTileStipXOrigin | GCTileStipYOrigin | mask,
395 &val );
396 if (pixmap) XFreePixmap( gdi_display, pixmap );
397 return TRUE;
401 /***********************************************************************
402 * X11DRV_SetupGCForBrush
404 * Setup physDev->gc for drawing operations using current brush.
405 * Return FALSE if brush is BS_NULL, TRUE otherwise.
407 BOOL X11DRV_SetupGCForBrush( X11DRV_PDEVICE *physDev )
409 return X11DRV_SetupGCForPatBlt( physDev, physDev->gc, FALSE );
413 /***********************************************************************
414 * X11DRV_SetupGCForPen
416 * Setup physDev->gc for drawing operations using current pen.
417 * Return FALSE if pen is PS_NULL, TRUE otherwise.
419 static BOOL X11DRV_SetupGCForPen( X11DRV_PDEVICE *physDev )
421 XGCValues val;
422 UINT rop2 = GetROP2(physDev->dev.hdc);
424 if (physDev->pen.style == PS_NULL) return FALSE;
426 switch (rop2)
428 case R2_BLACK :
429 val.foreground = BlackPixel( gdi_display, DefaultScreen(gdi_display) );
430 val.function = GXcopy;
431 break;
432 case R2_WHITE :
433 val.foreground = WhitePixel( gdi_display, DefaultScreen(gdi_display) );
434 val.function = GXcopy;
435 break;
436 case R2_XORPEN :
437 val.foreground = physDev->pen.pixel;
438 /* It is very unlikely someone wants to XOR with 0 */
439 /* This fixes the rubber-drawings in paintbrush */
440 if (val.foreground == 0)
441 val.foreground = (WhitePixel( gdi_display, DefaultScreen(gdi_display) ) ^
442 BlackPixel( gdi_display, DefaultScreen(gdi_display) ));
443 val.function = GXxor;
444 break;
445 default :
446 val.foreground = physDev->pen.pixel;
447 val.function = X11DRV_XROPfunction[rop2-1];
449 val.background = X11DRV_PALETTE_ToPhysical( physDev, GetBkColor(physDev->dev.hdc) );
450 val.fill_style = FillSolid;
451 val.line_width = physDev->pen.width;
452 if (val.line_width <= 1) {
453 val.cap_style = CapNotLast;
454 } else {
455 switch (physDev->pen.endcap)
457 case PS_ENDCAP_SQUARE:
458 val.cap_style = CapProjecting;
459 break;
460 case PS_ENDCAP_FLAT:
461 val.cap_style = CapButt;
462 break;
463 case PS_ENDCAP_ROUND:
464 default:
465 val.cap_style = CapRound;
468 switch (physDev->pen.linejoin)
470 case PS_JOIN_BEVEL:
471 val.join_style = JoinBevel;
472 break;
473 case PS_JOIN_MITER:
474 val.join_style = JoinMiter;
475 break;
476 case PS_JOIN_ROUND:
477 default:
478 val.join_style = JoinRound;
481 if (physDev->pen.dash_len)
482 val.line_style = ((GetBkMode(physDev->dev.hdc) == OPAQUE) && (!physDev->pen.ext))
483 ? LineDoubleDash : LineOnOffDash;
484 else
485 val.line_style = LineSolid;
487 if (physDev->pen.dash_len)
488 XSetDashes( gdi_display, physDev->gc, 0, physDev->pen.dashes, physDev->pen.dash_len );
489 XChangeGC( gdi_display, physDev->gc,
490 GCFunction | GCForeground | GCBackground | GCLineWidth |
491 GCLineStyle | GCCapStyle | GCJoinStyle | GCFillStyle, &val );
492 return TRUE;
496 /***********************************************************************
497 * X11DRV_XWStoDS
499 * Performs a world-to-viewport transformation on the specified width.
501 INT X11DRV_XWStoDS( HDC hdc, INT width )
503 POINT pt[2];
505 pt[0].x = 0;
506 pt[0].y = 0;
507 pt[1].x = width;
508 pt[1].y = 0;
509 LPtoDP( hdc, pt, 2 );
510 return pt[1].x - pt[0].x;
513 /***********************************************************************
514 * X11DRV_YWStoDS
516 * Performs a world-to-viewport transformation on the specified height.
518 INT X11DRV_YWStoDS( HDC hdc, INT height )
520 POINT pt[2];
522 pt[0].x = 0;
523 pt[0].y = 0;
524 pt[1].x = 0;
525 pt[1].y = height;
526 LPtoDP( hdc, pt, 2 );
527 return pt[1].y - pt[0].y;
530 /***********************************************************************
531 * X11DRV_LineTo
533 BOOL X11DRV_LineTo( PHYSDEV dev, INT x, INT y )
535 X11DRV_PDEVICE *physDev = get_x11drv_dev( dev );
536 POINT pt[2];
538 GetCurrentPositionEx( dev->hdc, &pt[0] );
539 pt[1].x = x;
540 pt[1].y = y;
541 LPtoDP( dev->hdc, pt, 2 );
542 add_pen_device_bounds( physDev, pt, 2 );
544 if (X11DRV_SetupGCForPen( physDev ))
545 XDrawLine(gdi_display, physDev->drawable, physDev->gc,
546 physDev->dc_rect.left + pt[0].x, physDev->dc_rect.top + pt[0].y,
547 physDev->dc_rect.left + pt[1].x, physDev->dc_rect.top + pt[1].y );
548 return TRUE;
553 /***********************************************************************
554 * X11DRV_DrawArc
556 * Helper functions for Arc(), Chord() and Pie().
557 * 'lines' is the number of lines to draw: 0 for Arc, 1 for Chord, 2 for Pie.
560 static BOOL X11DRV_DrawArc( PHYSDEV dev, INT left, INT top, INT right, INT bottom,
561 INT xstart, INT ystart, INT xend, INT yend, INT lines )
563 X11DRV_PDEVICE *physDev = get_x11drv_dev( dev );
564 INT xcenter, ycenter, istart_angle, idiff_angle;
565 INT width, oldwidth;
566 double start_angle, end_angle;
567 XPoint points[4];
568 POINT start, end;
569 RECT rc = get_device_rect( dev->hdc, left, top, right, bottom );
571 start.x = xstart;
572 start.y = ystart;
573 end.x = xend;
574 end.y = yend;
575 LPtoDP(dev->hdc, &start, 1);
576 LPtoDP(dev->hdc, &end, 1);
578 if ((rc.left == rc.right) || (rc.top == rc.bottom)
579 ||(lines && ((rc.right-rc.left==1)||(rc.bottom-rc.top==1)))) return TRUE;
581 if (GetArcDirection( dev->hdc ) == AD_CLOCKWISE)
582 { POINT tmp = start; start = end; end = tmp; }
584 oldwidth = width = physDev->pen.width;
585 if (!width) width = 1;
586 if(physDev->pen.style == PS_NULL) width = 0;
588 if (physDev->pen.style == PS_INSIDEFRAME)
590 if (2*width > (rc.right-rc.left)) width=(rc.right-rc.left + 1)/2;
591 if (2*width > (rc.bottom-rc.top)) width=(rc.bottom-rc.top + 1)/2;
592 rc.left += width / 2;
593 rc.right -= (width - 1) / 2;
594 rc.top += width / 2;
595 rc.bottom -= (width - 1) / 2;
597 if(width == 0) width = 1; /* more accurate */
598 physDev->pen.width = width;
600 xcenter = (rc.right + rc.left) / 2;
601 ycenter = (rc.bottom + rc.top) / 2;
602 start_angle = atan2( (double)(ycenter-start.y)*(rc.right-rc.left),
603 (double)(start.x-xcenter)*(rc.bottom-rc.top) );
604 end_angle = atan2( (double)(ycenter-end.y)*(rc.right-rc.left),
605 (double)(end.x-xcenter)*(rc.bottom-rc.top) );
606 if ((start.x==end.x)&&(start.y==end.y))
607 { /* A lazy program delivers xstart=xend=ystart=yend=0) */
608 start_angle = 0;
609 end_angle = 2* PI;
611 else /* notorious cases */
612 if ((start_angle == PI)&&( end_angle <0))
613 start_angle = - PI;
614 else
615 if ((end_angle == PI)&&( start_angle <0))
616 end_angle = - PI;
617 istart_angle = (INT)(start_angle * 180 * 64 / PI + 0.5);
618 idiff_angle = (INT)((end_angle - start_angle) * 180 * 64 / PI + 0.5);
619 if (idiff_angle <= 0) idiff_angle += 360 * 64;
621 /* Fill arc with brush if Chord() or Pie() */
623 if ((lines > 0) && X11DRV_SetupGCForBrush( physDev )) {
624 XSetArcMode( gdi_display, physDev->gc, (lines==1) ? ArcChord : ArcPieSlice);
625 XFillArc( gdi_display, physDev->drawable, physDev->gc,
626 physDev->dc_rect.left + rc.left, physDev->dc_rect.top + rc.top,
627 rc.right-rc.left-1, rc.bottom-rc.top-1, istart_angle, idiff_angle );
630 /* Draw arc and lines */
632 if (X11DRV_SetupGCForPen( physDev ))
634 wine_tsx11_lock();
635 XDrawArc( gdi_display, physDev->drawable, physDev->gc,
636 physDev->dc_rect.left + rc.left, physDev->dc_rect.top + rc.top,
637 rc.right-rc.left-1, rc.bottom-rc.top-1, istart_angle, idiff_angle );
638 if (lines) {
639 /* use the truncated values */
640 start_angle=(double)istart_angle*PI/64./180.;
641 end_angle=(double)(istart_angle+idiff_angle)*PI/64./180.;
642 /* calculate the endpoints and round correctly */
643 points[0].x = (int) floor(physDev->dc_rect.left + (rc.right+rc.left)/2.0 +
644 cos(start_angle) * (rc.right-rc.left-width*2+2) / 2. + 0.5);
645 points[0].y = (int) floor(physDev->dc_rect.top + (rc.top+rc.bottom)/2.0 -
646 sin(start_angle) * (rc.bottom-rc.top-width*2+2) / 2. + 0.5);
647 points[1].x = (int) floor(physDev->dc_rect.left + (rc.right+rc.left)/2.0 +
648 cos(end_angle) * (rc.right-rc.left-width*2+2) / 2. + 0.5);
649 points[1].y = (int) floor(physDev->dc_rect.top + (rc.top+rc.bottom)/2.0 -
650 sin(end_angle) * (rc.bottom-rc.top-width*2+2) / 2. + 0.5);
652 /* OK, this stuff is optimized for Xfree86
653 * which is probably the server most used by
654 * wine users. Other X servers will not
655 * display correctly. (eXceed for instance)
656 * so if you feel you must make changes, make sure that
657 * you either use Xfree86 or separate your changes
658 * from these (compile switch or whatever)
660 if (lines == 2) {
661 INT dx1,dy1;
662 points[3] = points[1];
663 points[1].x = physDev->dc_rect.left + xcenter;
664 points[1].y = physDev->dc_rect.top + ycenter;
665 points[2] = points[1];
666 dx1=points[1].x-points[0].x;
667 dy1=points[1].y-points[0].y;
668 if(((rc.top-rc.bottom) | -2) == -2)
669 if(dy1>0) points[1].y--;
670 if(dx1<0) {
671 if (((-dx1)*64)<=ABS(dy1)*37) points[0].x--;
672 if(((-dx1*9))<(dy1*16)) points[0].y--;
673 if( dy1<0 && ((dx1*9)) < (dy1*16)) points[0].y--;
674 } else {
675 if(dy1 < 0) points[0].y--;
676 if(((rc.right-rc.left) | -2) == -2) points[1].x--;
678 dx1=points[3].x-points[2].x;
679 dy1=points[3].y-points[2].y;
680 if(((rc.top-rc.bottom) | -2 ) == -2)
681 if(dy1 < 0) points[2].y--;
682 if( dx1<0){
683 if( dy1>0) points[3].y--;
684 if(((rc.right-rc.left) | -2) == -2 ) points[2].x--;
685 }else {
686 points[3].y--;
687 if( dx1 * 64 < dy1 * -37 ) points[3].x--;
689 lines++;
691 XDrawLines( gdi_display, physDev->drawable, physDev->gc,
692 points, lines+1, CoordModeOrigin );
694 wine_tsx11_unlock();
697 physDev->pen.width = oldwidth;
698 add_pen_device_bounds( physDev, (POINT *)&rc, 2 );
699 return TRUE;
703 /***********************************************************************
704 * X11DRV_Arc
706 BOOL X11DRV_Arc( PHYSDEV dev, INT left, INT top, INT right, INT bottom,
707 INT xstart, INT ystart, INT xend, INT yend )
709 return X11DRV_DrawArc( dev, left, top, right, bottom, xstart, ystart, xend, yend, 0 );
713 /***********************************************************************
714 * X11DRV_Pie
716 BOOL X11DRV_Pie( PHYSDEV dev, INT left, INT top, INT right, INT bottom,
717 INT xstart, INT ystart, INT xend, INT yend )
719 return X11DRV_DrawArc( dev, left, top, right, bottom, xstart, ystart, xend, yend, 2 );
722 /***********************************************************************
723 * X11DRV_Chord
725 BOOL X11DRV_Chord( PHYSDEV dev, INT left, INT top, INT right, INT bottom,
726 INT xstart, INT ystart, INT xend, INT yend )
728 return X11DRV_DrawArc( dev, left, top, right, bottom, xstart, ystart, xend, yend, 1 );
732 /***********************************************************************
733 * X11DRV_Ellipse
735 BOOL X11DRV_Ellipse( PHYSDEV dev, INT left, INT top, INT right, INT bottom )
737 X11DRV_PDEVICE *physDev = get_x11drv_dev( dev );
738 INT width, oldwidth;
739 RECT rc = get_device_rect( dev->hdc, left, top, right, bottom );
741 if ((rc.left == rc.right) || (rc.top == rc.bottom)) return TRUE;
743 oldwidth = width = physDev->pen.width;
744 if (!width) width = 1;
745 if(physDev->pen.style == PS_NULL) width = 0;
747 if (physDev->pen.style == PS_INSIDEFRAME)
749 if (2*width > (rc.right-rc.left)) width=(rc.right-rc.left + 1)/2;
750 if (2*width > (rc.bottom-rc.top)) width=(rc.bottom-rc.top + 1)/2;
751 rc.left += width / 2;
752 rc.right -= (width - 1) / 2;
753 rc.top += width / 2;
754 rc.bottom -= (width - 1) / 2;
756 if(width == 0) width = 1; /* more accurate */
757 physDev->pen.width = width;
759 if (X11DRV_SetupGCForBrush( physDev ))
760 XFillArc( gdi_display, physDev->drawable, physDev->gc,
761 physDev->dc_rect.left + rc.left, physDev->dc_rect.top + rc.top,
762 rc.right-rc.left-1, rc.bottom-rc.top-1, 0, 360*64 );
764 if (X11DRV_SetupGCForPen( physDev ))
765 XDrawArc( gdi_display, physDev->drawable, physDev->gc,
766 physDev->dc_rect.left + rc.left, physDev->dc_rect.top + rc.top,
767 rc.right-rc.left-1, rc.bottom-rc.top-1, 0, 360*64 );
769 physDev->pen.width = oldwidth;
770 add_pen_device_bounds( physDev, (POINT *)&rc, 2 );
771 return TRUE;
775 /***********************************************************************
776 * X11DRV_Rectangle
778 BOOL X11DRV_Rectangle(PHYSDEV dev, INT left, INT top, INT right, INT bottom)
780 X11DRV_PDEVICE *physDev = get_x11drv_dev( dev );
781 INT width, oldwidth, oldjoinstyle;
782 RECT rc = get_device_rect( dev->hdc, left, top, right, bottom );
784 TRACE("(%d %d %d %d)\n", left, top, right, bottom);
786 if ((rc.left == rc.right) || (rc.top == rc.bottom)) return TRUE;
788 oldwidth = width = physDev->pen.width;
789 if (!width) width = 1;
790 if(physDev->pen.style == PS_NULL) width = 0;
792 if (physDev->pen.style == PS_INSIDEFRAME)
794 if (2*width > (rc.right-rc.left)) width=(rc.right-rc.left + 1)/2;
795 if (2*width > (rc.bottom-rc.top)) width=(rc.bottom-rc.top + 1)/2;
796 rc.left += width / 2;
797 rc.right -= (width - 1) / 2;
798 rc.top += width / 2;
799 rc.bottom -= (width - 1) / 2;
801 if(width == 1) width = 0;
802 physDev->pen.width = width;
803 oldjoinstyle = physDev->pen.linejoin;
804 if(physDev->pen.type != PS_GEOMETRIC)
805 physDev->pen.linejoin = PS_JOIN_MITER;
807 rc.right--;
808 rc.bottom--;
809 if ((rc.right >= rc.left + width) && (rc.bottom >= rc.top + width))
811 if (X11DRV_SetupGCForBrush( physDev ))
812 XFillRectangle( gdi_display, physDev->drawable, physDev->gc,
813 physDev->dc_rect.left + rc.left + (width + 1) / 2,
814 physDev->dc_rect.top + rc.top + (width + 1) / 2,
815 rc.right-rc.left-width, rc.bottom-rc.top-width);
817 if (X11DRV_SetupGCForPen( physDev ))
818 XDrawRectangle( gdi_display, physDev->drawable, physDev->gc,
819 physDev->dc_rect.left + rc.left, physDev->dc_rect.top + rc.top,
820 rc.right-rc.left, rc.bottom-rc.top );
822 physDev->pen.width = oldwidth;
823 physDev->pen.linejoin = oldjoinstyle;
824 add_pen_device_bounds( physDev, (POINT *)&rc, 2 );
825 return TRUE;
828 /***********************************************************************
829 * X11DRV_RoundRect
831 BOOL X11DRV_RoundRect( PHYSDEV dev, INT left, INT top, INT right, INT bottom,
832 INT ell_width, INT ell_height )
834 X11DRV_PDEVICE *physDev = get_x11drv_dev( dev );
835 INT width, oldwidth, oldendcap;
836 POINT pts[2];
837 RECT rc = get_device_rect( dev->hdc, left, top, right, bottom );
839 TRACE("(%d %d %d %d %d %d\n",
840 left, top, right, bottom, ell_width, ell_height);
842 if ((rc.left == rc.right) || (rc.top == rc.bottom))
843 return TRUE;
845 /* Make sure ell_width and ell_height are >= 1 otherwise XDrawArc gets
846 called with width/height < 0 */
847 pts[0].x = pts[0].y = 0;
848 pts[1].x = ell_width;
849 pts[1].y = ell_height;
850 LPtoDP(dev->hdc, pts, 2);
851 ell_width = max(abs( pts[1].x - pts[0].x ), 1);
852 ell_height = max(abs( pts[1].y - pts[0].y ), 1);
854 oldwidth = width = physDev->pen.width;
855 oldendcap = physDev->pen.endcap;
856 if (!width) width = 1;
857 if(physDev->pen.style == PS_NULL) width = 0;
859 if (physDev->pen.style == PS_INSIDEFRAME)
861 if (2*width > (rc.right-rc.left)) width=(rc.right-rc.left + 1)/2;
862 if (2*width > (rc.bottom-rc.top)) width=(rc.bottom-rc.top + 1)/2;
863 rc.left += width / 2;
864 rc.right -= (width - 1) / 2;
865 rc.top += width / 2;
866 rc.bottom -= (width - 1) / 2;
868 if(width == 0) width = 1;
869 physDev->pen.width = width;
870 physDev->pen.endcap = PS_ENDCAP_SQUARE;
872 if (X11DRV_SetupGCForBrush( physDev ))
874 wine_tsx11_lock();
875 if (ell_width > (rc.right-rc.left) )
876 if (ell_height > (rc.bottom-rc.top) )
877 XFillArc( gdi_display, physDev->drawable, physDev->gc,
878 physDev->dc_rect.left + rc.left, physDev->dc_rect.top + rc.top,
879 rc.right - rc.left - 1, rc.bottom - rc.top - 1,
880 0, 360 * 64 );
881 else{
882 XFillArc( gdi_display, physDev->drawable, physDev->gc,
883 physDev->dc_rect.left + rc.left, physDev->dc_rect.top + rc.top,
884 rc.right - rc.left - 1, ell_height, 0, 180 * 64 );
885 XFillArc( gdi_display, physDev->drawable, physDev->gc,
886 physDev->dc_rect.left + rc.left,
887 physDev->dc_rect.top + rc.bottom - ell_height - 1,
888 rc.right - rc.left - 1, ell_height, 180 * 64,
889 180 * 64 );
891 else if (ell_height > (rc.bottom-rc.top) ){
892 XFillArc( gdi_display, physDev->drawable, physDev->gc,
893 physDev->dc_rect.left + rc.left, physDev->dc_rect.top + rc.top,
894 ell_width, rc.bottom - rc.top - 1, 90 * 64, 180 * 64 );
895 XFillArc( gdi_display, physDev->drawable, physDev->gc,
896 physDev->dc_rect.left + rc.right - ell_width - 1, physDev->dc_rect.top + rc.top,
897 ell_width, rc.bottom - rc.top - 1, 270 * 64, 180 * 64 );
898 }else{
899 XFillArc( gdi_display, physDev->drawable, physDev->gc,
900 physDev->dc_rect.left + rc.left, physDev->dc_rect.top + rc.top,
901 ell_width, ell_height, 90 * 64, 90 * 64 );
902 XFillArc( gdi_display, physDev->drawable, physDev->gc,
903 physDev->dc_rect.left + rc.left,
904 physDev->dc_rect.top + rc.bottom - ell_height - 1,
905 ell_width, ell_height, 180 * 64, 90 * 64 );
906 XFillArc( gdi_display, physDev->drawable, physDev->gc,
907 physDev->dc_rect.left + rc.right - ell_width - 1,
908 physDev->dc_rect.top + rc.bottom - ell_height - 1,
909 ell_width, ell_height, 270 * 64, 90 * 64 );
910 XFillArc( gdi_display, physDev->drawable, physDev->gc,
911 physDev->dc_rect.left + rc.right - ell_width - 1,
912 physDev->dc_rect.top + rc.top,
913 ell_width, ell_height, 0, 90 * 64 );
915 if (ell_width < rc.right - rc.left)
917 XFillRectangle( gdi_display, physDev->drawable, physDev->gc,
918 physDev->dc_rect.left + rc.left + (ell_width + 1) / 2,
919 physDev->dc_rect.top + rc.top + 1,
920 rc.right - rc.left - ell_width - 1,
921 (ell_height + 1) / 2 - 1);
922 XFillRectangle( gdi_display, physDev->drawable, physDev->gc,
923 physDev->dc_rect.left + rc.left + (ell_width + 1) / 2,
924 physDev->dc_rect.top + rc.bottom - (ell_height) / 2 - 1,
925 rc.right - rc.left - ell_width - 1,
926 (ell_height) / 2 );
928 if (ell_height < rc.bottom - rc.top)
930 XFillRectangle( gdi_display, physDev->drawable, physDev->gc,
931 physDev->dc_rect.left + rc.left + 1,
932 physDev->dc_rect.top + rc.top + (ell_height + 1) / 2,
933 rc.right - rc.left - 2,
934 rc.bottom - rc.top - ell_height - 1);
936 wine_tsx11_unlock();
938 /* FIXME: this could be done with on X call
939 * more efficient and probably more correct
940 * on any X server: XDrawArcs will draw
941 * straight horizontal and vertical lines
942 * if width or height are zero.
944 * BTW this stuff is optimized for an Xfree86 server
945 * read the comments inside the X11DRV_DrawArc function
947 if (X11DRV_SetupGCForPen( physDev ))
949 wine_tsx11_lock();
950 if (ell_width > (rc.right-rc.left) )
951 if (ell_height > (rc.bottom-rc.top) )
952 XDrawArc( gdi_display, physDev->drawable, physDev->gc,
953 physDev->dc_rect.left + rc.left, physDev->dc_rect.top + rc.top,
954 rc.right - rc.left - 1, rc.bottom - rc.top - 1, 0 , 360 * 64 );
955 else{
956 XDrawArc( gdi_display, physDev->drawable, physDev->gc,
957 physDev->dc_rect.left + rc.left, physDev->dc_rect.top + rc.top,
958 rc.right - rc.left - 1, ell_height - 1, 0 , 180 * 64 );
959 XDrawArc( gdi_display, physDev->drawable, physDev->gc,
960 physDev->dc_rect.left + rc.left,
961 physDev->dc_rect.top + rc.bottom - ell_height,
962 rc.right - rc.left - 1, ell_height - 1, 180 * 64 , 180 * 64 );
964 else if (ell_height > (rc.bottom-rc.top) ){
965 XDrawArc( gdi_display, physDev->drawable, physDev->gc,
966 physDev->dc_rect.left + rc.left, physDev->dc_rect.top + rc.top,
967 ell_width - 1 , rc.bottom - rc.top - 1, 90 * 64 , 180 * 64 );
968 XDrawArc( gdi_display, physDev->drawable, physDev->gc,
969 physDev->dc_rect.left + rc.right - ell_width,
970 physDev->dc_rect.top + rc.top,
971 ell_width - 1 , rc.bottom - rc.top - 1, 270 * 64 , 180 * 64 );
972 }else{
973 XDrawArc( gdi_display, physDev->drawable, physDev->gc,
974 physDev->dc_rect.left + rc.left, physDev->dc_rect.top + rc.top,
975 ell_width - 1, ell_height - 1, 90 * 64, 90 * 64 );
976 XDrawArc( gdi_display, physDev->drawable, physDev->gc,
977 physDev->dc_rect.left + rc.left, physDev->dc_rect.top + rc.bottom - ell_height,
978 ell_width - 1, ell_height - 1, 180 * 64, 90 * 64 );
979 XDrawArc( gdi_display, physDev->drawable, physDev->gc,
980 physDev->dc_rect.left + rc.right - ell_width,
981 physDev->dc_rect.top + rc.bottom - ell_height,
982 ell_width - 1, ell_height - 1, 270 * 64, 90 * 64 );
983 XDrawArc( gdi_display, physDev->drawable, physDev->gc,
984 physDev->dc_rect.left + rc.right - ell_width, physDev->dc_rect.top + rc.top,
985 ell_width - 1, ell_height - 1, 0, 90 * 64 );
987 if (ell_width < rc.right - rc.left)
989 XDrawLine( gdi_display, physDev->drawable, physDev->gc,
990 physDev->dc_rect.left + rc.left + ell_width / 2,
991 physDev->dc_rect.top + rc.top,
992 physDev->dc_rect.left + rc.right - (ell_width+1) / 2,
993 physDev->dc_rect.top + rc.top);
994 XDrawLine( gdi_display, physDev->drawable, physDev->gc,
995 physDev->dc_rect.left + rc.left + ell_width / 2 ,
996 physDev->dc_rect.top + rc.bottom - 1,
997 physDev->dc_rect.left + rc.right - (ell_width+1)/ 2,
998 physDev->dc_rect.top + rc.bottom - 1);
1000 if (ell_height < rc.bottom - rc.top)
1002 XDrawLine( gdi_display, physDev->drawable, physDev->gc,
1003 physDev->dc_rect.left + rc.right - 1,
1004 physDev->dc_rect.top + rc.top + ell_height / 2,
1005 physDev->dc_rect.left + rc.right - 1,
1006 physDev->dc_rect.top + rc.bottom - (ell_height+1) / 2);
1007 XDrawLine( gdi_display, physDev->drawable, physDev->gc,
1008 physDev->dc_rect.left + rc.left,
1009 physDev->dc_rect.top + rc.top + ell_height / 2,
1010 physDev->dc_rect.left + rc.left,
1011 physDev->dc_rect.top + rc.bottom - (ell_height+1) / 2);
1013 wine_tsx11_unlock();
1016 physDev->pen.width = oldwidth;
1017 physDev->pen.endcap = oldendcap;
1018 add_pen_device_bounds( physDev, (POINT *)&rc, 2 );
1019 return TRUE;
1023 /***********************************************************************
1024 * X11DRV_SetPixel
1026 COLORREF X11DRV_SetPixel( PHYSDEV dev, INT x, INT y, COLORREF color )
1028 X11DRV_PDEVICE *physDev = get_x11drv_dev( dev );
1029 unsigned long pixel;
1030 POINT pt;
1031 RECT rect;
1033 pt.x = x;
1034 pt.y = y;
1035 LPtoDP( dev->hdc, &pt, 1 );
1036 pixel = X11DRV_PALETTE_ToPhysical( physDev, color );
1038 XSetForeground( gdi_display, physDev->gc, pixel );
1039 XSetFunction( gdi_display, physDev->gc, GXcopy );
1040 XDrawPoint( gdi_display, physDev->drawable, physDev->gc,
1041 physDev->dc_rect.left + pt.x, physDev->dc_rect.top + pt.y );
1043 SetRect( &rect, pt.x, pt.y, pt.x + 1, pt.y + 1 );
1044 add_device_bounds( physDev, &rect );
1045 return X11DRV_PALETTE_ToLogical(physDev, pixel);
1049 /***********************************************************************
1050 * X11DRV_PaintRgn
1052 BOOL X11DRV_PaintRgn( PHYSDEV dev, HRGN hrgn )
1054 X11DRV_PDEVICE *physDev = get_x11drv_dev( dev );
1055 RECT rc;
1057 if (X11DRV_SetupGCForBrush( physDev ))
1059 unsigned int i;
1060 XRectangle *rect;
1061 RGNDATA *data = X11DRV_GetRegionData( hrgn, dev->hdc );
1063 if (!data) return FALSE;
1064 rect = (XRectangle *)data->Buffer;
1065 for (i = 0; i < data->rdh.nCount; i++)
1067 rect[i].x += physDev->dc_rect.left;
1068 rect[i].y += physDev->dc_rect.top;
1071 XFillRectangles( gdi_display, physDev->drawable, physDev->gc, rect, data->rdh.nCount );
1072 HeapFree( GetProcessHeap(), 0, data );
1074 if (GetRgnBox( hrgn, &rc ))
1076 LPtoDP( dev->hdc, (POINT *)&rc, 2 );
1077 add_device_bounds( physDev, &rc );
1079 return TRUE;
1082 /**********************************************************************
1083 * X11DRV_Polygon
1085 BOOL X11DRV_Polygon( PHYSDEV dev, const POINT* pt, INT count )
1087 X11DRV_PDEVICE *physDev = get_x11drv_dev( dev );
1088 int i;
1089 POINT *points;
1090 XPoint *xpoints;
1092 points = HeapAlloc( GetProcessHeap(), 0, count * sizeof(*pt) );
1093 if (!points) return FALSE;
1094 memcpy( points, pt, count * sizeof(*pt) );
1095 LPtoDP( dev->hdc, points, count );
1096 add_pen_device_bounds( physDev, points, count );
1098 if (!(xpoints = HeapAlloc( GetProcessHeap(), 0, sizeof(XPoint) * (count+1) )))
1100 HeapFree( GetProcessHeap(), 0, points );
1101 return FALSE;
1103 for (i = 0; i < count; i++)
1105 xpoints[i].x = physDev->dc_rect.left + points[i].x;
1106 xpoints[i].y = physDev->dc_rect.top + points[i].y;
1108 xpoints[count] = xpoints[0];
1110 if (X11DRV_SetupGCForBrush( physDev ))
1111 XFillPolygon( gdi_display, physDev->drawable, physDev->gc,
1112 xpoints, count+1, Complex, CoordModeOrigin);
1114 if (X11DRV_SetupGCForPen ( physDev ))
1115 XDrawLines( gdi_display, physDev->drawable, physDev->gc,
1116 xpoints, count+1, CoordModeOrigin );
1118 HeapFree( GetProcessHeap(), 0, xpoints );
1119 HeapFree( GetProcessHeap(), 0, points );
1120 return TRUE;
1124 /**********************************************************************
1125 * X11DRV_PolyPolygon
1127 BOOL X11DRV_PolyPolygon( PHYSDEV dev, const POINT* pt, const INT* counts, UINT polygons )
1129 X11DRV_PDEVICE *physDev = get_x11drv_dev( dev );
1130 DWORD total = 0, max = 0, pos, i;
1131 POINT *points;
1132 BOOL ret = FALSE;
1134 for (i = 0; i < polygons; i++)
1136 if (counts[i] < 2) return FALSE;
1137 if (counts[i] > max) max = counts[i];
1138 total += counts[i];
1141 points = HeapAlloc( GetProcessHeap(), 0, total * sizeof(*pt) );
1142 if (!points) return FALSE;
1143 memcpy( points, pt, total * sizeof(*pt) );
1144 LPtoDP( dev->hdc, points, total );
1145 add_pen_device_bounds( physDev, points, total );
1147 if (X11DRV_SetupGCForBrush( physDev ))
1149 XRectangle *rect;
1150 HRGN hrgn = CreatePolyPolygonRgn( points, counts, polygons, GetPolyFillMode( dev->hdc ) );
1151 RGNDATA *data = X11DRV_GetRegionData( hrgn, 0 );
1153 DeleteObject( hrgn );
1154 if (!data) goto done;
1155 rect = (XRectangle *)data->Buffer;
1156 for (i = 0; i < data->rdh.nCount; i++)
1158 rect[i].x += physDev->dc_rect.left;
1159 rect[i].y += physDev->dc_rect.top;
1162 XFillRectangles( gdi_display, physDev->drawable, physDev->gc, rect, data->rdh.nCount );
1163 HeapFree( GetProcessHeap(), 0, data );
1166 if (X11DRV_SetupGCForPen ( physDev ))
1168 XPoint *xpoints;
1169 int j;
1171 if (!(xpoints = HeapAlloc( GetProcessHeap(), 0, sizeof(XPoint) * (max + 1) ))) goto done;
1172 for (i = pos = 0; i < polygons; pos += counts[i++])
1174 for (j = 0; j < counts[i]; j++)
1176 xpoints[j].x = physDev->dc_rect.left + points[pos + j].x;
1177 xpoints[j].y = physDev->dc_rect.top + points[pos + j].y;
1179 xpoints[j] = xpoints[0];
1180 XDrawLines( gdi_display, physDev->drawable, physDev->gc, xpoints, j + 1, CoordModeOrigin );
1182 HeapFree( GetProcessHeap(), 0, xpoints );
1184 ret = TRUE;
1186 done:
1187 HeapFree( GetProcessHeap(), 0, points );
1188 return ret;
1192 /**********************************************************************
1193 * X11DRV_PolyPolyline
1195 BOOL X11DRV_PolyPolyline( PHYSDEV dev, const POINT* pt, const DWORD* counts, DWORD polylines )
1197 X11DRV_PDEVICE *physDev = get_x11drv_dev( dev );
1198 DWORD total = 0, max = 0, pos, i, j;
1199 POINT *points;
1201 for (i = 0; i < polylines; i++)
1203 if (counts[i] < 2) return FALSE;
1204 if (counts[i] > max) max = counts[i];
1205 total += counts[i];
1208 points = HeapAlloc( GetProcessHeap(), 0, total * sizeof(*pt) );
1209 if (!points) return FALSE;
1210 memcpy( points, pt, total * sizeof(*pt) );
1211 LPtoDP( dev->hdc, points, total );
1212 add_pen_device_bounds( physDev, points, total );
1214 if (X11DRV_SetupGCForPen ( physDev ))
1216 XPoint *xpoints;
1218 if (!(xpoints = HeapAlloc( GetProcessHeap(), 0, sizeof(XPoint) * max )))
1220 HeapFree( GetProcessHeap(), 0, points );
1221 return FALSE;
1223 for (i = pos = 0; i < polylines; pos += counts[i++])
1225 for (j = 0; j < counts[i]; j++)
1227 xpoints[j].x = physDev->dc_rect.left + points[pos + j].x;
1228 xpoints[j].y = physDev->dc_rect.top + points[pos + j].y;
1230 XDrawLines( gdi_display, physDev->drawable, physDev->gc, xpoints, j, CoordModeOrigin );
1232 HeapFree( GetProcessHeap(), 0, xpoints );
1234 HeapFree( GetProcessHeap(), 0, points );
1235 return TRUE;
1239 /**********************************************************************
1240 * X11DRV_InternalFloodFill
1242 * Internal helper function for flood fill.
1243 * (xorg,yorg) is the origin of the X image relative to the drawable.
1244 * (x,y) is relative to the origin of the X image.
1246 static void X11DRV_InternalFloodFill(XImage *image, X11DRV_PDEVICE *physDev,
1247 int x, int y,
1248 int xOrg, int yOrg,
1249 unsigned long pixel, WORD fillType, RECT *bounds )
1251 int left, right;
1253 #define TO_FLOOD(x,y) ((fillType == FLOODFILLBORDER) ? \
1254 (XGetPixel(image,x,y) != pixel) : \
1255 (XGetPixel(image,x,y) == pixel))
1257 if (!TO_FLOOD(x,y)) return;
1259 /* Find left and right boundaries */
1261 left = right = x;
1262 while ((left > 0) && TO_FLOOD( left-1, y )) left--;
1263 while ((right < image->width) && TO_FLOOD( right, y )) right++;
1264 bounds->left = min( bounds->left, left );
1265 bounds->top = min( bounds->top, y );
1266 bounds->right = max( bounds->right, right );
1267 bounds->bottom = max( bounds->bottom, y + 1 );
1268 XFillRectangle( gdi_display, physDev->drawable, physDev->gc,
1269 xOrg + left, yOrg + y, right-left, 1 );
1271 /* Set the pixels of this line so we don't fill it again */
1273 for (x = left; x < right; x++)
1275 if (fillType == FLOODFILLBORDER) XPutPixel( image, x, y, pixel );
1276 else XPutPixel( image, x, y, ~pixel );
1279 /* Fill the line above */
1281 if (--y >= 0)
1283 x = left;
1284 while (x < right)
1286 while ((x < right) && !TO_FLOOD(x,y)) x++;
1287 if (x >= right) break;
1288 while ((x < right) && TO_FLOOD(x,y)) x++;
1289 X11DRV_InternalFloodFill(image, physDev, x-1, y,
1290 xOrg, yOrg, pixel, fillType, bounds );
1294 /* Fill the line below */
1296 if ((y += 2) < image->height)
1298 x = left;
1299 while (x < right)
1301 while ((x < right) && !TO_FLOOD(x,y)) x++;
1302 if (x >= right) break;
1303 while ((x < right) && TO_FLOOD(x,y)) x++;
1304 X11DRV_InternalFloodFill(image, physDev, x-1, y,
1305 xOrg, yOrg, pixel, fillType, bounds );
1308 #undef TO_FLOOD
1312 static int ExtFloodFillXGetImageErrorHandler( Display *dpy, XErrorEvent *event, void *arg )
1314 return (event->request_code == X_GetImage && event->error_code == BadMatch);
1317 /**********************************************************************
1318 * X11DRV_ExtFloodFill
1320 BOOL X11DRV_ExtFloodFill( PHYSDEV dev, INT x, INT y, COLORREF color, UINT fillType )
1322 X11DRV_PDEVICE *physDev = get_x11drv_dev( dev );
1323 XImage *image;
1324 RECT rect, bounds;
1325 POINT pt;
1327 TRACE("X11DRV_ExtFloodFill %d,%d %06x %d\n", x, y, color, fillType );
1329 pt.x = x;
1330 pt.y = y;
1331 LPtoDP( dev->hdc, &pt, 1 );
1333 if (!physDev->region)
1335 rect.left = 0;
1336 rect.top = 0;
1337 rect.right = physDev->dc_rect.right - physDev->dc_rect.left;
1338 rect.bottom = physDev->dc_rect.bottom - physDev->dc_rect.top;
1340 else
1342 if (!PtInRegion( physDev->region, pt.x, pt.y )) return FALSE;
1343 GetRgnBox( physDev->region, &rect );
1344 rect.left = max( rect.left, 0 );
1345 rect.top = max( rect.top, 0 );
1346 rect.right = min( rect.right, physDev->dc_rect.right - physDev->dc_rect.left );
1347 rect.bottom = min( rect.bottom, physDev->dc_rect.bottom - physDev->dc_rect.top );
1349 if (pt.x < rect.left || pt.x >= rect.right || pt.y < rect.top || pt.y >= rect.bottom) return FALSE;
1351 X11DRV_expect_error( gdi_display, ExtFloodFillXGetImageErrorHandler, NULL );
1352 image = XGetImage( gdi_display, physDev->drawable,
1353 physDev->dc_rect.left + rect.left, physDev->dc_rect.top + rect.top,
1354 rect.right - rect.left, rect.bottom - rect.top,
1355 AllPlanes, ZPixmap );
1356 if(X11DRV_check_error()) image = NULL;
1357 if (!image) return FALSE;
1359 if (X11DRV_SetupGCForBrush( physDev ))
1361 unsigned long pixel = X11DRV_PALETTE_ToPhysical( physDev, color );
1363 reset_bounds( &bounds );
1365 X11DRV_InternalFloodFill(image, physDev,
1366 pt.x - rect.left,
1367 pt.y - rect.top,
1368 physDev->dc_rect.left + rect.left,
1369 physDev->dc_rect.top + rect.top,
1370 pixel, fillType, &bounds );
1372 OffsetRect( &bounds, rect.left, rect.top );
1373 add_device_bounds( physDev, &bounds );
1376 XDestroyImage( image );
1377 return TRUE;
1380 /**********************************************************************
1381 * X11DRV_GradientFill
1383 BOOL X11DRV_GradientFill( PHYSDEV dev, TRIVERTEX *vert_array, ULONG nvert,
1384 void *grad_array, ULONG ngrad, ULONG mode )
1386 X11DRV_PDEVICE *physdev = get_x11drv_dev( dev );
1387 const GRADIENT_RECT *rect = grad_array;
1388 TRIVERTEX v[2];
1389 POINT pt[2];
1390 RECT rc, bounds;
1391 unsigned int i;
1392 XGCValues val;
1394 /* <= 16-bpp use dithering */
1395 if (physdev->depth <= 16) goto fallback;
1397 switch (mode)
1399 case GRADIENT_FILL_RECT_H:
1400 val.function = GXcopy;
1401 val.fill_style = FillSolid;
1402 val.line_width = 1;
1403 val.cap_style = CapNotLast;
1404 val.line_style = LineSolid;
1405 XChangeGC( gdi_display, physdev->gc,
1406 GCFunction | GCLineWidth | GCLineStyle | GCCapStyle | GCFillStyle, &val );
1407 reset_bounds( &bounds );
1409 for (i = 0; i < ngrad; i++, rect++)
1411 int x, dx;
1413 v[0] = vert_array[rect->UpperLeft];
1414 v[1] = vert_array[rect->LowerRight];
1415 pt[0].x = v[0].x;
1416 pt[0].y = v[0].y;
1417 pt[1].x = v[1].x;
1418 pt[1].y = v[1].y;
1419 LPtoDP( dev->hdc, pt, 2 );
1420 dx = pt[1].x - pt[0].x;
1421 if (!dx) continue;
1422 if (dx < 0) /* swap the colors */
1424 v[0] = vert_array[rect->LowerRight];
1425 v[1] = vert_array[rect->UpperLeft];
1426 dx = -dx;
1428 rc.left = min( pt[0].x, pt[1].x );
1429 rc.top = min( pt[0].y, pt[1].y );
1430 rc.right = max( pt[0].x, pt[1].x );
1431 rc.bottom = max( pt[0].y, pt[1].y );
1432 add_bounds_rect( &bounds, &rc );
1433 for (x = 0; x < dx; x++)
1435 int color = X11DRV_PALETTE_ToPhysical( physdev,
1436 RGB( (v[0].Red * (dx - x) + v[1].Red * x) / dx / 256,
1437 (v[0].Green * (dx - x) + v[1].Green * x) / dx / 256,
1438 (v[0].Blue * (dx - x) + v[1].Blue * x) / dx / 256) );
1440 XSetForeground( gdi_display, physdev->gc, color );
1441 XDrawLine( gdi_display, physdev->drawable, physdev->gc,
1442 physdev->dc_rect.left + rc.left + x, physdev->dc_rect.top + rc.top,
1443 physdev->dc_rect.left + rc.left + x, physdev->dc_rect.top + rc.bottom );
1446 add_device_bounds( physdev, &bounds );
1447 return TRUE;
1449 case GRADIENT_FILL_RECT_V:
1450 val.function = GXcopy;
1451 val.fill_style = FillSolid;
1452 val.line_width = 1;
1453 val.cap_style = CapNotLast;
1454 val.line_style = LineSolid;
1455 XChangeGC( gdi_display, physdev->gc,
1456 GCFunction | GCLineWidth | GCLineStyle | GCCapStyle | GCFillStyle, &val );
1457 reset_bounds( &bounds );
1459 for (i = 0; i < ngrad; i++, rect++)
1461 int y, dy;
1463 v[0] = vert_array[rect->UpperLeft];
1464 v[1] = vert_array[rect->LowerRight];
1465 pt[0].x = v[0].x;
1466 pt[0].y = v[0].y;
1467 pt[1].x = v[1].x;
1468 pt[1].y = v[1].y;
1469 LPtoDP( dev->hdc, pt, 2 );
1470 dy = pt[1].y - pt[0].y;
1471 if (!dy) continue;
1472 if (dy < 0) /* swap the colors */
1474 v[0] = vert_array[rect->LowerRight];
1475 v[1] = vert_array[rect->UpperLeft];
1476 dy = -dy;
1478 rc.left = min( pt[0].x, pt[1].x );
1479 rc.top = min( pt[0].y, pt[1].y );
1480 rc.right = max( pt[0].x, pt[1].x );
1481 rc.bottom = max( pt[0].y, pt[1].y );
1482 add_bounds_rect( &bounds, &rc );
1483 for (y = 0; y < dy; y++)
1485 int color = X11DRV_PALETTE_ToPhysical( physdev,
1486 RGB( (v[0].Red * (dy - y) + v[1].Red * y) / dy / 256,
1487 (v[0].Green * (dy - y) + v[1].Green * y) / dy / 256,
1488 (v[0].Blue * (dy - y) + v[1].Blue * y) / dy / 256) );
1490 XSetForeground( gdi_display, physdev->gc, color );
1491 XDrawLine( gdi_display, physdev->drawable, physdev->gc,
1492 physdev->dc_rect.left + rc.left, physdev->dc_rect.top + rc.top + y,
1493 physdev->dc_rect.left + rc.right, physdev->dc_rect.top + rc.top + y );
1496 add_device_bounds( physdev, &bounds );
1497 return TRUE;
1500 fallback:
1501 dev = GET_NEXT_PHYSDEV( dev, pGradientFill );
1502 return dev->funcs->pGradientFill( dev, vert_array, nvert, grad_array, ngrad, mode );
1505 static unsigned char *get_icm_profile( unsigned long *size )
1507 Atom type;
1508 int format;
1509 unsigned long count, remaining;
1510 unsigned char *profile, *ret = NULL;
1512 wine_tsx11_lock();
1513 XGetWindowProperty( gdi_display, DefaultRootWindow(gdi_display),
1514 x11drv_atom(_ICC_PROFILE), 0, ~0UL, False, AnyPropertyType,
1515 &type, &format, &count, &remaining, &profile );
1516 *size = get_property_size( format, count );
1517 if (format && count)
1519 if ((ret = HeapAlloc( GetProcessHeap(), 0, *size ))) memcpy( ret, profile, *size );
1520 XFree( profile );
1522 wine_tsx11_unlock();
1523 return ret;
1526 typedef struct
1528 unsigned int unknown[6];
1529 unsigned int state[5];
1530 unsigned int count[2];
1531 unsigned char buffer[64];
1532 } sha_ctx;
1534 extern void WINAPI A_SHAInit( sha_ctx * );
1535 extern void WINAPI A_SHAUpdate( sha_ctx *, const unsigned char *, unsigned int );
1536 extern void WINAPI A_SHAFinal( sha_ctx *, unsigned char * );
1538 static const WCHAR mntr_key[] =
1539 {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
1540 'W','i','n','d','o','w','s',' ','N','T','\\','C','u','r','r','e','n','t',
1541 'V','e','r','s','i','o','n','\\','I','C','M','\\','m','n','t','r',0};
1543 static const WCHAR color_path[] =
1544 {'\\','s','p','o','o','l','\\','d','r','i','v','e','r','s','\\','c','o','l','o','r','\\',0};
1546 /***********************************************************************
1547 * GetICMProfile (X11DRV.@)
1549 BOOL X11DRV_GetICMProfile( PHYSDEV dev, LPDWORD size, LPWSTR filename )
1551 static const WCHAR srgb[] =
1552 {'s','R','G','B',' ','C','o','l','o','r',' ','S','p','a','c','e',' ',
1553 'P','r','o','f','i','l','e','.','i','c','m',0};
1554 HKEY hkey;
1555 DWORD required, len;
1556 WCHAR profile[MAX_PATH], fullname[2*MAX_PATH + sizeof(color_path)/sizeof(WCHAR)];
1557 unsigned char *buffer;
1558 unsigned long buflen;
1560 if (!size) return FALSE;
1562 GetSystemDirectoryW( fullname, MAX_PATH );
1563 strcatW( fullname, color_path );
1565 len = sizeof(profile)/sizeof(WCHAR);
1566 if (!RegCreateKeyExW( HKEY_LOCAL_MACHINE, mntr_key, 0, NULL, 0, KEY_ALL_ACCESS, NULL, &hkey, NULL ) &&
1567 !RegEnumValueW( hkey, 0, profile, &len, NULL, NULL, NULL, NULL )) /* FIXME handle multiple values */
1569 strcatW( fullname, profile );
1570 RegCloseKey( hkey );
1572 else if ((buffer = get_icm_profile( &buflen )))
1574 static const WCHAR fmt[] = {'%','0','2','x',0};
1575 static const WCHAR icm[] = {'.','i','c','m',0};
1577 unsigned char sha1sum[20];
1578 unsigned int i;
1579 sha_ctx ctx;
1580 HANDLE file;
1582 A_SHAInit( &ctx );
1583 A_SHAUpdate( &ctx, buffer, buflen );
1584 A_SHAFinal( &ctx, sha1sum );
1586 for (i = 0; i < sizeof(sha1sum); i++) sprintfW( &profile[i * 2], fmt, sha1sum[i] );
1587 memcpy( &profile[i * 2], icm, sizeof(icm) );
1589 strcatW( fullname, profile );
1590 file = CreateFileW( fullname, GENERIC_WRITE, 0, NULL, CREATE_NEW, 0, 0 );
1591 if (file != INVALID_HANDLE_VALUE)
1593 DWORD written;
1595 if (!WriteFile( file, buffer, buflen, &written, NULL ) || written != buflen)
1596 ERR( "Unable to write color profile\n" );
1597 CloseHandle( file );
1599 HeapFree( GetProcessHeap(), 0, buffer );
1601 else strcatW( fullname, srgb );
1603 required = strlenW( fullname ) + 1;
1604 if (*size < required)
1606 *size = required;
1607 SetLastError( ERROR_INSUFFICIENT_BUFFER );
1608 return FALSE;
1610 if (filename)
1612 strcpyW( filename, fullname );
1613 if (GetFileAttributesW( filename ) == INVALID_FILE_ATTRIBUTES)
1614 WARN( "color profile not found\n" );
1616 *size = required;
1617 return TRUE;
1620 /***********************************************************************
1621 * EnumICMProfiles (X11DRV.@)
1623 INT X11DRV_EnumICMProfiles( PHYSDEV dev, ICMENUMPROCW proc, LPARAM lparam )
1625 X11DRV_PDEVICE *physDev = get_x11drv_dev( dev );
1626 HKEY hkey;
1627 DWORD len_sysdir, len_path, len, index = 0;
1628 WCHAR sysdir[MAX_PATH], *profile;
1629 LONG res;
1630 INT ret;
1632 TRACE("%p, %p, %ld\n", physDev, proc, lparam);
1634 if (RegOpenKeyExW( HKEY_LOCAL_MACHINE, mntr_key, 0, KEY_ALL_ACCESS, &hkey ))
1635 return -1;
1637 len_sysdir = GetSystemDirectoryW( sysdir, MAX_PATH );
1638 len_path = len_sysdir + sizeof(color_path) / sizeof(color_path[0]) - 1;
1639 len = 64;
1640 for (;;)
1642 if (!(profile = HeapAlloc( GetProcessHeap(), 0, (len_path + len) * sizeof(WCHAR) )))
1644 RegCloseKey( hkey );
1645 return -1;
1647 res = RegEnumValueW( hkey, index, profile + len_path, &len, NULL, NULL, NULL, NULL );
1648 while (res == ERROR_MORE_DATA)
1650 len *= 2;
1651 HeapFree( GetProcessHeap(), 0, profile );
1652 if (!(profile = HeapAlloc( GetProcessHeap(), 0, (len_path + len) * sizeof(WCHAR) )))
1654 RegCloseKey( hkey );
1655 return -1;
1657 res = RegEnumValueW( hkey, index, profile + len_path, &len, NULL, NULL, NULL, NULL );
1659 if (res != ERROR_SUCCESS)
1661 HeapFree( GetProcessHeap(), 0, profile );
1662 break;
1664 memcpy( profile, sysdir, len_sysdir * sizeof(WCHAR) );
1665 memcpy( profile + len_sysdir, color_path, sizeof(color_path) - sizeof(WCHAR) );
1666 ret = proc( profile, lparam );
1667 HeapFree( GetProcessHeap(), 0, profile );
1668 if (!ret) break;
1669 index++;
1671 RegCloseKey( hkey );
1672 return -1;