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
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 */
67 GXorInverted
, /* R2_MERGENOTPEN */
68 GXcopy
, /* R2_COPYPEN */
69 GXorReverse
, /* R2_MERGEPENNOT */
70 GXor
, /* R2_MERGEPEN */
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
)
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 */
91 LPtoDP( hdc
, (POINT
*)&rect
, 2 );
92 if (rect
.left
> rect
.right
)
95 rect
.left
= rect
.right
;
98 if (rect
.top
> rect
.bottom
)
101 rect
.top
= rect
.bottom
;
107 static void add_pen_device_bounds( X11DRV_PDEVICE
*dev
, const POINT
*points
, int count
)
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
)
122 if (dev
->pen
.endcap
== PS_ENDCAP_SQUARE
) width
= (width
* 3 + 1) / 2;
126 if (dev
->pen
.endcap
== PS_ENDCAP_SQUARE
) width
-= width
/ 4;
127 else width
= (width
+ 1) / 2;
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
);
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
)
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
);
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
;
187 if (rect
[i
].bottom
< rect
[i
].top
)
189 INT tmp
= rect
[i
].bottom
;
190 rect
[i
].bottom
= rect
[i
].top
;
196 if (sizeof(XRectangle
) > sizeof(RECT
))
199 /* need to start from the end */
200 xrect
+= data
->rdh
.nCount
;
201 for (j
= data
->rdh
.nCount
-1; j
>= 0; 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;
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
) );
222 for (i
= 0; i
< data
->rdh
.nCount
; 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);
235 data
->rdh
.nCount
= xrect
- (XRectangle
*)data
->Buffer
;
241 /***********************************************************************
242 * update_x11_clipping
244 static void update_x11_clipping( X11DRV_PDEVICE
*physDev
, HRGN rgn
)
251 XSetClipMask( gdi_display
, physDev
->gc
, None
);
254 else if ((data
= X11DRV_GetRegionData( rgn
, 0 )))
257 XSetClipRectangles( gdi_display
, physDev
->gc
, physDev
->dc_rect
.left
, physDev
->dc_rect
.top
,
258 (XRectangle
*)data
->Buffer
, data
->rdh
.nCount
, YXBanded
);
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
)
275 if (!rgn
) return FALSE
;
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
);
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
)
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
) );
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
)
360 case FillOpaqueStippled
:
361 if (GetBkMode(physDev
->dev
.hdc
)==OPAQUE
) val
.fill_style
= FillOpaqueStippled
;
362 val
.stipple
= physDev
->brush
.pixmap
;
367 if (fMapColors
&& X11DRV_PALETTE_XPixelToPalette
)
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
);
384 else val
.tile
= physDev
->brush
.pixmap
;
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
;
397 XChangeGC( gdi_display
, gc
,
398 GCFunction
| GCForeground
| GCBackground
| GCFillStyle
|
399 GCFillRule
| GCTileStipXOrigin
| GCTileStipYOrigin
| mask
,
401 if (pixmap
) XFreePixmap( gdi_display
, pixmap
);
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
)
428 UINT rop2
= GetROP2(physDev
->dev
.hdc
);
430 if (physDev
->pen
.style
== PS_NULL
) return FALSE
;
435 val
.foreground
= BlackPixel( gdi_display
, DefaultScreen(gdi_display
) );
436 val
.function
= GXcopy
;
439 val
.foreground
= WhitePixel( gdi_display
, DefaultScreen(gdi_display
) );
440 val
.function
= GXcopy
;
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
;
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
;
461 switch (physDev
->pen
.endcap
)
463 case PS_ENDCAP_SQUARE
:
464 val
.cap_style
= CapProjecting
;
467 val
.cap_style
= CapButt
;
469 case PS_ENDCAP_ROUND
:
471 val
.cap_style
= CapRound
;
474 switch (physDev
->pen
.linejoin
)
477 val
.join_style
= JoinBevel
;
480 val
.join_style
= JoinMiter
;
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
;
491 val
.line_style
= LineSolid
;
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
);
504 /***********************************************************************
507 * Performs a world-to-viewport transformation on the specified width.
509 INT
X11DRV_XWStoDS( HDC hdc
, INT width
)
517 LPtoDP( hdc
, pt
, 2 );
518 return pt
[1].x
- pt
[0].x
;
521 /***********************************************************************
524 * Performs a world-to-viewport transformation on the specified height.
526 INT
X11DRV_YWStoDS( HDC hdc
, INT height
)
534 LPtoDP( hdc
, pt
, 2 );
535 return pt
[1].y
- pt
[0].y
;
538 /***********************************************************************
541 BOOL
X11DRV_LineTo( PHYSDEV dev
, INT x
, INT y
)
543 X11DRV_PDEVICE
*physDev
= get_x11drv_dev( dev
);
546 GetCurrentPositionEx( dev
->hdc
, &pt
[0] );
549 LPtoDP( dev
->hdc
, pt
, 2 );
550 add_pen_device_bounds( physDev
, pt
, 2 );
552 if (X11DRV_SetupGCForPen( physDev
))
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
);
565 /***********************************************************************
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
;
578 double start_angle
, end_angle
;
581 RECT rc
= get_device_rect( dev
->hdc
, left
, top
, right
, bottom
);
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;
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) */
623 else /* notorious cases */
624 if ((start_angle
== PI
)&&( end_angle
<0))
627 if ((end_angle
== PI
)&&( start_angle
<0))
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
)) {
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
);
644 /* Draw arc and lines */
646 if (X11DRV_SetupGCForPen( physDev
))
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
);
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)
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
--;
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
--;
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
--;
697 if( dy1
>0) points
[3].y
--;
698 if(((rc
.right
-rc
.left
) | -2) == -2 ) points
[2].x
--;
701 if( dx1
* 64 < dy1
* -37 ) points
[3].x
--;
705 XDrawLines( gdi_display
, physDev
->drawable
, physDev
->gc
,
706 points
, lines
+1, CoordModeOrigin
);
711 physDev
->pen
.width
= oldwidth
;
712 add_pen_device_bounds( physDev
, (POINT
*)&rc
, 2 );
717 /***********************************************************************
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 /***********************************************************************
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 /***********************************************************************
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 /***********************************************************************
749 BOOL
X11DRV_Ellipse( PHYSDEV dev
, INT left
, INT top
, INT right
, INT bottom
)
751 X11DRV_PDEVICE
*physDev
= get_x11drv_dev( dev
);
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;
768 rc
.bottom
-= (width
- 1) / 2;
770 if(width
== 0) width
= 1; /* more accurate */
771 physDev
->pen
.width
= width
;
773 if (X11DRV_SetupGCForBrush( physDev
))
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 );
781 if (X11DRV_SetupGCForPen( physDev
))
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 );
790 physDev
->pen
.width
= oldwidth
;
791 add_pen_device_bounds( physDev
, (POINT
*)&rc
, 2 );
796 /***********************************************************************
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;
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
;
830 if ((rc
.right
>= rc
.left
+ width
) && (rc
.bottom
>= rc
.top
+ width
))
832 if (X11DRV_SetupGCForBrush( physDev
))
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
);
842 if (X11DRV_SetupGCForPen( physDev
))
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
);
851 physDev
->pen
.width
= oldwidth
;
852 physDev
->pen
.linejoin
= oldjoinstyle
;
853 add_pen_device_bounds( physDev
, (POINT
*)&rc
, 2 );
857 /***********************************************************************
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
;
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
))
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;
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
))
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,
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,
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 );
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,
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);
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
))
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 );
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 );
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 );
1052 /***********************************************************************
1055 COLORREF
X11DRV_SetPixel( PHYSDEV dev
, INT x
, INT y
, COLORREF color
)
1057 X11DRV_PDEVICE
*physDev
= get_x11drv_dev( dev
);
1058 unsigned long pixel
;
1064 LPtoDP( dev
->hdc
, &pt
, 1 );
1065 pixel
= X11DRV_PALETTE_ToPhysical( physDev
, color
);
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 /***********************************************************************
1083 BOOL
X11DRV_PaintRgn( PHYSDEV dev
, HRGN hrgn
)
1085 X11DRV_PDEVICE
*physDev
= get_x11drv_dev( dev
);
1088 if (X11DRV_SetupGCForBrush( physDev
))
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
;
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
);
1115 /**********************************************************************
1118 BOOL
X11DRV_Polygon( PHYSDEV dev
, const POINT
* pt
, INT count
)
1120 X11DRV_PDEVICE
*physDev
= get_x11drv_dev( dev
);
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
);
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
))
1146 XFillPolygon( gdi_display
, physDev
->drawable
, physDev
->gc
,
1147 xpoints
, count
+1, Complex
, CoordModeOrigin
);
1148 wine_tsx11_unlock();
1150 if (X11DRV_SetupGCForPen ( physDev
))
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
);
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
;
1174 for (i
= 0; i
< polygons
; i
++)
1176 if (counts
[i
] < 2) return FALSE
;
1177 if (counts
[i
] > max
) max
= 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
))
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
;
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
))
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];
1223 XDrawLines( gdi_display
, physDev
->drawable
, physDev
->gc
, xpoints
, j
+ 1, CoordModeOrigin
);
1224 wine_tsx11_unlock();
1226 HeapFree( GetProcessHeap(), 0, xpoints
);
1231 HeapFree( GetProcessHeap(), 0, points
);
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
;
1245 for (i
= 0; i
< polylines
; i
++)
1247 if (counts
[i
] < 2) return FALSE
;
1248 if (counts
[i
] > max
) max
= 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
))
1262 if (!(xpoints
= HeapAlloc( GetProcessHeap(), 0, sizeof(XPoint
) * max
)))
1264 HeapFree( GetProcessHeap(), 0, points
);
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
;
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
);
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
,
1295 unsigned long pixel
, WORD fillType
, RECT
*bounds
)
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 */
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 */
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
)
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
);
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
);
1373 TRACE("X11DRV_ExtFloodFill %d,%d %06x %d\n", x
, y
, color
, fillType
);
1377 LPtoDP( dev
->hdc
, &pt
, 1 );
1379 if (!physDev
->region
)
1383 rect
.right
= physDev
->dc_rect
.right
- physDev
->dc_rect
.left
;
1384 rect
.bottom
= physDev
->dc_rect
.bottom
- physDev
->dc_rect
.top
;
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
);
1412 X11DRV_InternalFloodFill(image
, physDev
,
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
);
1425 XDestroyImage( image
);
1426 wine_tsx11_unlock();
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
;
1444 /* <= 16-bpp use dithering */
1445 if (physdev
->depth
<= 16) goto fallback
;
1449 case GRADIENT_FILL_RECT_H
:
1450 val
.function
= GXcopy
;
1451 val
.fill_style
= FillSolid
;
1453 val
.cap_style
= CapNotLast
;
1454 val
.line_style
= LineSolid
;
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
++)
1465 v
[0] = vert_array
[rect
->UpperLeft
];
1466 v
[1] = vert_array
[rect
->LowerRight
];
1471 LPtoDP( dev
->hdc
, pt
, 2 );
1472 dx
= pt
[1].x
- pt
[0].x
;
1474 if (dx
< 0) /* swap the colors */
1476 v
[0] = vert_array
[rect
->LowerRight
];
1477 v
[1] = vert_array
[rect
->UpperLeft
];
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) );
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
);
1503 case GRADIENT_FILL_RECT_V
:
1504 val
.function
= GXcopy
;
1505 val
.fill_style
= FillSolid
;
1507 val
.cap_style
= CapNotLast
;
1508 val
.line_style
= LineSolid
;
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
++)
1519 v
[0] = vert_array
[rect
->UpperLeft
];
1520 v
[1] = vert_array
[rect
->LowerRight
];
1525 LPtoDP( dev
->hdc
, pt
, 2 );
1526 dy
= pt
[1].y
- pt
[0].y
;
1528 if (dy
< 0) /* swap the colors */
1530 v
[0] = vert_array
[rect
->LowerRight
];
1531 v
[1] = vert_array
[rect
->UpperLeft
];
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) );
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
);
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
)
1567 unsigned long count
, remaining
;
1568 unsigned char *profile
, *ret
= NULL
;
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
);
1580 wine_tsx11_unlock();
1586 unsigned int unknown
[6];
1587 unsigned int state
[5];
1588 unsigned int count
[2];
1589 unsigned char buffer
[64];
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};
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];
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
)
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
)
1665 SetLastError( ERROR_INSUFFICIENT_BUFFER
);
1670 strcpyW( filename
, fullname
);
1671 if (GetFileAttributesW( filename
) == INVALID_FILE_ATTRIBUTES
)
1672 WARN( "color profile not found\n" );
1678 /***********************************************************************
1679 * EnumICMProfiles (X11DRV.@)
1681 INT
X11DRV_EnumICMProfiles( PHYSDEV dev
, ICMENUMPROCW proc
, LPARAM lparam
)
1683 X11DRV_PDEVICE
*physDev
= get_x11drv_dev( dev
);
1685 DWORD len_sysdir
, len_path
, len
, index
= 0;
1686 WCHAR sysdir
[MAX_PATH
], *profile
;
1690 TRACE("%p, %p, %ld\n", physDev
, proc
, lparam
);
1692 if (RegOpenKeyExW( HKEY_LOCAL_MACHINE
, mntr_key
, 0, KEY_ALL_ACCESS
, &hkey
))
1695 len_sysdir
= GetSystemDirectoryW( sysdir
, MAX_PATH
);
1696 len_path
= len_sysdir
+ sizeof(color_path
) / sizeof(color_path
[0]) - 1;
1700 if (!(profile
= HeapAlloc( GetProcessHeap(), 0, (len_path
+ len
) * sizeof(WCHAR
) )))
1702 RegCloseKey( hkey
);
1705 res
= RegEnumValueW( hkey
, index
, profile
+ len_path
, &len
, NULL
, NULL
, NULL
, NULL
);
1706 while (res
== ERROR_MORE_DATA
)
1709 HeapFree( GetProcessHeap(), 0, profile
);
1710 if (!(profile
= HeapAlloc( GetProcessHeap(), 0, (len_path
+ len
) * sizeof(WCHAR
) )))
1712 RegCloseKey( hkey
);
1715 res
= RegEnumValueW( hkey
, index
, profile
+ len_path
, &len
, NULL
, NULL
, NULL
, NULL
);
1717 if (res
!= ERROR_SUCCESS
)
1719 HeapFree( GetProcessHeap(), 0, profile
);
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
);
1729 RegCloseKey( hkey
);