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
)
250 XSetClipMask( gdi_display
, physDev
->gc
, None
);
252 else if ((data
= X11DRV_GetRegionData( rgn
, 0 )))
254 XSetClipRectangles( gdi_display
, physDev
->gc
, physDev
->dc_rect
.left
, physDev
->dc_rect
.top
,
255 (XRectangle
*)data
->Buffer
, data
->rdh
.nCount
, YXBanded
);
256 HeapFree( GetProcessHeap(), 0, data
);
261 /***********************************************************************
262 * add_extra_clipping_region
264 * Temporarily add a region to the current clipping region.
265 * The region must be restored with restore_clipping_region.
267 BOOL
add_extra_clipping_region( X11DRV_PDEVICE
*dev
, HRGN rgn
)
271 if (!rgn
) return FALSE
;
274 if (!(clip
= CreateRectRgn( 0, 0, 0, 0 ))) return FALSE
;
275 CombineRgn( clip
, dev
->region
, rgn
, RGN_AND
);
276 update_x11_clipping( dev
, clip
);
277 DeleteObject( clip
);
279 else update_x11_clipping( dev
, rgn
);
284 /***********************************************************************
285 * restore_clipping_region
287 void restore_clipping_region( X11DRV_PDEVICE
*dev
)
289 update_x11_clipping( dev
, dev
->region
);
293 /***********************************************************************
294 * X11DRV_SetDeviceClipping
296 void X11DRV_SetDeviceClipping( PHYSDEV dev
, HRGN rgn
)
298 X11DRV_PDEVICE
*physDev
= get_x11drv_dev( dev
);
300 physDev
->region
= rgn
;
301 update_x11_clipping( physDev
, rgn
);
305 /***********************************************************************
306 * X11DRV_SetupGCForPatBlt
308 * Setup the GC for a PatBlt operation using current brush.
309 * If fMapColors is TRUE, X pixels are mapped to Windows colors.
310 * Return FALSE if brush is BS_NULL, TRUE otherwise.
312 BOOL
X11DRV_SetupGCForPatBlt( X11DRV_PDEVICE
*physDev
, GC gc
, BOOL fMapColors
)
319 if (physDev
->brush
.style
== BS_NULL
) return FALSE
;
320 if (physDev
->brush
.pixel
== -1)
322 /* Special case used for monochrome pattern brushes.
323 * We need to swap foreground and background because
324 * Windows does it the wrong way...
326 val
.foreground
= X11DRV_PALETTE_ToPhysical( physDev
, GetBkColor(physDev
->dev
.hdc
) );
327 val
.background
= X11DRV_PALETTE_ToPhysical( physDev
, GetTextColor(physDev
->dev
.hdc
) );
331 val
.foreground
= physDev
->brush
.pixel
;
332 val
.background
= X11DRV_PALETTE_ToPhysical( physDev
, GetBkColor(physDev
->dev
.hdc
) );
334 if (fMapColors
&& X11DRV_PALETTE_XPixelToPalette
)
336 val
.foreground
= X11DRV_PALETTE_XPixelToPalette
[val
.foreground
];
337 val
.background
= X11DRV_PALETTE_XPixelToPalette
[val
.background
];
340 val
.function
= X11DRV_XROPfunction
[GetROP2(physDev
->dev
.hdc
)-1];
342 ** Let's replace GXinvert by GXxor with (black xor white)
343 ** This solves the selection color and leak problems in excel
344 ** FIXME : Let's do that only if we work with X-pixels, not with Win-pixels
346 if (val
.function
== GXinvert
)
348 val
.foreground
= (WhitePixel( gdi_display
, DefaultScreen(gdi_display
) ) ^
349 BlackPixel( gdi_display
, DefaultScreen(gdi_display
) ));
350 val
.function
= GXxor
;
352 val
.fill_style
= physDev
->brush
.fillStyle
;
353 switch(val
.fill_style
)
356 case FillOpaqueStippled
:
357 if (GetBkMode(physDev
->dev
.hdc
)==OPAQUE
) val
.fill_style
= FillOpaqueStippled
;
358 val
.stipple
= physDev
->brush
.pixmap
;
363 if (fMapColors
&& X11DRV_PALETTE_XPixelToPalette
)
368 pixmap
= XCreatePixmap( gdi_display
, root_window
, 8, 8, physDev
->depth
);
369 image
= XGetImage( gdi_display
, physDev
->brush
.pixmap
, 0, 0, 8, 8,
370 AllPlanes
, ZPixmap
);
371 for (y
= 0; y
< 8; y
++)
372 for (x
= 0; x
< 8; x
++)
373 XPutPixel( image
, x
, y
,
374 X11DRV_PALETTE_XPixelToPalette
[XGetPixel( image
, x
, y
)] );
375 XPutImage( gdi_display
, pixmap
, gc
, image
, 0, 0, 0, 0, 8, 8 );
376 XDestroyImage( image
);
380 else val
.tile
= physDev
->brush
.pixmap
;
388 GetBrushOrgEx( physDev
->dev
.hdc
, &pt
);
389 val
.ts_x_origin
= physDev
->dc_rect
.left
+ pt
.x
;
390 val
.ts_y_origin
= physDev
->dc_rect
.top
+ pt
.y
;
391 val
.fill_rule
= (GetPolyFillMode(physDev
->dev
.hdc
) == WINDING
) ? WindingRule
: EvenOddRule
;
392 XChangeGC( gdi_display
, gc
,
393 GCFunction
| GCForeground
| GCBackground
| GCFillStyle
|
394 GCFillRule
| GCTileStipXOrigin
| GCTileStipYOrigin
| mask
,
396 if (pixmap
) XFreePixmap( gdi_display
, pixmap
);
401 /***********************************************************************
402 * X11DRV_SetupGCForBrush
404 * Setup physDev->gc for drawing operations using current brush.
405 * Return FALSE if brush is BS_NULL, TRUE otherwise.
407 BOOL
X11DRV_SetupGCForBrush( X11DRV_PDEVICE
*physDev
)
409 return X11DRV_SetupGCForPatBlt( physDev
, physDev
->gc
, FALSE
);
413 /***********************************************************************
414 * X11DRV_SetupGCForPen
416 * Setup physDev->gc for drawing operations using current pen.
417 * Return FALSE if pen is PS_NULL, TRUE otherwise.
419 static BOOL
X11DRV_SetupGCForPen( X11DRV_PDEVICE
*physDev
)
422 UINT rop2
= GetROP2(physDev
->dev
.hdc
);
424 if (physDev
->pen
.style
== PS_NULL
) return FALSE
;
429 val
.foreground
= BlackPixel( gdi_display
, DefaultScreen(gdi_display
) );
430 val
.function
= GXcopy
;
433 val
.foreground
= WhitePixel( gdi_display
, DefaultScreen(gdi_display
) );
434 val
.function
= GXcopy
;
437 val
.foreground
= physDev
->pen
.pixel
;
438 /* It is very unlikely someone wants to XOR with 0 */
439 /* This fixes the rubber-drawings in paintbrush */
440 if (val
.foreground
== 0)
441 val
.foreground
= (WhitePixel( gdi_display
, DefaultScreen(gdi_display
) ) ^
442 BlackPixel( gdi_display
, DefaultScreen(gdi_display
) ));
443 val
.function
= GXxor
;
446 val
.foreground
= physDev
->pen
.pixel
;
447 val
.function
= X11DRV_XROPfunction
[rop2
-1];
449 val
.background
= X11DRV_PALETTE_ToPhysical( physDev
, GetBkColor(physDev
->dev
.hdc
) );
450 val
.fill_style
= FillSolid
;
451 val
.line_width
= physDev
->pen
.width
;
452 if (val
.line_width
<= 1) {
453 val
.cap_style
= CapNotLast
;
455 switch (physDev
->pen
.endcap
)
457 case PS_ENDCAP_SQUARE
:
458 val
.cap_style
= CapProjecting
;
461 val
.cap_style
= CapButt
;
463 case PS_ENDCAP_ROUND
:
465 val
.cap_style
= CapRound
;
468 switch (physDev
->pen
.linejoin
)
471 val
.join_style
= JoinBevel
;
474 val
.join_style
= JoinMiter
;
478 val
.join_style
= JoinRound
;
481 if (physDev
->pen
.dash_len
)
482 val
.line_style
= ((GetBkMode(physDev
->dev
.hdc
) == OPAQUE
) && (!physDev
->pen
.ext
))
483 ? LineDoubleDash
: LineOnOffDash
;
485 val
.line_style
= LineSolid
;
487 if (physDev
->pen
.dash_len
)
488 XSetDashes( gdi_display
, physDev
->gc
, 0, physDev
->pen
.dashes
, physDev
->pen
.dash_len
);
489 XChangeGC( gdi_display
, physDev
->gc
,
490 GCFunction
| GCForeground
| GCBackground
| GCLineWidth
|
491 GCLineStyle
| GCCapStyle
| GCJoinStyle
| GCFillStyle
, &val
);
496 /***********************************************************************
499 * Performs a world-to-viewport transformation on the specified width.
501 INT
X11DRV_XWStoDS( HDC hdc
, INT width
)
509 LPtoDP( hdc
, pt
, 2 );
510 return pt
[1].x
- pt
[0].x
;
513 /***********************************************************************
516 * Performs a world-to-viewport transformation on the specified height.
518 INT
X11DRV_YWStoDS( HDC hdc
, INT height
)
526 LPtoDP( hdc
, pt
, 2 );
527 return pt
[1].y
- pt
[0].y
;
530 /***********************************************************************
533 BOOL
X11DRV_LineTo( PHYSDEV dev
, INT x
, INT y
)
535 X11DRV_PDEVICE
*physDev
= get_x11drv_dev( dev
);
538 GetCurrentPositionEx( dev
->hdc
, &pt
[0] );
541 LPtoDP( dev
->hdc
, pt
, 2 );
542 add_pen_device_bounds( physDev
, pt
, 2 );
544 if (X11DRV_SetupGCForPen( physDev
))
545 XDrawLine(gdi_display
, physDev
->drawable
, physDev
->gc
,
546 physDev
->dc_rect
.left
+ pt
[0].x
, physDev
->dc_rect
.top
+ pt
[0].y
,
547 physDev
->dc_rect
.left
+ pt
[1].x
, physDev
->dc_rect
.top
+ pt
[1].y
);
553 /***********************************************************************
556 * Helper functions for Arc(), Chord() and Pie().
557 * 'lines' is the number of lines to draw: 0 for Arc, 1 for Chord, 2 for Pie.
560 static BOOL
X11DRV_DrawArc( PHYSDEV dev
, INT left
, INT top
, INT right
, INT bottom
,
561 INT xstart
, INT ystart
, INT xend
, INT yend
, INT lines
)
563 X11DRV_PDEVICE
*physDev
= get_x11drv_dev( dev
);
564 INT xcenter
, ycenter
, istart_angle
, idiff_angle
;
566 double start_angle
, end_angle
;
569 RECT rc
= get_device_rect( dev
->hdc
, left
, top
, right
, bottom
);
575 LPtoDP(dev
->hdc
, &start
, 1);
576 LPtoDP(dev
->hdc
, &end
, 1);
578 if ((rc
.left
== rc
.right
) || (rc
.top
== rc
.bottom
)
579 ||(lines
&& ((rc
.right
-rc
.left
==1)||(rc
.bottom
-rc
.top
==1)))) return TRUE
;
581 if (GetArcDirection( dev
->hdc
) == AD_CLOCKWISE
)
582 { POINT tmp
= start
; start
= end
; end
= tmp
; }
584 oldwidth
= width
= physDev
->pen
.width
;
585 if (!width
) width
= 1;
586 if(physDev
->pen
.style
== PS_NULL
) width
= 0;
588 if (physDev
->pen
.style
== PS_INSIDEFRAME
)
590 if (2*width
> (rc
.right
-rc
.left
)) width
=(rc
.right
-rc
.left
+ 1)/2;
591 if (2*width
> (rc
.bottom
-rc
.top
)) width
=(rc
.bottom
-rc
.top
+ 1)/2;
592 rc
.left
+= width
/ 2;
593 rc
.right
-= (width
- 1) / 2;
595 rc
.bottom
-= (width
- 1) / 2;
597 if(width
== 0) width
= 1; /* more accurate */
598 physDev
->pen
.width
= width
;
600 xcenter
= (rc
.right
+ rc
.left
) / 2;
601 ycenter
= (rc
.bottom
+ rc
.top
) / 2;
602 start_angle
= atan2( (double)(ycenter
-start
.y
)*(rc
.right
-rc
.left
),
603 (double)(start
.x
-xcenter
)*(rc
.bottom
-rc
.top
) );
604 end_angle
= atan2( (double)(ycenter
-end
.y
)*(rc
.right
-rc
.left
),
605 (double)(end
.x
-xcenter
)*(rc
.bottom
-rc
.top
) );
606 if ((start
.x
==end
.x
)&&(start
.y
==end
.y
))
607 { /* A lazy program delivers xstart=xend=ystart=yend=0) */
611 else /* notorious cases */
612 if ((start_angle
== PI
)&&( end_angle
<0))
615 if ((end_angle
== PI
)&&( start_angle
<0))
617 istart_angle
= (INT
)(start_angle
* 180 * 64 / PI
+ 0.5);
618 idiff_angle
= (INT
)((end_angle
- start_angle
) * 180 * 64 / PI
+ 0.5);
619 if (idiff_angle
<= 0) idiff_angle
+= 360 * 64;
621 /* Fill arc with brush if Chord() or Pie() */
623 if ((lines
> 0) && X11DRV_SetupGCForBrush( physDev
)) {
624 XSetArcMode( gdi_display
, physDev
->gc
, (lines
==1) ? ArcChord
: ArcPieSlice
);
625 XFillArc( gdi_display
, physDev
->drawable
, physDev
->gc
,
626 physDev
->dc_rect
.left
+ rc
.left
, physDev
->dc_rect
.top
+ rc
.top
,
627 rc
.right
-rc
.left
-1, rc
.bottom
-rc
.top
-1, istart_angle
, idiff_angle
);
630 /* Draw arc and lines */
632 if (X11DRV_SetupGCForPen( physDev
))
635 XDrawArc( gdi_display
, physDev
->drawable
, physDev
->gc
,
636 physDev
->dc_rect
.left
+ rc
.left
, physDev
->dc_rect
.top
+ rc
.top
,
637 rc
.right
-rc
.left
-1, rc
.bottom
-rc
.top
-1, istart_angle
, idiff_angle
);
639 /* use the truncated values */
640 start_angle
=(double)istart_angle
*PI
/64./180.;
641 end_angle
=(double)(istart_angle
+idiff_angle
)*PI
/64./180.;
642 /* calculate the endpoints and round correctly */
643 points
[0].x
= (int) floor(physDev
->dc_rect
.left
+ (rc
.right
+rc
.left
)/2.0 +
644 cos(start_angle
) * (rc
.right
-rc
.left
-width
*2+2) / 2. + 0.5);
645 points
[0].y
= (int) floor(physDev
->dc_rect
.top
+ (rc
.top
+rc
.bottom
)/2.0 -
646 sin(start_angle
) * (rc
.bottom
-rc
.top
-width
*2+2) / 2. + 0.5);
647 points
[1].x
= (int) floor(physDev
->dc_rect
.left
+ (rc
.right
+rc
.left
)/2.0 +
648 cos(end_angle
) * (rc
.right
-rc
.left
-width
*2+2) / 2. + 0.5);
649 points
[1].y
= (int) floor(physDev
->dc_rect
.top
+ (rc
.top
+rc
.bottom
)/2.0 -
650 sin(end_angle
) * (rc
.bottom
-rc
.top
-width
*2+2) / 2. + 0.5);
652 /* OK, this stuff is optimized for Xfree86
653 * which is probably the server most used by
654 * wine users. Other X servers will not
655 * display correctly. (eXceed for instance)
656 * so if you feel you must make changes, make sure that
657 * you either use Xfree86 or separate your changes
658 * from these (compile switch or whatever)
662 points
[3] = points
[1];
663 points
[1].x
= physDev
->dc_rect
.left
+ xcenter
;
664 points
[1].y
= physDev
->dc_rect
.top
+ ycenter
;
665 points
[2] = points
[1];
666 dx1
=points
[1].x
-points
[0].x
;
667 dy1
=points
[1].y
-points
[0].y
;
668 if(((rc
.top
-rc
.bottom
) | -2) == -2)
669 if(dy1
>0) points
[1].y
--;
671 if (((-dx1
)*64)<=ABS(dy1
)*37) points
[0].x
--;
672 if(((-dx1
*9))<(dy1
*16)) points
[0].y
--;
673 if( dy1
<0 && ((dx1
*9)) < (dy1
*16)) points
[0].y
--;
675 if(dy1
< 0) points
[0].y
--;
676 if(((rc
.right
-rc
.left
) | -2) == -2) points
[1].x
--;
678 dx1
=points
[3].x
-points
[2].x
;
679 dy1
=points
[3].y
-points
[2].y
;
680 if(((rc
.top
-rc
.bottom
) | -2 ) == -2)
681 if(dy1
< 0) points
[2].y
--;
683 if( dy1
>0) points
[3].y
--;
684 if(((rc
.right
-rc
.left
) | -2) == -2 ) points
[2].x
--;
687 if( dx1
* 64 < dy1
* -37 ) points
[3].x
--;
691 XDrawLines( gdi_display
, physDev
->drawable
, physDev
->gc
,
692 points
, lines
+1, CoordModeOrigin
);
697 physDev
->pen
.width
= oldwidth
;
698 add_pen_device_bounds( physDev
, (POINT
*)&rc
, 2 );
703 /***********************************************************************
706 BOOL
X11DRV_Arc( PHYSDEV dev
, INT left
, INT top
, INT right
, INT bottom
,
707 INT xstart
, INT ystart
, INT xend
, INT yend
)
709 return X11DRV_DrawArc( dev
, left
, top
, right
, bottom
, xstart
, ystart
, xend
, yend
, 0 );
713 /***********************************************************************
716 BOOL
X11DRV_Pie( PHYSDEV dev
, INT left
, INT top
, INT right
, INT bottom
,
717 INT xstart
, INT ystart
, INT xend
, INT yend
)
719 return X11DRV_DrawArc( dev
, left
, top
, right
, bottom
, xstart
, ystart
, xend
, yend
, 2 );
722 /***********************************************************************
725 BOOL
X11DRV_Chord( PHYSDEV dev
, INT left
, INT top
, INT right
, INT bottom
,
726 INT xstart
, INT ystart
, INT xend
, INT yend
)
728 return X11DRV_DrawArc( dev
, left
, top
, right
, bottom
, xstart
, ystart
, xend
, yend
, 1 );
732 /***********************************************************************
735 BOOL
X11DRV_Ellipse( PHYSDEV dev
, INT left
, INT top
, INT right
, INT bottom
)
737 X11DRV_PDEVICE
*physDev
= get_x11drv_dev( dev
);
739 RECT rc
= get_device_rect( dev
->hdc
, left
, top
, right
, bottom
);
741 if ((rc
.left
== rc
.right
) || (rc
.top
== rc
.bottom
)) return TRUE
;
743 oldwidth
= width
= physDev
->pen
.width
;
744 if (!width
) width
= 1;
745 if(physDev
->pen
.style
== PS_NULL
) width
= 0;
747 if (physDev
->pen
.style
== PS_INSIDEFRAME
)
749 if (2*width
> (rc
.right
-rc
.left
)) width
=(rc
.right
-rc
.left
+ 1)/2;
750 if (2*width
> (rc
.bottom
-rc
.top
)) width
=(rc
.bottom
-rc
.top
+ 1)/2;
751 rc
.left
+= width
/ 2;
752 rc
.right
-= (width
- 1) / 2;
754 rc
.bottom
-= (width
- 1) / 2;
756 if(width
== 0) width
= 1; /* more accurate */
757 physDev
->pen
.width
= width
;
759 if (X11DRV_SetupGCForBrush( physDev
))
760 XFillArc( gdi_display
, physDev
->drawable
, physDev
->gc
,
761 physDev
->dc_rect
.left
+ rc
.left
, physDev
->dc_rect
.top
+ rc
.top
,
762 rc
.right
-rc
.left
-1, rc
.bottom
-rc
.top
-1, 0, 360*64 );
764 if (X11DRV_SetupGCForPen( physDev
))
765 XDrawArc( gdi_display
, physDev
->drawable
, physDev
->gc
,
766 physDev
->dc_rect
.left
+ rc
.left
, physDev
->dc_rect
.top
+ rc
.top
,
767 rc
.right
-rc
.left
-1, rc
.bottom
-rc
.top
-1, 0, 360*64 );
769 physDev
->pen
.width
= oldwidth
;
770 add_pen_device_bounds( physDev
, (POINT
*)&rc
, 2 );
775 /***********************************************************************
778 BOOL
X11DRV_Rectangle(PHYSDEV dev
, INT left
, INT top
, INT right
, INT bottom
)
780 X11DRV_PDEVICE
*physDev
= get_x11drv_dev( dev
);
781 INT width
, oldwidth
, oldjoinstyle
;
782 RECT rc
= get_device_rect( dev
->hdc
, left
, top
, right
, bottom
);
784 TRACE("(%d %d %d %d)\n", left
, top
, right
, bottom
);
786 if ((rc
.left
== rc
.right
) || (rc
.top
== rc
.bottom
)) return TRUE
;
788 oldwidth
= width
= physDev
->pen
.width
;
789 if (!width
) width
= 1;
790 if(physDev
->pen
.style
== PS_NULL
) width
= 0;
792 if (physDev
->pen
.style
== PS_INSIDEFRAME
)
794 if (2*width
> (rc
.right
-rc
.left
)) width
=(rc
.right
-rc
.left
+ 1)/2;
795 if (2*width
> (rc
.bottom
-rc
.top
)) width
=(rc
.bottom
-rc
.top
+ 1)/2;
796 rc
.left
+= width
/ 2;
797 rc
.right
-= (width
- 1) / 2;
799 rc
.bottom
-= (width
- 1) / 2;
801 if(width
== 1) width
= 0;
802 physDev
->pen
.width
= width
;
803 oldjoinstyle
= physDev
->pen
.linejoin
;
804 if(physDev
->pen
.type
!= PS_GEOMETRIC
)
805 physDev
->pen
.linejoin
= PS_JOIN_MITER
;
809 if ((rc
.right
>= rc
.left
+ width
) && (rc
.bottom
>= rc
.top
+ width
))
811 if (X11DRV_SetupGCForBrush( physDev
))
812 XFillRectangle( gdi_display
, physDev
->drawable
, physDev
->gc
,
813 physDev
->dc_rect
.left
+ rc
.left
+ (width
+ 1) / 2,
814 physDev
->dc_rect
.top
+ rc
.top
+ (width
+ 1) / 2,
815 rc
.right
-rc
.left
-width
, rc
.bottom
-rc
.top
-width
);
817 if (X11DRV_SetupGCForPen( physDev
))
818 XDrawRectangle( gdi_display
, physDev
->drawable
, physDev
->gc
,
819 physDev
->dc_rect
.left
+ rc
.left
, physDev
->dc_rect
.top
+ rc
.top
,
820 rc
.right
-rc
.left
, rc
.bottom
-rc
.top
);
822 physDev
->pen
.width
= oldwidth
;
823 physDev
->pen
.linejoin
= oldjoinstyle
;
824 add_pen_device_bounds( physDev
, (POINT
*)&rc
, 2 );
828 /***********************************************************************
831 BOOL
X11DRV_RoundRect( PHYSDEV dev
, INT left
, INT top
, INT right
, INT bottom
,
832 INT ell_width
, INT ell_height
)
834 X11DRV_PDEVICE
*physDev
= get_x11drv_dev( dev
);
835 INT width
, oldwidth
, oldendcap
;
837 RECT rc
= get_device_rect( dev
->hdc
, left
, top
, right
, bottom
);
839 TRACE("(%d %d %d %d %d %d\n",
840 left
, top
, right
, bottom
, ell_width
, ell_height
);
842 if ((rc
.left
== rc
.right
) || (rc
.top
== rc
.bottom
))
845 /* Make sure ell_width and ell_height are >= 1 otherwise XDrawArc gets
846 called with width/height < 0 */
847 pts
[0].x
= pts
[0].y
= 0;
848 pts
[1].x
= ell_width
;
849 pts
[1].y
= ell_height
;
850 LPtoDP(dev
->hdc
, pts
, 2);
851 ell_width
= max(abs( pts
[1].x
- pts
[0].x
), 1);
852 ell_height
= max(abs( pts
[1].y
- pts
[0].y
), 1);
854 oldwidth
= width
= physDev
->pen
.width
;
855 oldendcap
= physDev
->pen
.endcap
;
856 if (!width
) width
= 1;
857 if(physDev
->pen
.style
== PS_NULL
) width
= 0;
859 if (physDev
->pen
.style
== PS_INSIDEFRAME
)
861 if (2*width
> (rc
.right
-rc
.left
)) width
=(rc
.right
-rc
.left
+ 1)/2;
862 if (2*width
> (rc
.bottom
-rc
.top
)) width
=(rc
.bottom
-rc
.top
+ 1)/2;
863 rc
.left
+= width
/ 2;
864 rc
.right
-= (width
- 1) / 2;
866 rc
.bottom
-= (width
- 1) / 2;
868 if(width
== 0) width
= 1;
869 physDev
->pen
.width
= width
;
870 physDev
->pen
.endcap
= PS_ENDCAP_SQUARE
;
872 if (X11DRV_SetupGCForBrush( physDev
))
875 if (ell_width
> (rc
.right
-rc
.left
) )
876 if (ell_height
> (rc
.bottom
-rc
.top
) )
877 XFillArc( gdi_display
, physDev
->drawable
, physDev
->gc
,
878 physDev
->dc_rect
.left
+ rc
.left
, physDev
->dc_rect
.top
+ rc
.top
,
879 rc
.right
- rc
.left
- 1, rc
.bottom
- rc
.top
- 1,
882 XFillArc( gdi_display
, physDev
->drawable
, physDev
->gc
,
883 physDev
->dc_rect
.left
+ rc
.left
, physDev
->dc_rect
.top
+ rc
.top
,
884 rc
.right
- rc
.left
- 1, ell_height
, 0, 180 * 64 );
885 XFillArc( gdi_display
, physDev
->drawable
, physDev
->gc
,
886 physDev
->dc_rect
.left
+ rc
.left
,
887 physDev
->dc_rect
.top
+ rc
.bottom
- ell_height
- 1,
888 rc
.right
- rc
.left
- 1, ell_height
, 180 * 64,
891 else if (ell_height
> (rc
.bottom
-rc
.top
) ){
892 XFillArc( gdi_display
, physDev
->drawable
, physDev
->gc
,
893 physDev
->dc_rect
.left
+ rc
.left
, physDev
->dc_rect
.top
+ rc
.top
,
894 ell_width
, rc
.bottom
- rc
.top
- 1, 90 * 64, 180 * 64 );
895 XFillArc( gdi_display
, physDev
->drawable
, physDev
->gc
,
896 physDev
->dc_rect
.left
+ rc
.right
- ell_width
- 1, physDev
->dc_rect
.top
+ rc
.top
,
897 ell_width
, rc
.bottom
- rc
.top
- 1, 270 * 64, 180 * 64 );
899 XFillArc( gdi_display
, physDev
->drawable
, physDev
->gc
,
900 physDev
->dc_rect
.left
+ rc
.left
, physDev
->dc_rect
.top
+ rc
.top
,
901 ell_width
, ell_height
, 90 * 64, 90 * 64 );
902 XFillArc( gdi_display
, physDev
->drawable
, physDev
->gc
,
903 physDev
->dc_rect
.left
+ rc
.left
,
904 physDev
->dc_rect
.top
+ rc
.bottom
- ell_height
- 1,
905 ell_width
, ell_height
, 180 * 64, 90 * 64 );
906 XFillArc( gdi_display
, physDev
->drawable
, physDev
->gc
,
907 physDev
->dc_rect
.left
+ rc
.right
- ell_width
- 1,
908 physDev
->dc_rect
.top
+ rc
.bottom
- ell_height
- 1,
909 ell_width
, ell_height
, 270 * 64, 90 * 64 );
910 XFillArc( gdi_display
, physDev
->drawable
, physDev
->gc
,
911 physDev
->dc_rect
.left
+ rc
.right
- ell_width
- 1,
912 physDev
->dc_rect
.top
+ rc
.top
,
913 ell_width
, ell_height
, 0, 90 * 64 );
915 if (ell_width
< rc
.right
- rc
.left
)
917 XFillRectangle( gdi_display
, physDev
->drawable
, physDev
->gc
,
918 physDev
->dc_rect
.left
+ rc
.left
+ (ell_width
+ 1) / 2,
919 physDev
->dc_rect
.top
+ rc
.top
+ 1,
920 rc
.right
- rc
.left
- ell_width
- 1,
921 (ell_height
+ 1) / 2 - 1);
922 XFillRectangle( gdi_display
, physDev
->drawable
, physDev
->gc
,
923 physDev
->dc_rect
.left
+ rc
.left
+ (ell_width
+ 1) / 2,
924 physDev
->dc_rect
.top
+ rc
.bottom
- (ell_height
) / 2 - 1,
925 rc
.right
- rc
.left
- ell_width
- 1,
928 if (ell_height
< rc
.bottom
- rc
.top
)
930 XFillRectangle( gdi_display
, physDev
->drawable
, physDev
->gc
,
931 physDev
->dc_rect
.left
+ rc
.left
+ 1,
932 physDev
->dc_rect
.top
+ rc
.top
+ (ell_height
+ 1) / 2,
933 rc
.right
- rc
.left
- 2,
934 rc
.bottom
- rc
.top
- ell_height
- 1);
938 /* FIXME: this could be done with on X call
939 * more efficient and probably more correct
940 * on any X server: XDrawArcs will draw
941 * straight horizontal and vertical lines
942 * if width or height are zero.
944 * BTW this stuff is optimized for an Xfree86 server
945 * read the comments inside the X11DRV_DrawArc function
947 if (X11DRV_SetupGCForPen( physDev
))
950 if (ell_width
> (rc
.right
-rc
.left
) )
951 if (ell_height
> (rc
.bottom
-rc
.top
) )
952 XDrawArc( gdi_display
, physDev
->drawable
, physDev
->gc
,
953 physDev
->dc_rect
.left
+ rc
.left
, physDev
->dc_rect
.top
+ rc
.top
,
954 rc
.right
- rc
.left
- 1, rc
.bottom
- rc
.top
- 1, 0 , 360 * 64 );
956 XDrawArc( gdi_display
, physDev
->drawable
, physDev
->gc
,
957 physDev
->dc_rect
.left
+ rc
.left
, physDev
->dc_rect
.top
+ rc
.top
,
958 rc
.right
- rc
.left
- 1, ell_height
- 1, 0 , 180 * 64 );
959 XDrawArc( gdi_display
, physDev
->drawable
, physDev
->gc
,
960 physDev
->dc_rect
.left
+ rc
.left
,
961 physDev
->dc_rect
.top
+ rc
.bottom
- ell_height
,
962 rc
.right
- rc
.left
- 1, ell_height
- 1, 180 * 64 , 180 * 64 );
964 else if (ell_height
> (rc
.bottom
-rc
.top
) ){
965 XDrawArc( gdi_display
, physDev
->drawable
, physDev
->gc
,
966 physDev
->dc_rect
.left
+ rc
.left
, physDev
->dc_rect
.top
+ rc
.top
,
967 ell_width
- 1 , rc
.bottom
- rc
.top
- 1, 90 * 64 , 180 * 64 );
968 XDrawArc( gdi_display
, physDev
->drawable
, physDev
->gc
,
969 physDev
->dc_rect
.left
+ rc
.right
- ell_width
,
970 physDev
->dc_rect
.top
+ rc
.top
,
971 ell_width
- 1 , rc
.bottom
- rc
.top
- 1, 270 * 64 , 180 * 64 );
973 XDrawArc( gdi_display
, physDev
->drawable
, physDev
->gc
,
974 physDev
->dc_rect
.left
+ rc
.left
, physDev
->dc_rect
.top
+ rc
.top
,
975 ell_width
- 1, ell_height
- 1, 90 * 64, 90 * 64 );
976 XDrawArc( gdi_display
, physDev
->drawable
, physDev
->gc
,
977 physDev
->dc_rect
.left
+ rc
.left
, physDev
->dc_rect
.top
+ rc
.bottom
- ell_height
,
978 ell_width
- 1, ell_height
- 1, 180 * 64, 90 * 64 );
979 XDrawArc( gdi_display
, physDev
->drawable
, physDev
->gc
,
980 physDev
->dc_rect
.left
+ rc
.right
- ell_width
,
981 physDev
->dc_rect
.top
+ rc
.bottom
- ell_height
,
982 ell_width
- 1, ell_height
- 1, 270 * 64, 90 * 64 );
983 XDrawArc( gdi_display
, physDev
->drawable
, physDev
->gc
,
984 physDev
->dc_rect
.left
+ rc
.right
- ell_width
, physDev
->dc_rect
.top
+ rc
.top
,
985 ell_width
- 1, ell_height
- 1, 0, 90 * 64 );
987 if (ell_width
< rc
.right
- rc
.left
)
989 XDrawLine( gdi_display
, physDev
->drawable
, physDev
->gc
,
990 physDev
->dc_rect
.left
+ rc
.left
+ ell_width
/ 2,
991 physDev
->dc_rect
.top
+ rc
.top
,
992 physDev
->dc_rect
.left
+ rc
.right
- (ell_width
+1) / 2,
993 physDev
->dc_rect
.top
+ rc
.top
);
994 XDrawLine( gdi_display
, physDev
->drawable
, physDev
->gc
,
995 physDev
->dc_rect
.left
+ rc
.left
+ ell_width
/ 2 ,
996 physDev
->dc_rect
.top
+ rc
.bottom
- 1,
997 physDev
->dc_rect
.left
+ rc
.right
- (ell_width
+1)/ 2,
998 physDev
->dc_rect
.top
+ rc
.bottom
- 1);
1000 if (ell_height
< rc
.bottom
- rc
.top
)
1002 XDrawLine( gdi_display
, physDev
->drawable
, physDev
->gc
,
1003 physDev
->dc_rect
.left
+ rc
.right
- 1,
1004 physDev
->dc_rect
.top
+ rc
.top
+ ell_height
/ 2,
1005 physDev
->dc_rect
.left
+ rc
.right
- 1,
1006 physDev
->dc_rect
.top
+ rc
.bottom
- (ell_height
+1) / 2);
1007 XDrawLine( gdi_display
, physDev
->drawable
, physDev
->gc
,
1008 physDev
->dc_rect
.left
+ rc
.left
,
1009 physDev
->dc_rect
.top
+ rc
.top
+ ell_height
/ 2,
1010 physDev
->dc_rect
.left
+ rc
.left
,
1011 physDev
->dc_rect
.top
+ rc
.bottom
- (ell_height
+1) / 2);
1013 wine_tsx11_unlock();
1016 physDev
->pen
.width
= oldwidth
;
1017 physDev
->pen
.endcap
= oldendcap
;
1018 add_pen_device_bounds( physDev
, (POINT
*)&rc
, 2 );
1023 /***********************************************************************
1026 COLORREF
X11DRV_SetPixel( PHYSDEV dev
, INT x
, INT y
, COLORREF color
)
1028 X11DRV_PDEVICE
*physDev
= get_x11drv_dev( dev
);
1029 unsigned long pixel
;
1035 LPtoDP( dev
->hdc
, &pt
, 1 );
1036 pixel
= X11DRV_PALETTE_ToPhysical( physDev
, color
);
1038 XSetForeground( gdi_display
, physDev
->gc
, pixel
);
1039 XSetFunction( gdi_display
, physDev
->gc
, GXcopy
);
1040 XDrawPoint( gdi_display
, physDev
->drawable
, physDev
->gc
,
1041 physDev
->dc_rect
.left
+ pt
.x
, physDev
->dc_rect
.top
+ pt
.y
);
1043 SetRect( &rect
, pt
.x
, pt
.y
, pt
.x
+ 1, pt
.y
+ 1 );
1044 add_device_bounds( physDev
, &rect
);
1045 return X11DRV_PALETTE_ToLogical(physDev
, pixel
);
1049 /***********************************************************************
1052 BOOL
X11DRV_PaintRgn( PHYSDEV dev
, HRGN hrgn
)
1054 X11DRV_PDEVICE
*physDev
= get_x11drv_dev( dev
);
1057 if (X11DRV_SetupGCForBrush( physDev
))
1061 RGNDATA
*data
= X11DRV_GetRegionData( hrgn
, dev
->hdc
);
1063 if (!data
) return FALSE
;
1064 rect
= (XRectangle
*)data
->Buffer
;
1065 for (i
= 0; i
< data
->rdh
.nCount
; i
++)
1067 rect
[i
].x
+= physDev
->dc_rect
.left
;
1068 rect
[i
].y
+= physDev
->dc_rect
.top
;
1071 XFillRectangles( gdi_display
, physDev
->drawable
, physDev
->gc
, rect
, data
->rdh
.nCount
);
1072 HeapFree( GetProcessHeap(), 0, data
);
1074 if (GetRgnBox( hrgn
, &rc
))
1076 LPtoDP( dev
->hdc
, (POINT
*)&rc
, 2 );
1077 add_device_bounds( physDev
, &rc
);
1082 /**********************************************************************
1085 BOOL
X11DRV_Polygon( PHYSDEV dev
, const POINT
* pt
, INT count
)
1087 X11DRV_PDEVICE
*physDev
= get_x11drv_dev( dev
);
1092 points
= HeapAlloc( GetProcessHeap(), 0, count
* sizeof(*pt
) );
1093 if (!points
) return FALSE
;
1094 memcpy( points
, pt
, count
* sizeof(*pt
) );
1095 LPtoDP( dev
->hdc
, points
, count
);
1096 add_pen_device_bounds( physDev
, points
, count
);
1098 if (!(xpoints
= HeapAlloc( GetProcessHeap(), 0, sizeof(XPoint
) * (count
+1) )))
1100 HeapFree( GetProcessHeap(), 0, points
);
1103 for (i
= 0; i
< count
; i
++)
1105 xpoints
[i
].x
= physDev
->dc_rect
.left
+ points
[i
].x
;
1106 xpoints
[i
].y
= physDev
->dc_rect
.top
+ points
[i
].y
;
1108 xpoints
[count
] = xpoints
[0];
1110 if (X11DRV_SetupGCForBrush( physDev
))
1111 XFillPolygon( gdi_display
, physDev
->drawable
, physDev
->gc
,
1112 xpoints
, count
+1, Complex
, CoordModeOrigin
);
1114 if (X11DRV_SetupGCForPen ( physDev
))
1115 XDrawLines( gdi_display
, physDev
->drawable
, physDev
->gc
,
1116 xpoints
, count
+1, CoordModeOrigin
);
1118 HeapFree( GetProcessHeap(), 0, xpoints
);
1119 HeapFree( GetProcessHeap(), 0, points
);
1124 /**********************************************************************
1125 * X11DRV_PolyPolygon
1127 BOOL
X11DRV_PolyPolygon( PHYSDEV dev
, const POINT
* pt
, const INT
* counts
, UINT polygons
)
1129 X11DRV_PDEVICE
*physDev
= get_x11drv_dev( dev
);
1130 DWORD total
= 0, max
= 0, pos
, i
;
1134 for (i
= 0; i
< polygons
; i
++)
1136 if (counts
[i
] < 2) return FALSE
;
1137 if (counts
[i
] > max
) max
= counts
[i
];
1141 points
= HeapAlloc( GetProcessHeap(), 0, total
* sizeof(*pt
) );
1142 if (!points
) return FALSE
;
1143 memcpy( points
, pt
, total
* sizeof(*pt
) );
1144 LPtoDP( dev
->hdc
, points
, total
);
1145 add_pen_device_bounds( physDev
, points
, total
);
1147 if (X11DRV_SetupGCForBrush( physDev
))
1150 HRGN hrgn
= CreatePolyPolygonRgn( points
, counts
, polygons
, GetPolyFillMode( dev
->hdc
) );
1151 RGNDATA
*data
= X11DRV_GetRegionData( hrgn
, 0 );
1153 DeleteObject( hrgn
);
1154 if (!data
) goto done
;
1155 rect
= (XRectangle
*)data
->Buffer
;
1156 for (i
= 0; i
< data
->rdh
.nCount
; i
++)
1158 rect
[i
].x
+= physDev
->dc_rect
.left
;
1159 rect
[i
].y
+= physDev
->dc_rect
.top
;
1162 XFillRectangles( gdi_display
, physDev
->drawable
, physDev
->gc
, rect
, data
->rdh
.nCount
);
1163 HeapFree( GetProcessHeap(), 0, data
);
1166 if (X11DRV_SetupGCForPen ( physDev
))
1171 if (!(xpoints
= HeapAlloc( GetProcessHeap(), 0, sizeof(XPoint
) * (max
+ 1) ))) goto done
;
1172 for (i
= pos
= 0; i
< polygons
; pos
+= counts
[i
++])
1174 for (j
= 0; j
< counts
[i
]; j
++)
1176 xpoints
[j
].x
= physDev
->dc_rect
.left
+ points
[pos
+ j
].x
;
1177 xpoints
[j
].y
= physDev
->dc_rect
.top
+ points
[pos
+ j
].y
;
1179 xpoints
[j
] = xpoints
[0];
1180 XDrawLines( gdi_display
, physDev
->drawable
, physDev
->gc
, xpoints
, j
+ 1, CoordModeOrigin
);
1182 HeapFree( GetProcessHeap(), 0, xpoints
);
1187 HeapFree( GetProcessHeap(), 0, points
);
1192 /**********************************************************************
1193 * X11DRV_PolyPolyline
1195 BOOL
X11DRV_PolyPolyline( PHYSDEV dev
, const POINT
* pt
, const DWORD
* counts
, DWORD polylines
)
1197 X11DRV_PDEVICE
*physDev
= get_x11drv_dev( dev
);
1198 DWORD total
= 0, max
= 0, pos
, i
, j
;
1201 for (i
= 0; i
< polylines
; i
++)
1203 if (counts
[i
] < 2) return FALSE
;
1204 if (counts
[i
] > max
) max
= counts
[i
];
1208 points
= HeapAlloc( GetProcessHeap(), 0, total
* sizeof(*pt
) );
1209 if (!points
) return FALSE
;
1210 memcpy( points
, pt
, total
* sizeof(*pt
) );
1211 LPtoDP( dev
->hdc
, points
, total
);
1212 add_pen_device_bounds( physDev
, points
, total
);
1214 if (X11DRV_SetupGCForPen ( physDev
))
1218 if (!(xpoints
= HeapAlloc( GetProcessHeap(), 0, sizeof(XPoint
) * max
)))
1220 HeapFree( GetProcessHeap(), 0, points
);
1223 for (i
= pos
= 0; i
< polylines
; pos
+= counts
[i
++])
1225 for (j
= 0; j
< counts
[i
]; j
++)
1227 xpoints
[j
].x
= physDev
->dc_rect
.left
+ points
[pos
+ j
].x
;
1228 xpoints
[j
].y
= physDev
->dc_rect
.top
+ points
[pos
+ j
].y
;
1230 XDrawLines( gdi_display
, physDev
->drawable
, physDev
->gc
, xpoints
, j
, CoordModeOrigin
);
1232 HeapFree( GetProcessHeap(), 0, xpoints
);
1234 HeapFree( GetProcessHeap(), 0, points
);
1239 /**********************************************************************
1240 * X11DRV_InternalFloodFill
1242 * Internal helper function for flood fill.
1243 * (xorg,yorg) is the origin of the X image relative to the drawable.
1244 * (x,y) is relative to the origin of the X image.
1246 static void X11DRV_InternalFloodFill(XImage
*image
, X11DRV_PDEVICE
*physDev
,
1249 unsigned long pixel
, WORD fillType
, RECT
*bounds
)
1253 #define TO_FLOOD(x,y) ((fillType == FLOODFILLBORDER) ? \
1254 (XGetPixel(image,x,y) != pixel) : \
1255 (XGetPixel(image,x,y) == pixel))
1257 if (!TO_FLOOD(x
,y
)) return;
1259 /* Find left and right boundaries */
1262 while ((left
> 0) && TO_FLOOD( left
-1, y
)) left
--;
1263 while ((right
< image
->width
) && TO_FLOOD( right
, y
)) right
++;
1264 bounds
->left
= min( bounds
->left
, left
);
1265 bounds
->top
= min( bounds
->top
, y
);
1266 bounds
->right
= max( bounds
->right
, right
);
1267 bounds
->bottom
= max( bounds
->bottom
, y
+ 1 );
1268 XFillRectangle( gdi_display
, physDev
->drawable
, physDev
->gc
,
1269 xOrg
+ left
, yOrg
+ y
, right
-left
, 1 );
1271 /* Set the pixels of this line so we don't fill it again */
1273 for (x
= left
; x
< right
; x
++)
1275 if (fillType
== FLOODFILLBORDER
) XPutPixel( image
, x
, y
, pixel
);
1276 else XPutPixel( image
, x
, y
, ~pixel
);
1279 /* Fill the line above */
1286 while ((x
< right
) && !TO_FLOOD(x
,y
)) x
++;
1287 if (x
>= right
) break;
1288 while ((x
< right
) && TO_FLOOD(x
,y
)) x
++;
1289 X11DRV_InternalFloodFill(image
, physDev
, x
-1, y
,
1290 xOrg
, yOrg
, pixel
, fillType
, bounds
);
1294 /* Fill the line below */
1296 if ((y
+= 2) < image
->height
)
1301 while ((x
< right
) && !TO_FLOOD(x
,y
)) x
++;
1302 if (x
>= right
) break;
1303 while ((x
< right
) && TO_FLOOD(x
,y
)) x
++;
1304 X11DRV_InternalFloodFill(image
, physDev
, x
-1, y
,
1305 xOrg
, yOrg
, pixel
, fillType
, bounds
);
1312 static int ExtFloodFillXGetImageErrorHandler( Display
*dpy
, XErrorEvent
*event
, void *arg
)
1314 return (event
->request_code
== X_GetImage
&& event
->error_code
== BadMatch
);
1317 /**********************************************************************
1318 * X11DRV_ExtFloodFill
1320 BOOL
X11DRV_ExtFloodFill( PHYSDEV dev
, INT x
, INT y
, COLORREF color
, UINT fillType
)
1322 X11DRV_PDEVICE
*physDev
= get_x11drv_dev( dev
);
1327 TRACE("X11DRV_ExtFloodFill %d,%d %06x %d\n", x
, y
, color
, fillType
);
1331 LPtoDP( dev
->hdc
, &pt
, 1 );
1333 if (!physDev
->region
)
1337 rect
.right
= physDev
->dc_rect
.right
- physDev
->dc_rect
.left
;
1338 rect
.bottom
= physDev
->dc_rect
.bottom
- physDev
->dc_rect
.top
;
1342 if (!PtInRegion( physDev
->region
, pt
.x
, pt
.y
)) return FALSE
;
1343 GetRgnBox( physDev
->region
, &rect
);
1344 rect
.left
= max( rect
.left
, 0 );
1345 rect
.top
= max( rect
.top
, 0 );
1346 rect
.right
= min( rect
.right
, physDev
->dc_rect
.right
- physDev
->dc_rect
.left
);
1347 rect
.bottom
= min( rect
.bottom
, physDev
->dc_rect
.bottom
- physDev
->dc_rect
.top
);
1349 if (pt
.x
< rect
.left
|| pt
.x
>= rect
.right
|| pt
.y
< rect
.top
|| pt
.y
>= rect
.bottom
) return FALSE
;
1351 X11DRV_expect_error( gdi_display
, ExtFloodFillXGetImageErrorHandler
, NULL
);
1352 image
= XGetImage( gdi_display
, physDev
->drawable
,
1353 physDev
->dc_rect
.left
+ rect
.left
, physDev
->dc_rect
.top
+ rect
.top
,
1354 rect
.right
- rect
.left
, rect
.bottom
- rect
.top
,
1355 AllPlanes
, ZPixmap
);
1356 if(X11DRV_check_error()) image
= NULL
;
1357 if (!image
) return FALSE
;
1359 if (X11DRV_SetupGCForBrush( physDev
))
1361 unsigned long pixel
= X11DRV_PALETTE_ToPhysical( physDev
, color
);
1363 reset_bounds( &bounds
);
1365 X11DRV_InternalFloodFill(image
, physDev
,
1368 physDev
->dc_rect
.left
+ rect
.left
,
1369 physDev
->dc_rect
.top
+ rect
.top
,
1370 pixel
, fillType
, &bounds
);
1372 OffsetRect( &bounds
, rect
.left
, rect
.top
);
1373 add_device_bounds( physDev
, &bounds
);
1376 XDestroyImage( image
);
1380 /**********************************************************************
1381 * X11DRV_GradientFill
1383 BOOL
X11DRV_GradientFill( PHYSDEV dev
, TRIVERTEX
*vert_array
, ULONG nvert
,
1384 void *grad_array
, ULONG ngrad
, ULONG mode
)
1386 X11DRV_PDEVICE
*physdev
= get_x11drv_dev( dev
);
1387 const GRADIENT_RECT
*rect
= grad_array
;
1394 /* <= 16-bpp use dithering */
1395 if (physdev
->depth
<= 16) goto fallback
;
1399 case GRADIENT_FILL_RECT_H
:
1400 val
.function
= GXcopy
;
1401 val
.fill_style
= FillSolid
;
1403 val
.cap_style
= CapNotLast
;
1404 val
.line_style
= LineSolid
;
1405 XChangeGC( gdi_display
, physdev
->gc
,
1406 GCFunction
| GCLineWidth
| GCLineStyle
| GCCapStyle
| GCFillStyle
, &val
);
1407 reset_bounds( &bounds
);
1409 for (i
= 0; i
< ngrad
; i
++, rect
++)
1413 v
[0] = vert_array
[rect
->UpperLeft
];
1414 v
[1] = vert_array
[rect
->LowerRight
];
1419 LPtoDP( dev
->hdc
, pt
, 2 );
1420 dx
= pt
[1].x
- pt
[0].x
;
1422 if (dx
< 0) /* swap the colors */
1424 v
[0] = vert_array
[rect
->LowerRight
];
1425 v
[1] = vert_array
[rect
->UpperLeft
];
1428 rc
.left
= min( pt
[0].x
, pt
[1].x
);
1429 rc
.top
= min( pt
[0].y
, pt
[1].y
);
1430 rc
.right
= max( pt
[0].x
, pt
[1].x
);
1431 rc
.bottom
= max( pt
[0].y
, pt
[1].y
);
1432 add_bounds_rect( &bounds
, &rc
);
1433 for (x
= 0; x
< dx
; x
++)
1435 int color
= X11DRV_PALETTE_ToPhysical( physdev
,
1436 RGB( (v
[0].Red
* (dx
- x
) + v
[1].Red
* x
) / dx
/ 256,
1437 (v
[0].Green
* (dx
- x
) + v
[1].Green
* x
) / dx
/ 256,
1438 (v
[0].Blue
* (dx
- x
) + v
[1].Blue
* x
) / dx
/ 256) );
1440 XSetForeground( gdi_display
, physdev
->gc
, color
);
1441 XDrawLine( gdi_display
, physdev
->drawable
, physdev
->gc
,
1442 physdev
->dc_rect
.left
+ rc
.left
+ x
, physdev
->dc_rect
.top
+ rc
.top
,
1443 physdev
->dc_rect
.left
+ rc
.left
+ x
, physdev
->dc_rect
.top
+ rc
.bottom
);
1446 add_device_bounds( physdev
, &bounds
);
1449 case GRADIENT_FILL_RECT_V
:
1450 val
.function
= GXcopy
;
1451 val
.fill_style
= FillSolid
;
1453 val
.cap_style
= CapNotLast
;
1454 val
.line_style
= LineSolid
;
1455 XChangeGC( gdi_display
, physdev
->gc
,
1456 GCFunction
| GCLineWidth
| GCLineStyle
| GCCapStyle
| GCFillStyle
, &val
);
1457 reset_bounds( &bounds
);
1459 for (i
= 0; i
< ngrad
; i
++, rect
++)
1463 v
[0] = vert_array
[rect
->UpperLeft
];
1464 v
[1] = vert_array
[rect
->LowerRight
];
1469 LPtoDP( dev
->hdc
, pt
, 2 );
1470 dy
= pt
[1].y
- pt
[0].y
;
1472 if (dy
< 0) /* swap the colors */
1474 v
[0] = vert_array
[rect
->LowerRight
];
1475 v
[1] = vert_array
[rect
->UpperLeft
];
1478 rc
.left
= min( pt
[0].x
, pt
[1].x
);
1479 rc
.top
= min( pt
[0].y
, pt
[1].y
);
1480 rc
.right
= max( pt
[0].x
, pt
[1].x
);
1481 rc
.bottom
= max( pt
[0].y
, pt
[1].y
);
1482 add_bounds_rect( &bounds
, &rc
);
1483 for (y
= 0; y
< dy
; y
++)
1485 int color
= X11DRV_PALETTE_ToPhysical( physdev
,
1486 RGB( (v
[0].Red
* (dy
- y
) + v
[1].Red
* y
) / dy
/ 256,
1487 (v
[0].Green
* (dy
- y
) + v
[1].Green
* y
) / dy
/ 256,
1488 (v
[0].Blue
* (dy
- y
) + v
[1].Blue
* y
) / dy
/ 256) );
1490 XSetForeground( gdi_display
, physdev
->gc
, color
);
1491 XDrawLine( gdi_display
, physdev
->drawable
, physdev
->gc
,
1492 physdev
->dc_rect
.left
+ rc
.left
, physdev
->dc_rect
.top
+ rc
.top
+ y
,
1493 physdev
->dc_rect
.left
+ rc
.right
, physdev
->dc_rect
.top
+ rc
.top
+ y
);
1496 add_device_bounds( physdev
, &bounds
);
1501 dev
= GET_NEXT_PHYSDEV( dev
, pGradientFill
);
1502 return dev
->funcs
->pGradientFill( dev
, vert_array
, nvert
, grad_array
, ngrad
, mode
);
1505 static unsigned char *get_icm_profile( unsigned long *size
)
1509 unsigned long count
, remaining
;
1510 unsigned char *profile
, *ret
= NULL
;
1513 XGetWindowProperty( gdi_display
, DefaultRootWindow(gdi_display
),
1514 x11drv_atom(_ICC_PROFILE
), 0, ~0UL, False
, AnyPropertyType
,
1515 &type
, &format
, &count
, &remaining
, &profile
);
1516 *size
= get_property_size( format
, count
);
1517 if (format
&& count
)
1519 if ((ret
= HeapAlloc( GetProcessHeap(), 0, *size
))) memcpy( ret
, profile
, *size
);
1522 wine_tsx11_unlock();
1528 unsigned int unknown
[6];
1529 unsigned int state
[5];
1530 unsigned int count
[2];
1531 unsigned char buffer
[64];
1534 extern void WINAPI
A_SHAInit( sha_ctx
* );
1535 extern void WINAPI
A_SHAUpdate( sha_ctx
*, const unsigned char *, unsigned int );
1536 extern void WINAPI
A_SHAFinal( sha_ctx
*, unsigned char * );
1538 static const WCHAR mntr_key
[] =
1539 {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
1540 'W','i','n','d','o','w','s',' ','N','T','\\','C','u','r','r','e','n','t',
1541 'V','e','r','s','i','o','n','\\','I','C','M','\\','m','n','t','r',0};
1543 static const WCHAR color_path
[] =
1544 {'\\','s','p','o','o','l','\\','d','r','i','v','e','r','s','\\','c','o','l','o','r','\\',0};
1546 /***********************************************************************
1547 * GetICMProfile (X11DRV.@)
1549 BOOL
X11DRV_GetICMProfile( PHYSDEV dev
, LPDWORD size
, LPWSTR filename
)
1551 static const WCHAR srgb
[] =
1552 {'s','R','G','B',' ','C','o','l','o','r',' ','S','p','a','c','e',' ',
1553 'P','r','o','f','i','l','e','.','i','c','m',0};
1555 DWORD required
, len
;
1556 WCHAR profile
[MAX_PATH
], fullname
[2*MAX_PATH
+ sizeof(color_path
)/sizeof(WCHAR
)];
1557 unsigned char *buffer
;
1558 unsigned long buflen
;
1560 if (!size
) return FALSE
;
1562 GetSystemDirectoryW( fullname
, MAX_PATH
);
1563 strcatW( fullname
, color_path
);
1565 len
= sizeof(profile
)/sizeof(WCHAR
);
1566 if (!RegCreateKeyExW( HKEY_LOCAL_MACHINE
, mntr_key
, 0, NULL
, 0, KEY_ALL_ACCESS
, NULL
, &hkey
, NULL
) &&
1567 !RegEnumValueW( hkey
, 0, profile
, &len
, NULL
, NULL
, NULL
, NULL
)) /* FIXME handle multiple values */
1569 strcatW( fullname
, profile
);
1570 RegCloseKey( hkey
);
1572 else if ((buffer
= get_icm_profile( &buflen
)))
1574 static const WCHAR fmt
[] = {'%','0','2','x',0};
1575 static const WCHAR icm
[] = {'.','i','c','m',0};
1577 unsigned char sha1sum
[20];
1583 A_SHAUpdate( &ctx
, buffer
, buflen
);
1584 A_SHAFinal( &ctx
, sha1sum
);
1586 for (i
= 0; i
< sizeof(sha1sum
); i
++) sprintfW( &profile
[i
* 2], fmt
, sha1sum
[i
] );
1587 memcpy( &profile
[i
* 2], icm
, sizeof(icm
) );
1589 strcatW( fullname
, profile
);
1590 file
= CreateFileW( fullname
, GENERIC_WRITE
, 0, NULL
, CREATE_NEW
, 0, 0 );
1591 if (file
!= INVALID_HANDLE_VALUE
)
1595 if (!WriteFile( file
, buffer
, buflen
, &written
, NULL
) || written
!= buflen
)
1596 ERR( "Unable to write color profile\n" );
1597 CloseHandle( file
);
1599 HeapFree( GetProcessHeap(), 0, buffer
);
1601 else strcatW( fullname
, srgb
);
1603 required
= strlenW( fullname
) + 1;
1604 if (*size
< required
)
1607 SetLastError( ERROR_INSUFFICIENT_BUFFER
);
1612 strcpyW( filename
, fullname
);
1613 if (GetFileAttributesW( filename
) == INVALID_FILE_ATTRIBUTES
)
1614 WARN( "color profile not found\n" );
1620 /***********************************************************************
1621 * EnumICMProfiles (X11DRV.@)
1623 INT
X11DRV_EnumICMProfiles( PHYSDEV dev
, ICMENUMPROCW proc
, LPARAM lparam
)
1625 X11DRV_PDEVICE
*physDev
= get_x11drv_dev( dev
);
1627 DWORD len_sysdir
, len_path
, len
, index
= 0;
1628 WCHAR sysdir
[MAX_PATH
], *profile
;
1632 TRACE("%p, %p, %ld\n", physDev
, proc
, lparam
);
1634 if (RegOpenKeyExW( HKEY_LOCAL_MACHINE
, mntr_key
, 0, KEY_ALL_ACCESS
, &hkey
))
1637 len_sysdir
= GetSystemDirectoryW( sysdir
, MAX_PATH
);
1638 len_path
= len_sysdir
+ sizeof(color_path
) / sizeof(color_path
[0]) - 1;
1642 if (!(profile
= HeapAlloc( GetProcessHeap(), 0, (len_path
+ len
) * sizeof(WCHAR
) )))
1644 RegCloseKey( hkey
);
1647 res
= RegEnumValueW( hkey
, index
, profile
+ len_path
, &len
, NULL
, NULL
, NULL
, NULL
);
1648 while (res
== ERROR_MORE_DATA
)
1651 HeapFree( GetProcessHeap(), 0, profile
);
1652 if (!(profile
= HeapAlloc( GetProcessHeap(), 0, (len_path
+ len
) * sizeof(WCHAR
) )))
1654 RegCloseKey( hkey
);
1657 res
= RegEnumValueW( hkey
, index
, profile
+ len_path
, &len
, NULL
, NULL
, NULL
, NULL
);
1659 if (res
!= ERROR_SUCCESS
)
1661 HeapFree( GetProcessHeap(), 0, profile
);
1664 memcpy( profile
, sysdir
, len_sysdir
* sizeof(WCHAR
) );
1665 memcpy( profile
+ len_sysdir
, color_path
, sizeof(color_path
) - sizeof(WCHAR
) );
1666 ret
= proc( profile
, lparam
);
1667 HeapFree( GetProcessHeap(), 0, profile
);
1671 RegCloseKey( hkey
);