winex11: Store the DC bounds rectangle as a pointer.
[wine/multimedia.git] / dlls / winex11.drv / graphics.c
blob0d1e49b9afe200707bcc68e33e8ca64f3dcff521
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 wine_tsx11_lock();
251 XSetClipMask( gdi_display, physDev->gc, None );
252 wine_tsx11_unlock();
254 else if ((data = X11DRV_GetRegionData( rgn, 0 )))
256 wine_tsx11_lock();
257 XSetClipRectangles( gdi_display, physDev->gc, physDev->dc_rect.left, physDev->dc_rect.top,
258 (XRectangle *)data->Buffer, data->rdh.nCount, YXBanded );
259 wine_tsx11_unlock();
260 HeapFree( GetProcessHeap(), 0, data );
265 /***********************************************************************
266 * add_extra_clipping_region
268 * Temporarily add a region to the current clipping region.
269 * The region must be restored with restore_clipping_region.
271 BOOL add_extra_clipping_region( X11DRV_PDEVICE *dev, HRGN rgn )
273 HRGN clip;
275 if (!rgn) return FALSE;
276 if (dev->region)
278 if (!(clip = CreateRectRgn( 0, 0, 0, 0 ))) return FALSE;
279 CombineRgn( clip, dev->region, rgn, RGN_AND );
280 update_x11_clipping( dev, clip );
281 DeleteObject( clip );
283 else update_x11_clipping( dev, rgn );
284 return TRUE;
288 /***********************************************************************
289 * restore_clipping_region
291 void restore_clipping_region( X11DRV_PDEVICE *dev )
293 update_x11_clipping( dev, dev->region );
297 /***********************************************************************
298 * X11DRV_SetDeviceClipping
300 void X11DRV_SetDeviceClipping( PHYSDEV dev, HRGN rgn )
302 X11DRV_PDEVICE *physDev = get_x11drv_dev( dev );
304 physDev->region = rgn;
305 update_x11_clipping( physDev, rgn );
309 /***********************************************************************
310 * X11DRV_SetupGCForPatBlt
312 * Setup the GC for a PatBlt operation using current brush.
313 * If fMapColors is TRUE, X pixels are mapped to Windows colors.
314 * Return FALSE if brush is BS_NULL, TRUE otherwise.
316 BOOL X11DRV_SetupGCForPatBlt( X11DRV_PDEVICE *physDev, GC gc, BOOL fMapColors )
318 XGCValues val;
319 unsigned long mask;
320 Pixmap pixmap = 0;
321 POINT pt;
323 if (physDev->brush.style == BS_NULL) return FALSE;
324 if (physDev->brush.pixel == -1)
326 /* Special case used for monochrome pattern brushes.
327 * We need to swap foreground and background because
328 * Windows does it the wrong way...
330 val.foreground = X11DRV_PALETTE_ToPhysical( physDev, GetBkColor(physDev->dev.hdc) );
331 val.background = X11DRV_PALETTE_ToPhysical( physDev, GetTextColor(physDev->dev.hdc) );
333 else
335 val.foreground = physDev->brush.pixel;
336 val.background = X11DRV_PALETTE_ToPhysical( physDev, GetBkColor(physDev->dev.hdc) );
338 if (fMapColors && X11DRV_PALETTE_XPixelToPalette)
340 val.foreground = X11DRV_PALETTE_XPixelToPalette[val.foreground];
341 val.background = X11DRV_PALETTE_XPixelToPalette[val.background];
344 val.function = X11DRV_XROPfunction[GetROP2(physDev->dev.hdc)-1];
346 ** Let's replace GXinvert by GXxor with (black xor white)
347 ** This solves the selection color and leak problems in excel
348 ** FIXME : Let's do that only if we work with X-pixels, not with Win-pixels
350 if (val.function == GXinvert)
352 val.foreground = (WhitePixel( gdi_display, DefaultScreen(gdi_display) ) ^
353 BlackPixel( gdi_display, DefaultScreen(gdi_display) ));
354 val.function = GXxor;
356 val.fill_style = physDev->brush.fillStyle;
357 switch(val.fill_style)
359 case FillStippled:
360 case FillOpaqueStippled:
361 if (GetBkMode(physDev->dev.hdc)==OPAQUE) val.fill_style = FillOpaqueStippled;
362 val.stipple = physDev->brush.pixmap;
363 mask = GCStipple;
364 break;
366 case FillTiled:
367 if (fMapColors && X11DRV_PALETTE_XPixelToPalette)
369 register int x, y;
370 XImage *image;
371 wine_tsx11_lock();
372 pixmap = XCreatePixmap( gdi_display, root_window, 8, 8, physDev->depth );
373 image = XGetImage( gdi_display, physDev->brush.pixmap, 0, 0, 8, 8,
374 AllPlanes, ZPixmap );
375 for (y = 0; y < 8; y++)
376 for (x = 0; x < 8; x++)
377 XPutPixel( image, x, y,
378 X11DRV_PALETTE_XPixelToPalette[XGetPixel( image, x, y)] );
379 XPutImage( gdi_display, pixmap, gc, image, 0, 0, 0, 0, 8, 8 );
380 XDestroyImage( image );
381 wine_tsx11_unlock();
382 val.tile = pixmap;
384 else val.tile = physDev->brush.pixmap;
385 mask = GCTile;
386 break;
388 default:
389 mask = 0;
390 break;
392 GetBrushOrgEx( physDev->dev.hdc, &pt );
393 val.ts_x_origin = physDev->dc_rect.left + pt.x;
394 val.ts_y_origin = physDev->dc_rect.top + pt.y;
395 val.fill_rule = (GetPolyFillMode(physDev->dev.hdc) == WINDING) ? WindingRule : EvenOddRule;
396 wine_tsx11_lock();
397 XChangeGC( gdi_display, gc,
398 GCFunction | GCForeground | GCBackground | GCFillStyle |
399 GCFillRule | GCTileStipXOrigin | GCTileStipYOrigin | mask,
400 &val );
401 if (pixmap) XFreePixmap( gdi_display, pixmap );
402 wine_tsx11_unlock();
403 return TRUE;
407 /***********************************************************************
408 * X11DRV_SetupGCForBrush
410 * Setup physDev->gc for drawing operations using current brush.
411 * Return FALSE if brush is BS_NULL, TRUE otherwise.
413 BOOL X11DRV_SetupGCForBrush( X11DRV_PDEVICE *physDev )
415 return X11DRV_SetupGCForPatBlt( physDev, physDev->gc, FALSE );
419 /***********************************************************************
420 * X11DRV_SetupGCForPen
422 * Setup physDev->gc for drawing operations using current pen.
423 * Return FALSE if pen is PS_NULL, TRUE otherwise.
425 static BOOL X11DRV_SetupGCForPen( X11DRV_PDEVICE *physDev )
427 XGCValues val;
428 UINT rop2 = GetROP2(physDev->dev.hdc);
430 if (physDev->pen.style == PS_NULL) return FALSE;
432 switch (rop2)
434 case R2_BLACK :
435 val.foreground = BlackPixel( gdi_display, DefaultScreen(gdi_display) );
436 val.function = GXcopy;
437 break;
438 case R2_WHITE :
439 val.foreground = WhitePixel( gdi_display, DefaultScreen(gdi_display) );
440 val.function = GXcopy;
441 break;
442 case R2_XORPEN :
443 val.foreground = physDev->pen.pixel;
444 /* It is very unlikely someone wants to XOR with 0 */
445 /* This fixes the rubber-drawings in paintbrush */
446 if (val.foreground == 0)
447 val.foreground = (WhitePixel( gdi_display, DefaultScreen(gdi_display) ) ^
448 BlackPixel( gdi_display, DefaultScreen(gdi_display) ));
449 val.function = GXxor;
450 break;
451 default :
452 val.foreground = physDev->pen.pixel;
453 val.function = X11DRV_XROPfunction[rop2-1];
455 val.background = X11DRV_PALETTE_ToPhysical( physDev, GetBkColor(physDev->dev.hdc) );
456 val.fill_style = FillSolid;
457 val.line_width = physDev->pen.width;
458 if (val.line_width <= 1) {
459 val.cap_style = CapNotLast;
460 } else {
461 switch (physDev->pen.endcap)
463 case PS_ENDCAP_SQUARE:
464 val.cap_style = CapProjecting;
465 break;
466 case PS_ENDCAP_FLAT:
467 val.cap_style = CapButt;
468 break;
469 case PS_ENDCAP_ROUND:
470 default:
471 val.cap_style = CapRound;
474 switch (physDev->pen.linejoin)
476 case PS_JOIN_BEVEL:
477 val.join_style = JoinBevel;
478 break;
479 case PS_JOIN_MITER:
480 val.join_style = JoinMiter;
481 break;
482 case PS_JOIN_ROUND:
483 default:
484 val.join_style = JoinRound;
487 if (physDev->pen.dash_len)
488 val.line_style = ((GetBkMode(physDev->dev.hdc) == OPAQUE) && (!physDev->pen.ext))
489 ? LineDoubleDash : LineOnOffDash;
490 else
491 val.line_style = LineSolid;
493 wine_tsx11_lock();
494 if (physDev->pen.dash_len)
495 XSetDashes( gdi_display, physDev->gc, 0, physDev->pen.dashes, physDev->pen.dash_len );
496 XChangeGC( gdi_display, physDev->gc,
497 GCFunction | GCForeground | GCBackground | GCLineWidth |
498 GCLineStyle | GCCapStyle | GCJoinStyle | GCFillStyle, &val );
499 wine_tsx11_unlock();
500 return TRUE;
504 /***********************************************************************
505 * X11DRV_XWStoDS
507 * Performs a world-to-viewport transformation on the specified width.
509 INT X11DRV_XWStoDS( HDC hdc, INT width )
511 POINT pt[2];
513 pt[0].x = 0;
514 pt[0].y = 0;
515 pt[1].x = width;
516 pt[1].y = 0;
517 LPtoDP( hdc, pt, 2 );
518 return pt[1].x - pt[0].x;
521 /***********************************************************************
522 * X11DRV_YWStoDS
524 * Performs a world-to-viewport transformation on the specified height.
526 INT X11DRV_YWStoDS( HDC hdc, INT height )
528 POINT pt[2];
530 pt[0].x = 0;
531 pt[0].y = 0;
532 pt[1].x = 0;
533 pt[1].y = height;
534 LPtoDP( hdc, pt, 2 );
535 return pt[1].y - pt[0].y;
538 /***********************************************************************
539 * X11DRV_LineTo
541 BOOL X11DRV_LineTo( PHYSDEV dev, INT x, INT y )
543 X11DRV_PDEVICE *physDev = get_x11drv_dev( dev );
544 POINT pt[2];
546 GetCurrentPositionEx( dev->hdc, &pt[0] );
547 pt[1].x = x;
548 pt[1].y = y;
549 LPtoDP( dev->hdc, pt, 2 );
550 add_pen_device_bounds( physDev, pt, 2 );
552 if (X11DRV_SetupGCForPen( physDev ))
554 wine_tsx11_lock();
555 XDrawLine(gdi_display, physDev->drawable, physDev->gc,
556 physDev->dc_rect.left + pt[0].x, physDev->dc_rect.top + pt[0].y,
557 physDev->dc_rect.left + pt[1].x, physDev->dc_rect.top + pt[1].y );
558 wine_tsx11_unlock();
560 return TRUE;
565 /***********************************************************************
566 * X11DRV_DrawArc
568 * Helper functions for Arc(), Chord() and Pie().
569 * 'lines' is the number of lines to draw: 0 for Arc, 1 for Chord, 2 for Pie.
572 static BOOL X11DRV_DrawArc( PHYSDEV dev, INT left, INT top, INT right, INT bottom,
573 INT xstart, INT ystart, INT xend, INT yend, INT lines )
575 X11DRV_PDEVICE *physDev = get_x11drv_dev( dev );
576 INT xcenter, ycenter, istart_angle, idiff_angle;
577 INT width, oldwidth;
578 double start_angle, end_angle;
579 XPoint points[4];
580 POINT start, end;
581 RECT rc = get_device_rect( dev->hdc, left, top, right, bottom );
583 start.x = xstart;
584 start.y = ystart;
585 end.x = xend;
586 end.y = yend;
587 LPtoDP(dev->hdc, &start, 1);
588 LPtoDP(dev->hdc, &end, 1);
590 if ((rc.left == rc.right) || (rc.top == rc.bottom)
591 ||(lines && ((rc.right-rc.left==1)||(rc.bottom-rc.top==1)))) return TRUE;
593 if (GetArcDirection( dev->hdc ) == AD_CLOCKWISE)
594 { POINT tmp = start; start = end; end = tmp; }
596 oldwidth = width = physDev->pen.width;
597 if (!width) width = 1;
598 if(physDev->pen.style == PS_NULL) width = 0;
600 if (physDev->pen.style == PS_INSIDEFRAME)
602 if (2*width > (rc.right-rc.left)) width=(rc.right-rc.left + 1)/2;
603 if (2*width > (rc.bottom-rc.top)) width=(rc.bottom-rc.top + 1)/2;
604 rc.left += width / 2;
605 rc.right -= (width - 1) / 2;
606 rc.top += width / 2;
607 rc.bottom -= (width - 1) / 2;
609 if(width == 0) width = 1; /* more accurate */
610 physDev->pen.width = width;
612 xcenter = (rc.right + rc.left) / 2;
613 ycenter = (rc.bottom + rc.top) / 2;
614 start_angle = atan2( (double)(ycenter-start.y)*(rc.right-rc.left),
615 (double)(start.x-xcenter)*(rc.bottom-rc.top) );
616 end_angle = atan2( (double)(ycenter-end.y)*(rc.right-rc.left),
617 (double)(end.x-xcenter)*(rc.bottom-rc.top) );
618 if ((start.x==end.x)&&(start.y==end.y))
619 { /* A lazy program delivers xstart=xend=ystart=yend=0) */
620 start_angle = 0;
621 end_angle = 2* PI;
623 else /* notorious cases */
624 if ((start_angle == PI)&&( end_angle <0))
625 start_angle = - PI;
626 else
627 if ((end_angle == PI)&&( start_angle <0))
628 end_angle = - PI;
629 istart_angle = (INT)(start_angle * 180 * 64 / PI + 0.5);
630 idiff_angle = (INT)((end_angle - start_angle) * 180 * 64 / PI + 0.5);
631 if (idiff_angle <= 0) idiff_angle += 360 * 64;
633 /* Fill arc with brush if Chord() or Pie() */
635 if ((lines > 0) && X11DRV_SetupGCForBrush( physDev )) {
636 wine_tsx11_lock();
637 XSetArcMode( gdi_display, physDev->gc, (lines==1) ? ArcChord : ArcPieSlice);
638 XFillArc( gdi_display, physDev->drawable, physDev->gc,
639 physDev->dc_rect.left + rc.left, physDev->dc_rect.top + rc.top,
640 rc.right-rc.left-1, rc.bottom-rc.top-1, istart_angle, idiff_angle );
641 wine_tsx11_unlock();
644 /* Draw arc and lines */
646 if (X11DRV_SetupGCForPen( physDev ))
648 wine_tsx11_lock();
649 XDrawArc( gdi_display, physDev->drawable, physDev->gc,
650 physDev->dc_rect.left + rc.left, physDev->dc_rect.top + rc.top,
651 rc.right-rc.left-1, rc.bottom-rc.top-1, istart_angle, idiff_angle );
652 if (lines) {
653 /* use the truncated values */
654 start_angle=(double)istart_angle*PI/64./180.;
655 end_angle=(double)(istart_angle+idiff_angle)*PI/64./180.;
656 /* calculate the endpoints and round correctly */
657 points[0].x = (int) floor(physDev->dc_rect.left + (rc.right+rc.left)/2.0 +
658 cos(start_angle) * (rc.right-rc.left-width*2+2) / 2. + 0.5);
659 points[0].y = (int) floor(physDev->dc_rect.top + (rc.top+rc.bottom)/2.0 -
660 sin(start_angle) * (rc.bottom-rc.top-width*2+2) / 2. + 0.5);
661 points[1].x = (int) floor(physDev->dc_rect.left + (rc.right+rc.left)/2.0 +
662 cos(end_angle) * (rc.right-rc.left-width*2+2) / 2. + 0.5);
663 points[1].y = (int) floor(physDev->dc_rect.top + (rc.top+rc.bottom)/2.0 -
664 sin(end_angle) * (rc.bottom-rc.top-width*2+2) / 2. + 0.5);
666 /* OK, this stuff is optimized for Xfree86
667 * which is probably the server most used by
668 * wine users. Other X servers will not
669 * display correctly. (eXceed for instance)
670 * so if you feel you must make changes, make sure that
671 * you either use Xfree86 or separate your changes
672 * from these (compile switch or whatever)
674 if (lines == 2) {
675 INT dx1,dy1;
676 points[3] = points[1];
677 points[1].x = physDev->dc_rect.left + xcenter;
678 points[1].y = physDev->dc_rect.top + ycenter;
679 points[2] = points[1];
680 dx1=points[1].x-points[0].x;
681 dy1=points[1].y-points[0].y;
682 if(((rc.top-rc.bottom) | -2) == -2)
683 if(dy1>0) points[1].y--;
684 if(dx1<0) {
685 if (((-dx1)*64)<=ABS(dy1)*37) points[0].x--;
686 if(((-dx1*9))<(dy1*16)) points[0].y--;
687 if( dy1<0 && ((dx1*9)) < (dy1*16)) points[0].y--;
688 } else {
689 if(dy1 < 0) points[0].y--;
690 if(((rc.right-rc.left) | -2) == -2) points[1].x--;
692 dx1=points[3].x-points[2].x;
693 dy1=points[3].y-points[2].y;
694 if(((rc.top-rc.bottom) | -2 ) == -2)
695 if(dy1 < 0) points[2].y--;
696 if( dx1<0){
697 if( dy1>0) points[3].y--;
698 if(((rc.right-rc.left) | -2) == -2 ) points[2].x--;
699 }else {
700 points[3].y--;
701 if( dx1 * 64 < dy1 * -37 ) points[3].x--;
703 lines++;
705 XDrawLines( gdi_display, physDev->drawable, physDev->gc,
706 points, lines+1, CoordModeOrigin );
708 wine_tsx11_unlock();
711 physDev->pen.width = oldwidth;
712 add_pen_device_bounds( physDev, (POINT *)&rc, 2 );
713 return TRUE;
717 /***********************************************************************
718 * X11DRV_Arc
720 BOOL X11DRV_Arc( PHYSDEV dev, INT left, INT top, INT right, INT bottom,
721 INT xstart, INT ystart, INT xend, INT yend )
723 return X11DRV_DrawArc( dev, left, top, right, bottom, xstart, ystart, xend, yend, 0 );
727 /***********************************************************************
728 * X11DRV_Pie
730 BOOL X11DRV_Pie( PHYSDEV dev, INT left, INT top, INT right, INT bottom,
731 INT xstart, INT ystart, INT xend, INT yend )
733 return X11DRV_DrawArc( dev, left, top, right, bottom, xstart, ystart, xend, yend, 2 );
736 /***********************************************************************
737 * X11DRV_Chord
739 BOOL X11DRV_Chord( PHYSDEV dev, INT left, INT top, INT right, INT bottom,
740 INT xstart, INT ystart, INT xend, INT yend )
742 return X11DRV_DrawArc( dev, left, top, right, bottom, xstart, ystart, xend, yend, 1 );
746 /***********************************************************************
747 * X11DRV_Ellipse
749 BOOL X11DRV_Ellipse( PHYSDEV dev, INT left, INT top, INT right, INT bottom )
751 X11DRV_PDEVICE *physDev = get_x11drv_dev( dev );
752 INT width, oldwidth;
753 RECT rc = get_device_rect( dev->hdc, left, top, right, bottom );
755 if ((rc.left == rc.right) || (rc.top == rc.bottom)) return TRUE;
757 oldwidth = width = physDev->pen.width;
758 if (!width) width = 1;
759 if(physDev->pen.style == PS_NULL) width = 0;
761 if (physDev->pen.style == PS_INSIDEFRAME)
763 if (2*width > (rc.right-rc.left)) width=(rc.right-rc.left + 1)/2;
764 if (2*width > (rc.bottom-rc.top)) width=(rc.bottom-rc.top + 1)/2;
765 rc.left += width / 2;
766 rc.right -= (width - 1) / 2;
767 rc.top += width / 2;
768 rc.bottom -= (width - 1) / 2;
770 if(width == 0) width = 1; /* more accurate */
771 physDev->pen.width = width;
773 if (X11DRV_SetupGCForBrush( physDev ))
775 wine_tsx11_lock();
776 XFillArc( gdi_display, physDev->drawable, physDev->gc,
777 physDev->dc_rect.left + rc.left, physDev->dc_rect.top + rc.top,
778 rc.right-rc.left-1, rc.bottom-rc.top-1, 0, 360*64 );
779 wine_tsx11_unlock();
781 if (X11DRV_SetupGCForPen( physDev ))
783 wine_tsx11_lock();
784 XDrawArc( gdi_display, physDev->drawable, physDev->gc,
785 physDev->dc_rect.left + rc.left, physDev->dc_rect.top + rc.top,
786 rc.right-rc.left-1, rc.bottom-rc.top-1, 0, 360*64 );
787 wine_tsx11_unlock();
790 physDev->pen.width = oldwidth;
791 add_pen_device_bounds( physDev, (POINT *)&rc, 2 );
792 return TRUE;
796 /***********************************************************************
797 * X11DRV_Rectangle
799 BOOL X11DRV_Rectangle(PHYSDEV dev, INT left, INT top, INT right, INT bottom)
801 X11DRV_PDEVICE *physDev = get_x11drv_dev( dev );
802 INT width, oldwidth, oldjoinstyle;
803 RECT rc = get_device_rect( dev->hdc, left, top, right, bottom );
805 TRACE("(%d %d %d %d)\n", left, top, right, bottom);
807 if ((rc.left == rc.right) || (rc.top == rc.bottom)) return TRUE;
809 oldwidth = width = physDev->pen.width;
810 if (!width) width = 1;
811 if(physDev->pen.style == PS_NULL) width = 0;
813 if (physDev->pen.style == PS_INSIDEFRAME)
815 if (2*width > (rc.right-rc.left)) width=(rc.right-rc.left + 1)/2;
816 if (2*width > (rc.bottom-rc.top)) width=(rc.bottom-rc.top + 1)/2;
817 rc.left += width / 2;
818 rc.right -= (width - 1) / 2;
819 rc.top += width / 2;
820 rc.bottom -= (width - 1) / 2;
822 if(width == 1) width = 0;
823 physDev->pen.width = width;
824 oldjoinstyle = physDev->pen.linejoin;
825 if(physDev->pen.type != PS_GEOMETRIC)
826 physDev->pen.linejoin = PS_JOIN_MITER;
828 rc.right--;
829 rc.bottom--;
830 if ((rc.right >= rc.left + width) && (rc.bottom >= rc.top + width))
832 if (X11DRV_SetupGCForBrush( physDev ))
834 wine_tsx11_lock();
835 XFillRectangle( gdi_display, physDev->drawable, physDev->gc,
836 physDev->dc_rect.left + rc.left + (width + 1) / 2,
837 physDev->dc_rect.top + rc.top + (width + 1) / 2,
838 rc.right-rc.left-width, rc.bottom-rc.top-width);
839 wine_tsx11_unlock();
842 if (X11DRV_SetupGCForPen( physDev ))
844 wine_tsx11_lock();
845 XDrawRectangle( gdi_display, physDev->drawable, physDev->gc,
846 physDev->dc_rect.left + rc.left, physDev->dc_rect.top + rc.top,
847 rc.right-rc.left, rc.bottom-rc.top );
848 wine_tsx11_unlock();
851 physDev->pen.width = oldwidth;
852 physDev->pen.linejoin = oldjoinstyle;
853 add_pen_device_bounds( physDev, (POINT *)&rc, 2 );
854 return TRUE;
857 /***********************************************************************
858 * X11DRV_RoundRect
860 BOOL X11DRV_RoundRect( PHYSDEV dev, INT left, INT top, INT right, INT bottom,
861 INT ell_width, INT ell_height )
863 X11DRV_PDEVICE *physDev = get_x11drv_dev( dev );
864 INT width, oldwidth, oldendcap;
865 POINT pts[2];
866 RECT rc = get_device_rect( dev->hdc, left, top, right, bottom );
868 TRACE("(%d %d %d %d %d %d\n",
869 left, top, right, bottom, ell_width, ell_height);
871 if ((rc.left == rc.right) || (rc.top == rc.bottom))
872 return TRUE;
874 /* Make sure ell_width and ell_height are >= 1 otherwise XDrawArc gets
875 called with width/height < 0 */
876 pts[0].x = pts[0].y = 0;
877 pts[1].x = ell_width;
878 pts[1].y = ell_height;
879 LPtoDP(dev->hdc, pts, 2);
880 ell_width = max(abs( pts[1].x - pts[0].x ), 1);
881 ell_height = max(abs( pts[1].y - pts[0].y ), 1);
883 oldwidth = width = physDev->pen.width;
884 oldendcap = physDev->pen.endcap;
885 if (!width) width = 1;
886 if(physDev->pen.style == PS_NULL) width = 0;
888 if (physDev->pen.style == PS_INSIDEFRAME)
890 if (2*width > (rc.right-rc.left)) width=(rc.right-rc.left + 1)/2;
891 if (2*width > (rc.bottom-rc.top)) width=(rc.bottom-rc.top + 1)/2;
892 rc.left += width / 2;
893 rc.right -= (width - 1) / 2;
894 rc.top += width / 2;
895 rc.bottom -= (width - 1) / 2;
897 if(width == 0) width = 1;
898 physDev->pen.width = width;
899 physDev->pen.endcap = PS_ENDCAP_SQUARE;
901 if (X11DRV_SetupGCForBrush( physDev ))
903 wine_tsx11_lock();
904 if (ell_width > (rc.right-rc.left) )
905 if (ell_height > (rc.bottom-rc.top) )
906 XFillArc( gdi_display, physDev->drawable, physDev->gc,
907 physDev->dc_rect.left + rc.left, physDev->dc_rect.top + rc.top,
908 rc.right - rc.left - 1, rc.bottom - rc.top - 1,
909 0, 360 * 64 );
910 else{
911 XFillArc( gdi_display, physDev->drawable, physDev->gc,
912 physDev->dc_rect.left + rc.left, physDev->dc_rect.top + rc.top,
913 rc.right - rc.left - 1, ell_height, 0, 180 * 64 );
914 XFillArc( gdi_display, physDev->drawable, physDev->gc,
915 physDev->dc_rect.left + rc.left,
916 physDev->dc_rect.top + rc.bottom - ell_height - 1,
917 rc.right - rc.left - 1, ell_height, 180 * 64,
918 180 * 64 );
920 else if (ell_height > (rc.bottom-rc.top) ){
921 XFillArc( gdi_display, physDev->drawable, physDev->gc,
922 physDev->dc_rect.left + rc.left, physDev->dc_rect.top + rc.top,
923 ell_width, rc.bottom - rc.top - 1, 90 * 64, 180 * 64 );
924 XFillArc( gdi_display, physDev->drawable, physDev->gc,
925 physDev->dc_rect.left + rc.right - ell_width - 1, physDev->dc_rect.top + rc.top,
926 ell_width, rc.bottom - rc.top - 1, 270 * 64, 180 * 64 );
927 }else{
928 XFillArc( gdi_display, physDev->drawable, physDev->gc,
929 physDev->dc_rect.left + rc.left, physDev->dc_rect.top + rc.top,
930 ell_width, ell_height, 90 * 64, 90 * 64 );
931 XFillArc( gdi_display, physDev->drawable, physDev->gc,
932 physDev->dc_rect.left + rc.left,
933 physDev->dc_rect.top + rc.bottom - ell_height - 1,
934 ell_width, ell_height, 180 * 64, 90 * 64 );
935 XFillArc( gdi_display, physDev->drawable, physDev->gc,
936 physDev->dc_rect.left + rc.right - ell_width - 1,
937 physDev->dc_rect.top + rc.bottom - ell_height - 1,
938 ell_width, ell_height, 270 * 64, 90 * 64 );
939 XFillArc( gdi_display, physDev->drawable, physDev->gc,
940 physDev->dc_rect.left + rc.right - ell_width - 1,
941 physDev->dc_rect.top + rc.top,
942 ell_width, ell_height, 0, 90 * 64 );
944 if (ell_width < rc.right - rc.left)
946 XFillRectangle( gdi_display, physDev->drawable, physDev->gc,
947 physDev->dc_rect.left + rc.left + (ell_width + 1) / 2,
948 physDev->dc_rect.top + rc.top + 1,
949 rc.right - rc.left - ell_width - 1,
950 (ell_height + 1) / 2 - 1);
951 XFillRectangle( gdi_display, physDev->drawable, physDev->gc,
952 physDev->dc_rect.left + rc.left + (ell_width + 1) / 2,
953 physDev->dc_rect.top + rc.bottom - (ell_height) / 2 - 1,
954 rc.right - rc.left - ell_width - 1,
955 (ell_height) / 2 );
957 if (ell_height < rc.bottom - rc.top)
959 XFillRectangle( gdi_display, physDev->drawable, physDev->gc,
960 physDev->dc_rect.left + rc.left + 1,
961 physDev->dc_rect.top + rc.top + (ell_height + 1) / 2,
962 rc.right - rc.left - 2,
963 rc.bottom - rc.top - ell_height - 1);
965 wine_tsx11_unlock();
967 /* FIXME: this could be done with on X call
968 * more efficient and probably more correct
969 * on any X server: XDrawArcs will draw
970 * straight horizontal and vertical lines
971 * if width or height are zero.
973 * BTW this stuff is optimized for an Xfree86 server
974 * read the comments inside the X11DRV_DrawArc function
976 if (X11DRV_SetupGCForPen( physDev ))
978 wine_tsx11_lock();
979 if (ell_width > (rc.right-rc.left) )
980 if (ell_height > (rc.bottom-rc.top) )
981 XDrawArc( gdi_display, physDev->drawable, physDev->gc,
982 physDev->dc_rect.left + rc.left, physDev->dc_rect.top + rc.top,
983 rc.right - rc.left - 1, rc.bottom - rc.top - 1, 0 , 360 * 64 );
984 else{
985 XDrawArc( gdi_display, physDev->drawable, physDev->gc,
986 physDev->dc_rect.left + rc.left, physDev->dc_rect.top + rc.top,
987 rc.right - rc.left - 1, ell_height - 1, 0 , 180 * 64 );
988 XDrawArc( gdi_display, physDev->drawable, physDev->gc,
989 physDev->dc_rect.left + rc.left,
990 physDev->dc_rect.top + rc.bottom - ell_height,
991 rc.right - rc.left - 1, ell_height - 1, 180 * 64 , 180 * 64 );
993 else if (ell_height > (rc.bottom-rc.top) ){
994 XDrawArc( gdi_display, physDev->drawable, physDev->gc,
995 physDev->dc_rect.left + rc.left, physDev->dc_rect.top + rc.top,
996 ell_width - 1 , rc.bottom - rc.top - 1, 90 * 64 , 180 * 64 );
997 XDrawArc( gdi_display, physDev->drawable, physDev->gc,
998 physDev->dc_rect.left + rc.right - ell_width,
999 physDev->dc_rect.top + rc.top,
1000 ell_width - 1 , rc.bottom - rc.top - 1, 270 * 64 , 180 * 64 );
1001 }else{
1002 XDrawArc( gdi_display, physDev->drawable, physDev->gc,
1003 physDev->dc_rect.left + rc.left, physDev->dc_rect.top + rc.top,
1004 ell_width - 1, ell_height - 1, 90 * 64, 90 * 64 );
1005 XDrawArc( gdi_display, physDev->drawable, physDev->gc,
1006 physDev->dc_rect.left + rc.left, physDev->dc_rect.top + rc.bottom - ell_height,
1007 ell_width - 1, ell_height - 1, 180 * 64, 90 * 64 );
1008 XDrawArc( gdi_display, physDev->drawable, physDev->gc,
1009 physDev->dc_rect.left + rc.right - ell_width,
1010 physDev->dc_rect.top + rc.bottom - ell_height,
1011 ell_width - 1, ell_height - 1, 270 * 64, 90 * 64 );
1012 XDrawArc( gdi_display, physDev->drawable, physDev->gc,
1013 physDev->dc_rect.left + rc.right - ell_width, physDev->dc_rect.top + rc.top,
1014 ell_width - 1, ell_height - 1, 0, 90 * 64 );
1016 if (ell_width < rc.right - rc.left)
1018 XDrawLine( gdi_display, physDev->drawable, physDev->gc,
1019 physDev->dc_rect.left + rc.left + ell_width / 2,
1020 physDev->dc_rect.top + rc.top,
1021 physDev->dc_rect.left + rc.right - (ell_width+1) / 2,
1022 physDev->dc_rect.top + rc.top);
1023 XDrawLine( gdi_display, physDev->drawable, physDev->gc,
1024 physDev->dc_rect.left + rc.left + ell_width / 2 ,
1025 physDev->dc_rect.top + rc.bottom - 1,
1026 physDev->dc_rect.left + rc.right - (ell_width+1)/ 2,
1027 physDev->dc_rect.top + rc.bottom - 1);
1029 if (ell_height < rc.bottom - rc.top)
1031 XDrawLine( gdi_display, physDev->drawable, physDev->gc,
1032 physDev->dc_rect.left + rc.right - 1,
1033 physDev->dc_rect.top + rc.top + ell_height / 2,
1034 physDev->dc_rect.left + rc.right - 1,
1035 physDev->dc_rect.top + rc.bottom - (ell_height+1) / 2);
1036 XDrawLine( gdi_display, physDev->drawable, physDev->gc,
1037 physDev->dc_rect.left + rc.left,
1038 physDev->dc_rect.top + rc.top + ell_height / 2,
1039 physDev->dc_rect.left + rc.left,
1040 physDev->dc_rect.top + rc.bottom - (ell_height+1) / 2);
1042 wine_tsx11_unlock();
1045 physDev->pen.width = oldwidth;
1046 physDev->pen.endcap = oldendcap;
1047 add_pen_device_bounds( physDev, (POINT *)&rc, 2 );
1048 return TRUE;
1052 /***********************************************************************
1053 * X11DRV_SetPixel
1055 COLORREF X11DRV_SetPixel( PHYSDEV dev, INT x, INT y, COLORREF color )
1057 X11DRV_PDEVICE *physDev = get_x11drv_dev( dev );
1058 unsigned long pixel;
1059 POINT pt;
1060 RECT rect;
1062 pt.x = x;
1063 pt.y = y;
1064 LPtoDP( dev->hdc, &pt, 1 );
1065 pixel = X11DRV_PALETTE_ToPhysical( physDev, color );
1067 wine_tsx11_lock();
1068 XSetForeground( gdi_display, physDev->gc, pixel );
1069 XSetFunction( gdi_display, physDev->gc, GXcopy );
1070 XDrawPoint( gdi_display, physDev->drawable, physDev->gc,
1071 physDev->dc_rect.left + pt.x, physDev->dc_rect.top + pt.y );
1072 wine_tsx11_unlock();
1074 SetRect( &rect, pt.x, pt.y, pt.x + 1, pt.y + 1 );
1075 add_device_bounds( physDev, &rect );
1076 return X11DRV_PALETTE_ToLogical(physDev, pixel);
1080 /***********************************************************************
1081 * X11DRV_PaintRgn
1083 BOOL X11DRV_PaintRgn( PHYSDEV dev, HRGN hrgn )
1085 X11DRV_PDEVICE *physDev = get_x11drv_dev( dev );
1086 RECT rc;
1088 if (X11DRV_SetupGCForBrush( physDev ))
1090 unsigned int i;
1091 XRectangle *rect;
1092 RGNDATA *data = X11DRV_GetRegionData( hrgn, dev->hdc );
1094 if (!data) return FALSE;
1095 rect = (XRectangle *)data->Buffer;
1096 for (i = 0; i < data->rdh.nCount; i++)
1098 rect[i].x += physDev->dc_rect.left;
1099 rect[i].y += physDev->dc_rect.top;
1102 wine_tsx11_lock();
1103 XFillRectangles( gdi_display, physDev->drawable, physDev->gc, rect, data->rdh.nCount );
1104 wine_tsx11_unlock();
1105 HeapFree( GetProcessHeap(), 0, data );
1107 if (GetRgnBox( hrgn, &rc ))
1109 LPtoDP( dev->hdc, (POINT *)&rc, 2 );
1110 add_device_bounds( physDev, &rc );
1112 return TRUE;
1115 /**********************************************************************
1116 * X11DRV_Polygon
1118 BOOL X11DRV_Polygon( PHYSDEV dev, const POINT* pt, INT count )
1120 X11DRV_PDEVICE *physDev = get_x11drv_dev( dev );
1121 int i;
1122 POINT *points;
1123 XPoint *xpoints;
1125 points = HeapAlloc( GetProcessHeap(), 0, count * sizeof(*pt) );
1126 if (!points) return FALSE;
1127 memcpy( points, pt, count * sizeof(*pt) );
1128 LPtoDP( dev->hdc, points, count );
1129 add_pen_device_bounds( physDev, points, count );
1131 if (!(xpoints = HeapAlloc( GetProcessHeap(), 0, sizeof(XPoint) * (count+1) )))
1133 HeapFree( GetProcessHeap(), 0, points );
1134 return FALSE;
1136 for (i = 0; i < count; i++)
1138 xpoints[i].x = physDev->dc_rect.left + points[i].x;
1139 xpoints[i].y = physDev->dc_rect.top + points[i].y;
1141 xpoints[count] = xpoints[0];
1143 if (X11DRV_SetupGCForBrush( physDev ))
1145 wine_tsx11_lock();
1146 XFillPolygon( gdi_display, physDev->drawable, physDev->gc,
1147 xpoints, count+1, Complex, CoordModeOrigin);
1148 wine_tsx11_unlock();
1150 if (X11DRV_SetupGCForPen ( physDev ))
1152 wine_tsx11_lock();
1153 XDrawLines( gdi_display, physDev->drawable, physDev->gc,
1154 xpoints, count+1, CoordModeOrigin );
1155 wine_tsx11_unlock();
1158 HeapFree( GetProcessHeap(), 0, xpoints );
1159 HeapFree( GetProcessHeap(), 0, points );
1160 return TRUE;
1164 /**********************************************************************
1165 * X11DRV_PolyPolygon
1167 BOOL X11DRV_PolyPolygon( PHYSDEV dev, const POINT* pt, const INT* counts, UINT polygons )
1169 X11DRV_PDEVICE *physDev = get_x11drv_dev( dev );
1170 DWORD total = 0, max = 0, pos, i;
1171 POINT *points;
1172 BOOL ret = FALSE;
1174 for (i = 0; i < polygons; i++)
1176 if (counts[i] < 2) return FALSE;
1177 if (counts[i] > max) max = counts[i];
1178 total += counts[i];
1181 points = HeapAlloc( GetProcessHeap(), 0, total * sizeof(*pt) );
1182 if (!points) return FALSE;
1183 memcpy( points, pt, total * sizeof(*pt) );
1184 LPtoDP( dev->hdc, points, total );
1185 add_pen_device_bounds( physDev, points, total );
1187 if (X11DRV_SetupGCForBrush( physDev ))
1189 XRectangle *rect;
1190 HRGN hrgn = CreatePolyPolygonRgn( points, counts, polygons, GetPolyFillMode( dev->hdc ) );
1191 RGNDATA *data = X11DRV_GetRegionData( hrgn, 0 );
1193 DeleteObject( hrgn );
1194 if (!data) goto done;
1195 rect = (XRectangle *)data->Buffer;
1196 for (i = 0; i < data->rdh.nCount; i++)
1198 rect[i].x += physDev->dc_rect.left;
1199 rect[i].y += physDev->dc_rect.top;
1202 wine_tsx11_lock();
1203 XFillRectangles( gdi_display, physDev->drawable, physDev->gc, rect, data->rdh.nCount );
1204 wine_tsx11_unlock();
1205 HeapFree( GetProcessHeap(), 0, data );
1208 if (X11DRV_SetupGCForPen ( physDev ))
1210 XPoint *xpoints;
1211 int j;
1213 if (!(xpoints = HeapAlloc( GetProcessHeap(), 0, sizeof(XPoint) * (max + 1) ))) goto done;
1214 for (i = pos = 0; i < polygons; pos += counts[i++])
1216 for (j = 0; j < counts[i]; j++)
1218 xpoints[j].x = physDev->dc_rect.left + points[pos + j].x;
1219 xpoints[j].y = physDev->dc_rect.top + points[pos + j].y;
1221 xpoints[j] = xpoints[0];
1222 wine_tsx11_lock();
1223 XDrawLines( gdi_display, physDev->drawable, physDev->gc, xpoints, j + 1, CoordModeOrigin );
1224 wine_tsx11_unlock();
1226 HeapFree( GetProcessHeap(), 0, xpoints );
1228 ret = TRUE;
1230 done:
1231 HeapFree( GetProcessHeap(), 0, points );
1232 return ret;
1236 /**********************************************************************
1237 * X11DRV_PolyPolyline
1239 BOOL X11DRV_PolyPolyline( PHYSDEV dev, const POINT* pt, const DWORD* counts, DWORD polylines )
1241 X11DRV_PDEVICE *physDev = get_x11drv_dev( dev );
1242 DWORD total = 0, max = 0, pos, i, j;
1243 POINT *points;
1245 for (i = 0; i < polylines; i++)
1247 if (counts[i] < 2) return FALSE;
1248 if (counts[i] > max) max = counts[i];
1249 total += counts[i];
1252 points = HeapAlloc( GetProcessHeap(), 0, total * sizeof(*pt) );
1253 if (!points) return FALSE;
1254 memcpy( points, pt, total * sizeof(*pt) );
1255 LPtoDP( dev->hdc, points, total );
1256 add_pen_device_bounds( physDev, points, total );
1258 if (X11DRV_SetupGCForPen ( physDev ))
1260 XPoint *xpoints;
1262 if (!(xpoints = HeapAlloc( GetProcessHeap(), 0, sizeof(XPoint) * max )))
1264 HeapFree( GetProcessHeap(), 0, points );
1265 return FALSE;
1267 for (i = pos = 0; i < polylines; pos += counts[i++])
1269 for (j = 0; j < counts[i]; j++)
1271 xpoints[j].x = physDev->dc_rect.left + points[pos + j].x;
1272 xpoints[j].y = physDev->dc_rect.top + points[pos + j].y;
1274 wine_tsx11_lock();
1275 XDrawLines( gdi_display, physDev->drawable, physDev->gc, xpoints, j, CoordModeOrigin );
1276 wine_tsx11_unlock();
1278 HeapFree( GetProcessHeap(), 0, xpoints );
1280 HeapFree( GetProcessHeap(), 0, points );
1281 return TRUE;
1285 /**********************************************************************
1286 * X11DRV_InternalFloodFill
1288 * Internal helper function for flood fill.
1289 * (xorg,yorg) is the origin of the X image relative to the drawable.
1290 * (x,y) is relative to the origin of the X image.
1292 static void X11DRV_InternalFloodFill(XImage *image, X11DRV_PDEVICE *physDev,
1293 int x, int y,
1294 int xOrg, int yOrg,
1295 unsigned long pixel, WORD fillType, RECT *bounds )
1297 int left, right;
1299 #define TO_FLOOD(x,y) ((fillType == FLOODFILLBORDER) ? \
1300 (XGetPixel(image,x,y) != pixel) : \
1301 (XGetPixel(image,x,y) == pixel))
1303 if (!TO_FLOOD(x,y)) return;
1305 /* Find left and right boundaries */
1307 left = right = x;
1308 while ((left > 0) && TO_FLOOD( left-1, y )) left--;
1309 while ((right < image->width) && TO_FLOOD( right, y )) right++;
1310 bounds->left = min( bounds->left, left );
1311 bounds->top = min( bounds->top, y );
1312 bounds->right = max( bounds->right, right );
1313 bounds->bottom = max( bounds->bottom, y + 1 );
1314 XFillRectangle( gdi_display, physDev->drawable, physDev->gc,
1315 xOrg + left, yOrg + y, right-left, 1 );
1317 /* Set the pixels of this line so we don't fill it again */
1319 for (x = left; x < right; x++)
1321 if (fillType == FLOODFILLBORDER) XPutPixel( image, x, y, pixel );
1322 else XPutPixel( image, x, y, ~pixel );
1325 /* Fill the line above */
1327 if (--y >= 0)
1329 x = left;
1330 while (x < right)
1332 while ((x < right) && !TO_FLOOD(x,y)) x++;
1333 if (x >= right) break;
1334 while ((x < right) && TO_FLOOD(x,y)) x++;
1335 X11DRV_InternalFloodFill(image, physDev, x-1, y,
1336 xOrg, yOrg, pixel, fillType, bounds );
1340 /* Fill the line below */
1342 if ((y += 2) < image->height)
1344 x = left;
1345 while (x < right)
1347 while ((x < right) && !TO_FLOOD(x,y)) x++;
1348 if (x >= right) break;
1349 while ((x < right) && TO_FLOOD(x,y)) x++;
1350 X11DRV_InternalFloodFill(image, physDev, x-1, y,
1351 xOrg, yOrg, pixel, fillType, bounds );
1354 #undef TO_FLOOD
1358 static int ExtFloodFillXGetImageErrorHandler( Display *dpy, XErrorEvent *event, void *arg )
1360 return (event->request_code == X_GetImage && event->error_code == BadMatch);
1363 /**********************************************************************
1364 * X11DRV_ExtFloodFill
1366 BOOL X11DRV_ExtFloodFill( PHYSDEV dev, INT x, INT y, COLORREF color, UINT fillType )
1368 X11DRV_PDEVICE *physDev = get_x11drv_dev( dev );
1369 XImage *image;
1370 RECT rect, bounds;
1371 POINT pt;
1373 TRACE("X11DRV_ExtFloodFill %d,%d %06x %d\n", x, y, color, fillType );
1375 pt.x = x;
1376 pt.y = y;
1377 LPtoDP( dev->hdc, &pt, 1 );
1379 if (!physDev->region)
1381 rect.left = 0;
1382 rect.top = 0;
1383 rect.right = physDev->dc_rect.right - physDev->dc_rect.left;
1384 rect.bottom = physDev->dc_rect.bottom - physDev->dc_rect.top;
1386 else
1388 if (!PtInRegion( physDev->region, pt.x, pt.y )) return FALSE;
1389 GetRgnBox( physDev->region, &rect );
1390 rect.left = max( rect.left, 0 );
1391 rect.top = max( rect.top, 0 );
1392 rect.right = min( rect.right, physDev->dc_rect.right - physDev->dc_rect.left );
1393 rect.bottom = min( rect.bottom, physDev->dc_rect.bottom - physDev->dc_rect.top );
1395 if (pt.x < rect.left || pt.x >= rect.right || pt.y < rect.top || pt.y >= rect.bottom) return FALSE;
1397 X11DRV_expect_error( gdi_display, ExtFloodFillXGetImageErrorHandler, NULL );
1398 image = XGetImage( gdi_display, physDev->drawable,
1399 physDev->dc_rect.left + rect.left, physDev->dc_rect.top + rect.top,
1400 rect.right - rect.left, rect.bottom - rect.top,
1401 AllPlanes, ZPixmap );
1402 if(X11DRV_check_error()) image = NULL;
1403 if (!image) return FALSE;
1405 if (X11DRV_SetupGCForBrush( physDev ))
1407 unsigned long pixel = X11DRV_PALETTE_ToPhysical( physDev, color );
1409 reset_bounds( &bounds );
1411 wine_tsx11_lock();
1412 X11DRV_InternalFloodFill(image, physDev,
1413 pt.x - rect.left,
1414 pt.y - rect.top,
1415 physDev->dc_rect.left + rect.left,
1416 physDev->dc_rect.top + rect.top,
1417 pixel, fillType, &bounds );
1418 wine_tsx11_unlock();
1420 OffsetRect( &bounds, rect.left, rect.top );
1421 add_device_bounds( physDev, &bounds );
1424 wine_tsx11_lock();
1425 XDestroyImage( image );
1426 wine_tsx11_unlock();
1427 return TRUE;
1430 /**********************************************************************
1431 * X11DRV_GradientFill
1433 BOOL X11DRV_GradientFill( PHYSDEV dev, TRIVERTEX *vert_array, ULONG nvert,
1434 void *grad_array, ULONG ngrad, ULONG mode )
1436 X11DRV_PDEVICE *physdev = get_x11drv_dev( dev );
1437 const GRADIENT_RECT *rect = grad_array;
1438 TRIVERTEX v[2];
1439 POINT pt[2];
1440 RECT rc, bounds;
1441 unsigned int i;
1442 XGCValues val;
1444 /* <= 16-bpp use dithering */
1445 if (physdev->depth <= 16) goto fallback;
1447 switch (mode)
1449 case GRADIENT_FILL_RECT_H:
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 wine_tsx11_lock();
1456 XChangeGC( gdi_display, physdev->gc,
1457 GCFunction | GCLineWidth | GCLineStyle | GCCapStyle | GCFillStyle, &val );
1458 wine_tsx11_unlock();
1459 reset_bounds( &bounds );
1461 for (i = 0; i < ngrad; i++, rect++)
1463 int x, dx;
1465 v[0] = vert_array[rect->UpperLeft];
1466 v[1] = vert_array[rect->LowerRight];
1467 pt[0].x = v[0].x;
1468 pt[0].y = v[0].y;
1469 pt[1].x = v[1].x;
1470 pt[1].y = v[1].y;
1471 LPtoDP( dev->hdc, pt, 2 );
1472 dx = pt[1].x - pt[0].x;
1473 if (!dx) continue;
1474 if (dx < 0) /* swap the colors */
1476 v[0] = vert_array[rect->LowerRight];
1477 v[1] = vert_array[rect->UpperLeft];
1478 dx = -dx;
1480 rc.left = min( pt[0].x, pt[1].x );
1481 rc.top = min( pt[0].y, pt[1].y );
1482 rc.right = max( pt[0].x, pt[1].x );
1483 rc.bottom = max( pt[0].y, pt[1].y );
1484 add_bounds_rect( &bounds, &rc );
1485 for (x = 0; x < dx; x++)
1487 int color = X11DRV_PALETTE_ToPhysical( physdev,
1488 RGB( (v[0].Red * (dx - x) + v[1].Red * x) / dx / 256,
1489 (v[0].Green * (dx - x) + v[1].Green * x) / dx / 256,
1490 (v[0].Blue * (dx - x) + v[1].Blue * x) / dx / 256) );
1492 wine_tsx11_lock();
1493 XSetForeground( gdi_display, physdev->gc, color );
1494 XDrawLine( gdi_display, physdev->drawable, physdev->gc,
1495 physdev->dc_rect.left + rc.left + x, physdev->dc_rect.top + rc.top,
1496 physdev->dc_rect.left + rc.left + x, physdev->dc_rect.top + rc.bottom );
1497 wine_tsx11_unlock();
1500 add_device_bounds( physdev, &bounds );
1501 return TRUE;
1503 case GRADIENT_FILL_RECT_V:
1504 val.function = GXcopy;
1505 val.fill_style = FillSolid;
1506 val.line_width = 1;
1507 val.cap_style = CapNotLast;
1508 val.line_style = LineSolid;
1509 wine_tsx11_lock();
1510 XChangeGC( gdi_display, physdev->gc,
1511 GCFunction | GCLineWidth | GCLineStyle | GCCapStyle | GCFillStyle, &val );
1512 wine_tsx11_unlock();
1513 reset_bounds( &bounds );
1515 for (i = 0; i < ngrad; i++, rect++)
1517 int y, dy;
1519 v[0] = vert_array[rect->UpperLeft];
1520 v[1] = vert_array[rect->LowerRight];
1521 pt[0].x = v[0].x;
1522 pt[0].y = v[0].y;
1523 pt[1].x = v[1].x;
1524 pt[1].y = v[1].y;
1525 LPtoDP( dev->hdc, pt, 2 );
1526 dy = pt[1].y - pt[0].y;
1527 if (!dy) continue;
1528 if (dy < 0) /* swap the colors */
1530 v[0] = vert_array[rect->LowerRight];
1531 v[1] = vert_array[rect->UpperLeft];
1532 dy = -dy;
1534 rc.left = min( pt[0].x, pt[1].x );
1535 rc.top = min( pt[0].y, pt[1].y );
1536 rc.right = max( pt[0].x, pt[1].x );
1537 rc.bottom = max( pt[0].y, pt[1].y );
1538 add_bounds_rect( &bounds, &rc );
1539 for (y = 0; y < dy; y++)
1541 int color = X11DRV_PALETTE_ToPhysical( physdev,
1542 RGB( (v[0].Red * (dy - y) + v[1].Red * y) / dy / 256,
1543 (v[0].Green * (dy - y) + v[1].Green * y) / dy / 256,
1544 (v[0].Blue * (dy - y) + v[1].Blue * y) / dy / 256) );
1546 wine_tsx11_lock();
1547 XSetForeground( gdi_display, physdev->gc, color );
1548 XDrawLine( gdi_display, physdev->drawable, physdev->gc,
1549 physdev->dc_rect.left + rc.left, physdev->dc_rect.top + rc.top + y,
1550 physdev->dc_rect.left + rc.right, physdev->dc_rect.top + rc.top + y );
1551 wine_tsx11_unlock();
1554 add_device_bounds( physdev, &bounds );
1555 return TRUE;
1558 fallback:
1559 dev = GET_NEXT_PHYSDEV( dev, pGradientFill );
1560 return dev->funcs->pGradientFill( dev, vert_array, nvert, grad_array, ngrad, mode );
1563 static unsigned char *get_icm_profile( unsigned long *size )
1565 Atom type;
1566 int format;
1567 unsigned long count, remaining;
1568 unsigned char *profile, *ret = NULL;
1570 wine_tsx11_lock();
1571 XGetWindowProperty( gdi_display, DefaultRootWindow(gdi_display),
1572 x11drv_atom(_ICC_PROFILE), 0, ~0UL, False, AnyPropertyType,
1573 &type, &format, &count, &remaining, &profile );
1574 *size = get_property_size( format, count );
1575 if (format && count)
1577 if ((ret = HeapAlloc( GetProcessHeap(), 0, *size ))) memcpy( ret, profile, *size );
1578 XFree( profile );
1580 wine_tsx11_unlock();
1581 return ret;
1584 typedef struct
1586 unsigned int unknown[6];
1587 unsigned int state[5];
1588 unsigned int count[2];
1589 unsigned char buffer[64];
1590 } sha_ctx;
1592 extern void WINAPI A_SHAInit( sha_ctx * );
1593 extern void WINAPI A_SHAUpdate( sha_ctx *, const unsigned char *, unsigned int );
1594 extern void WINAPI A_SHAFinal( sha_ctx *, unsigned char * );
1596 static const WCHAR mntr_key[] =
1597 {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
1598 'W','i','n','d','o','w','s',' ','N','T','\\','C','u','r','r','e','n','t',
1599 'V','e','r','s','i','o','n','\\','I','C','M','\\','m','n','t','r',0};
1601 static const WCHAR color_path[] =
1602 {'\\','s','p','o','o','l','\\','d','r','i','v','e','r','s','\\','c','o','l','o','r','\\',0};
1604 /***********************************************************************
1605 * GetICMProfile (X11DRV.@)
1607 BOOL X11DRV_GetICMProfile( PHYSDEV dev, LPDWORD size, LPWSTR filename )
1609 static const WCHAR srgb[] =
1610 {'s','R','G','B',' ','C','o','l','o','r',' ','S','p','a','c','e',' ',
1611 'P','r','o','f','i','l','e','.','i','c','m',0};
1612 HKEY hkey;
1613 DWORD required, len;
1614 WCHAR profile[MAX_PATH], fullname[2*MAX_PATH + sizeof(color_path)/sizeof(WCHAR)];
1615 unsigned char *buffer;
1616 unsigned long buflen;
1618 if (!size) return FALSE;
1620 GetSystemDirectoryW( fullname, MAX_PATH );
1621 strcatW( fullname, color_path );
1623 len = sizeof(profile)/sizeof(WCHAR);
1624 if (!RegCreateKeyExW( HKEY_LOCAL_MACHINE, mntr_key, 0, NULL, 0, KEY_ALL_ACCESS, NULL, &hkey, NULL ) &&
1625 !RegEnumValueW( hkey, 0, profile, &len, NULL, NULL, NULL, NULL )) /* FIXME handle multiple values */
1627 strcatW( fullname, profile );
1628 RegCloseKey( hkey );
1630 else if ((buffer = get_icm_profile( &buflen )))
1632 static const WCHAR fmt[] = {'%','0','2','x',0};
1633 static const WCHAR icm[] = {'.','i','c','m',0};
1635 unsigned char sha1sum[20];
1636 unsigned int i;
1637 sha_ctx ctx;
1638 HANDLE file;
1640 A_SHAInit( &ctx );
1641 A_SHAUpdate( &ctx, buffer, buflen );
1642 A_SHAFinal( &ctx, sha1sum );
1644 for (i = 0; i < sizeof(sha1sum); i++) sprintfW( &profile[i * 2], fmt, sha1sum[i] );
1645 memcpy( &profile[i * 2], icm, sizeof(icm) );
1647 strcatW( fullname, profile );
1648 file = CreateFileW( fullname, GENERIC_WRITE, 0, NULL, CREATE_NEW, 0, 0 );
1649 if (file != INVALID_HANDLE_VALUE)
1651 DWORD written;
1653 if (!WriteFile( file, buffer, buflen, &written, NULL ) || written != buflen)
1654 ERR( "Unable to write color profile\n" );
1655 CloseHandle( file );
1657 HeapFree( GetProcessHeap(), 0, buffer );
1659 else strcatW( fullname, srgb );
1661 required = strlenW( fullname ) + 1;
1662 if (*size < required)
1664 *size = required;
1665 SetLastError( ERROR_INSUFFICIENT_BUFFER );
1666 return FALSE;
1668 if (filename)
1670 strcpyW( filename, fullname );
1671 if (GetFileAttributesW( filename ) == INVALID_FILE_ATTRIBUTES)
1672 WARN( "color profile not found\n" );
1674 *size = required;
1675 return TRUE;
1678 /***********************************************************************
1679 * EnumICMProfiles (X11DRV.@)
1681 INT X11DRV_EnumICMProfiles( PHYSDEV dev, ICMENUMPROCW proc, LPARAM lparam )
1683 X11DRV_PDEVICE *physDev = get_x11drv_dev( dev );
1684 HKEY hkey;
1685 DWORD len_sysdir, len_path, len, index = 0;
1686 WCHAR sysdir[MAX_PATH], *profile;
1687 LONG res;
1688 INT ret;
1690 TRACE("%p, %p, %ld\n", physDev, proc, lparam);
1692 if (RegOpenKeyExW( HKEY_LOCAL_MACHINE, mntr_key, 0, KEY_ALL_ACCESS, &hkey ))
1693 return -1;
1695 len_sysdir = GetSystemDirectoryW( sysdir, MAX_PATH );
1696 len_path = len_sysdir + sizeof(color_path) / sizeof(color_path[0]) - 1;
1697 len = 64;
1698 for (;;)
1700 if (!(profile = HeapAlloc( GetProcessHeap(), 0, (len_path + len) * sizeof(WCHAR) )))
1702 RegCloseKey( hkey );
1703 return -1;
1705 res = RegEnumValueW( hkey, index, profile + len_path, &len, NULL, NULL, NULL, NULL );
1706 while (res == ERROR_MORE_DATA)
1708 len *= 2;
1709 HeapFree( GetProcessHeap(), 0, profile );
1710 if (!(profile = HeapAlloc( GetProcessHeap(), 0, (len_path + len) * sizeof(WCHAR) )))
1712 RegCloseKey( hkey );
1713 return -1;
1715 res = RegEnumValueW( hkey, index, profile + len_path, &len, NULL, NULL, NULL, NULL );
1717 if (res != ERROR_SUCCESS)
1719 HeapFree( GetProcessHeap(), 0, profile );
1720 break;
1722 memcpy( profile, sysdir, len_sysdir * sizeof(WCHAR) );
1723 memcpy( profile + len_sysdir, color_path, sizeof(color_path) - sizeof(WCHAR) );
1724 ret = proc( profile, lparam );
1725 HeapFree( GetProcessHeap(), 0, profile );
1726 if (!ret) break;
1727 index++;
1729 RegCloseKey( hkey );
1730 return -1;