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 static 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 CDECL
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
)
367 pixmap
= XCreatePixmap( gdi_display
, root_window
, 8, 8, physDev
->depth
);
368 image
= XGetImage( gdi_display
, physDev
->brush
.pixmap
, 0, 0, 8, 8,
369 AllPlanes
, ZPixmap
);
370 for (y
= 0; y
< 8; y
++)
371 for (x
= 0; x
< 8; x
++)
372 XPutPixel( image
, x
, y
,
373 X11DRV_PALETTE_XPixelToPalette
[XGetPixel( image
, x
, y
)] );
374 XPutImage( gdi_display
, pixmap
, gc
, image
, 0, 0, 0, 0, 8, 8 );
375 XDestroyImage( image
);
378 else val
.tile
= physDev
->brush
.pixmap
;
386 GetBrushOrgEx( physDev
->dev
.hdc
, &pt
);
387 val
.ts_x_origin
= physDev
->dc_rect
.left
+ pt
.x
;
388 val
.ts_y_origin
= physDev
->dc_rect
.top
+ pt
.y
;
389 val
.fill_rule
= (GetPolyFillMode(physDev
->dev
.hdc
) == WINDING
) ? WindingRule
: EvenOddRule
;
390 XChangeGC( gdi_display
, gc
,
391 GCFunction
| GCForeground
| GCBackground
| GCFillStyle
|
392 GCFillRule
| GCTileStipXOrigin
| GCTileStipYOrigin
| mask
,
394 if (pixmap
) XFreePixmap( gdi_display
, pixmap
);
399 /***********************************************************************
400 * X11DRV_SetupGCForBrush
402 * Setup physDev->gc for drawing operations using current brush.
403 * Return FALSE if brush is BS_NULL, TRUE otherwise.
405 BOOL
X11DRV_SetupGCForBrush( X11DRV_PDEVICE
*physDev
)
407 return X11DRV_SetupGCForPatBlt( physDev
, physDev
->gc
, FALSE
);
411 /***********************************************************************
412 * X11DRV_SetupGCForPen
414 * Setup physDev->gc for drawing operations using current pen.
415 * Return FALSE if pen is PS_NULL, TRUE otherwise.
417 static BOOL
X11DRV_SetupGCForPen( X11DRV_PDEVICE
*physDev
)
420 UINT rop2
= GetROP2(physDev
->dev
.hdc
);
422 if (physDev
->pen
.style
== PS_NULL
) return FALSE
;
427 val
.foreground
= BlackPixel( gdi_display
, DefaultScreen(gdi_display
) );
428 val
.function
= GXcopy
;
431 val
.foreground
= WhitePixel( gdi_display
, DefaultScreen(gdi_display
) );
432 val
.function
= GXcopy
;
435 val
.foreground
= physDev
->pen
.pixel
;
436 /* It is very unlikely someone wants to XOR with 0 */
437 /* This fixes the rubber-drawings in paintbrush */
438 if (val
.foreground
== 0)
439 val
.foreground
= (WhitePixel( gdi_display
, DefaultScreen(gdi_display
) ) ^
440 BlackPixel( gdi_display
, DefaultScreen(gdi_display
) ));
441 val
.function
= GXxor
;
444 val
.foreground
= physDev
->pen
.pixel
;
445 val
.function
= X11DRV_XROPfunction
[rop2
-1];
447 val
.background
= X11DRV_PALETTE_ToPhysical( physDev
, GetBkColor(physDev
->dev
.hdc
) );
448 val
.fill_style
= FillSolid
;
449 val
.line_width
= physDev
->pen
.width
;
450 if (val
.line_width
<= 1) {
451 val
.cap_style
= CapNotLast
;
453 switch (physDev
->pen
.endcap
)
455 case PS_ENDCAP_SQUARE
:
456 val
.cap_style
= CapProjecting
;
459 val
.cap_style
= CapButt
;
461 case PS_ENDCAP_ROUND
:
463 val
.cap_style
= CapRound
;
466 switch (physDev
->pen
.linejoin
)
469 val
.join_style
= JoinBevel
;
472 val
.join_style
= JoinMiter
;
476 val
.join_style
= JoinRound
;
479 if (physDev
->pen
.dash_len
)
480 val
.line_style
= ((GetBkMode(physDev
->dev
.hdc
) == OPAQUE
) && (!physDev
->pen
.ext
))
481 ? LineDoubleDash
: LineOnOffDash
;
483 val
.line_style
= LineSolid
;
485 if (physDev
->pen
.dash_len
)
486 XSetDashes( gdi_display
, physDev
->gc
, 0, physDev
->pen
.dashes
, physDev
->pen
.dash_len
);
487 XChangeGC( gdi_display
, physDev
->gc
,
488 GCFunction
| GCForeground
| GCBackground
| GCLineWidth
|
489 GCLineStyle
| GCCapStyle
| GCJoinStyle
| GCFillStyle
, &val
);
494 /***********************************************************************
497 * Performs a world-to-viewport transformation on the specified width.
499 INT
X11DRV_XWStoDS( HDC hdc
, INT width
)
507 LPtoDP( hdc
, pt
, 2 );
508 return pt
[1].x
- pt
[0].x
;
511 /***********************************************************************
514 * Performs a world-to-viewport transformation on the specified height.
516 INT
X11DRV_YWStoDS( HDC hdc
, INT height
)
524 LPtoDP( hdc
, pt
, 2 );
525 return pt
[1].y
- pt
[0].y
;
528 /***********************************************************************
531 BOOL CDECL
X11DRV_LineTo( PHYSDEV dev
, INT x
, INT y
)
533 X11DRV_PDEVICE
*physDev
= get_x11drv_dev( dev
);
536 GetCurrentPositionEx( dev
->hdc
, &pt
[0] );
539 LPtoDP( dev
->hdc
, pt
, 2 );
540 add_pen_device_bounds( physDev
, pt
, 2 );
542 if (X11DRV_SetupGCForPen( physDev
))
543 XDrawLine(gdi_display
, physDev
->drawable
, physDev
->gc
,
544 physDev
->dc_rect
.left
+ pt
[0].x
, physDev
->dc_rect
.top
+ pt
[0].y
,
545 physDev
->dc_rect
.left
+ pt
[1].x
, physDev
->dc_rect
.top
+ pt
[1].y
);
551 /***********************************************************************
554 * Helper functions for Arc(), Chord() and Pie().
555 * 'lines' is the number of lines to draw: 0 for Arc, 1 for Chord, 2 for Pie.
558 static BOOL
X11DRV_DrawArc( PHYSDEV dev
, INT left
, INT top
, INT right
, INT bottom
,
559 INT xstart
, INT ystart
, INT xend
, INT yend
, INT lines
)
561 X11DRV_PDEVICE
*physDev
= get_x11drv_dev( dev
);
562 INT xcenter
, ycenter
, istart_angle
, idiff_angle
;
564 double start_angle
, end_angle
;
567 RECT rc
= get_device_rect( dev
->hdc
, left
, top
, right
, bottom
);
573 LPtoDP(dev
->hdc
, &start
, 1);
574 LPtoDP(dev
->hdc
, &end
, 1);
576 if ((rc
.left
== rc
.right
) || (rc
.top
== rc
.bottom
)
577 ||(lines
&& ((rc
.right
-rc
.left
==1)||(rc
.bottom
-rc
.top
==1)))) return TRUE
;
579 if (GetArcDirection( dev
->hdc
) == AD_CLOCKWISE
)
580 { POINT tmp
= start
; start
= end
; end
= tmp
; }
582 oldwidth
= width
= physDev
->pen
.width
;
583 if (!width
) width
= 1;
584 if(physDev
->pen
.style
== PS_NULL
) width
= 0;
586 if (physDev
->pen
.style
== PS_INSIDEFRAME
)
588 if (2*width
> (rc
.right
-rc
.left
)) width
=(rc
.right
-rc
.left
+ 1)/2;
589 if (2*width
> (rc
.bottom
-rc
.top
)) width
=(rc
.bottom
-rc
.top
+ 1)/2;
590 rc
.left
+= width
/ 2;
591 rc
.right
-= (width
- 1) / 2;
593 rc
.bottom
-= (width
- 1) / 2;
595 if(width
== 0) width
= 1; /* more accurate */
596 physDev
->pen
.width
= width
;
598 xcenter
= (rc
.right
+ rc
.left
) / 2;
599 ycenter
= (rc
.bottom
+ rc
.top
) / 2;
600 start_angle
= atan2( (double)(ycenter
-start
.y
)*(rc
.right
-rc
.left
),
601 (double)(start
.x
-xcenter
)*(rc
.bottom
-rc
.top
) );
602 end_angle
= atan2( (double)(ycenter
-end
.y
)*(rc
.right
-rc
.left
),
603 (double)(end
.x
-xcenter
)*(rc
.bottom
-rc
.top
) );
604 if ((start
.x
==end
.x
)&&(start
.y
==end
.y
))
605 { /* A lazy program delivers xstart=xend=ystart=yend=0) */
609 else /* notorious cases */
610 if ((start_angle
== PI
)&&( end_angle
<0))
613 if ((end_angle
== PI
)&&( start_angle
<0))
615 istart_angle
= (INT
)(start_angle
* 180 * 64 / PI
+ 0.5);
616 idiff_angle
= (INT
)((end_angle
- start_angle
) * 180 * 64 / PI
+ 0.5);
617 if (idiff_angle
<= 0) idiff_angle
+= 360 * 64;
619 /* Fill arc with brush if Chord() or Pie() */
621 if ((lines
> 0) && X11DRV_SetupGCForBrush( physDev
)) {
622 XSetArcMode( gdi_display
, physDev
->gc
, (lines
==1) ? ArcChord
: ArcPieSlice
);
623 XFillArc( gdi_display
, physDev
->drawable
, physDev
->gc
,
624 physDev
->dc_rect
.left
+ rc
.left
, physDev
->dc_rect
.top
+ rc
.top
,
625 rc
.right
-rc
.left
-1, rc
.bottom
-rc
.top
-1, istart_angle
, idiff_angle
);
628 /* Draw arc and lines */
630 if (X11DRV_SetupGCForPen( physDev
))
632 XDrawArc( gdi_display
, physDev
->drawable
, physDev
->gc
,
633 physDev
->dc_rect
.left
+ rc
.left
, physDev
->dc_rect
.top
+ rc
.top
,
634 rc
.right
-rc
.left
-1, rc
.bottom
-rc
.top
-1, istart_angle
, idiff_angle
);
636 /* use the truncated values */
637 start_angle
=(double)istart_angle
*PI
/64./180.;
638 end_angle
=(double)(istart_angle
+idiff_angle
)*PI
/64./180.;
639 /* calculate the endpoints and round correctly */
640 points
[0].x
= (int) floor(physDev
->dc_rect
.left
+ (rc
.right
+rc
.left
)/2.0 +
641 cos(start_angle
) * (rc
.right
-rc
.left
-width
*2+2) / 2. + 0.5);
642 points
[0].y
= (int) floor(physDev
->dc_rect
.top
+ (rc
.top
+rc
.bottom
)/2.0 -
643 sin(start_angle
) * (rc
.bottom
-rc
.top
-width
*2+2) / 2. + 0.5);
644 points
[1].x
= (int) floor(physDev
->dc_rect
.left
+ (rc
.right
+rc
.left
)/2.0 +
645 cos(end_angle
) * (rc
.right
-rc
.left
-width
*2+2) / 2. + 0.5);
646 points
[1].y
= (int) floor(physDev
->dc_rect
.top
+ (rc
.top
+rc
.bottom
)/2.0 -
647 sin(end_angle
) * (rc
.bottom
-rc
.top
-width
*2+2) / 2. + 0.5);
649 /* OK, this stuff is optimized for Xfree86
650 * which is probably the server most used by
651 * wine users. Other X servers will not
652 * display correctly. (eXceed for instance)
653 * so if you feel you must make changes, make sure that
654 * you either use Xfree86 or separate your changes
655 * from these (compile switch or whatever)
659 points
[3] = points
[1];
660 points
[1].x
= physDev
->dc_rect
.left
+ xcenter
;
661 points
[1].y
= physDev
->dc_rect
.top
+ ycenter
;
662 points
[2] = points
[1];
663 dx1
=points
[1].x
-points
[0].x
;
664 dy1
=points
[1].y
-points
[0].y
;
665 if(((rc
.top
-rc
.bottom
) | -2) == -2)
666 if(dy1
>0) points
[1].y
--;
668 if (((-dx1
)*64)<=ABS(dy1
)*37) points
[0].x
--;
669 if(((-dx1
*9))<(dy1
*16)) points
[0].y
--;
670 if( dy1
<0 && ((dx1
*9)) < (dy1
*16)) points
[0].y
--;
672 if(dy1
< 0) points
[0].y
--;
673 if(((rc
.right
-rc
.left
) | -2) == -2) points
[1].x
--;
675 dx1
=points
[3].x
-points
[2].x
;
676 dy1
=points
[3].y
-points
[2].y
;
677 if(((rc
.top
-rc
.bottom
) | -2 ) == -2)
678 if(dy1
< 0) points
[2].y
--;
680 if( dy1
>0) points
[3].y
--;
681 if(((rc
.right
-rc
.left
) | -2) == -2 ) points
[2].x
--;
684 if( dx1
* 64 < dy1
* -37 ) points
[3].x
--;
688 XDrawLines( gdi_display
, physDev
->drawable
, physDev
->gc
,
689 points
, lines
+1, CoordModeOrigin
);
693 physDev
->pen
.width
= oldwidth
;
694 add_pen_device_bounds( physDev
, (POINT
*)&rc
, 2 );
699 /***********************************************************************
702 BOOL CDECL
X11DRV_Arc( PHYSDEV dev
, INT left
, INT top
, INT right
, INT bottom
,
703 INT xstart
, INT ystart
, INT xend
, INT yend
)
705 return X11DRV_DrawArc( dev
, left
, top
, right
, bottom
, xstart
, ystart
, xend
, yend
, 0 );
709 /***********************************************************************
712 BOOL CDECL
X11DRV_Pie( PHYSDEV dev
, INT left
, INT top
, INT right
, INT bottom
,
713 INT xstart
, INT ystart
, INT xend
, INT yend
)
715 return X11DRV_DrawArc( dev
, left
, top
, right
, bottom
, xstart
, ystart
, xend
, yend
, 2 );
718 /***********************************************************************
721 BOOL CDECL
X11DRV_Chord( PHYSDEV dev
, INT left
, INT top
, INT right
, INT bottom
,
722 INT xstart
, INT ystart
, INT xend
, INT yend
)
724 return X11DRV_DrawArc( dev
, left
, top
, right
, bottom
, xstart
, ystart
, xend
, yend
, 1 );
728 /***********************************************************************
731 BOOL CDECL
X11DRV_Ellipse( PHYSDEV dev
, INT left
, INT top
, INT right
, INT bottom
)
733 X11DRV_PDEVICE
*physDev
= get_x11drv_dev( dev
);
735 RECT rc
= get_device_rect( dev
->hdc
, left
, top
, right
, bottom
);
737 if ((rc
.left
== rc
.right
) || (rc
.top
== rc
.bottom
)) return TRUE
;
739 oldwidth
= width
= physDev
->pen
.width
;
740 if (!width
) width
= 1;
741 if(physDev
->pen
.style
== PS_NULL
) width
= 0;
743 if (physDev
->pen
.style
== PS_INSIDEFRAME
)
745 if (2*width
> (rc
.right
-rc
.left
)) width
=(rc
.right
-rc
.left
+ 1)/2;
746 if (2*width
> (rc
.bottom
-rc
.top
)) width
=(rc
.bottom
-rc
.top
+ 1)/2;
747 rc
.left
+= width
/ 2;
748 rc
.right
-= (width
- 1) / 2;
750 rc
.bottom
-= (width
- 1) / 2;
752 if(width
== 0) width
= 1; /* more accurate */
753 physDev
->pen
.width
= width
;
755 if (X11DRV_SetupGCForBrush( physDev
))
756 XFillArc( gdi_display
, physDev
->drawable
, physDev
->gc
,
757 physDev
->dc_rect
.left
+ rc
.left
, physDev
->dc_rect
.top
+ rc
.top
,
758 rc
.right
-rc
.left
-1, rc
.bottom
-rc
.top
-1, 0, 360*64 );
760 if (X11DRV_SetupGCForPen( physDev
))
761 XDrawArc( gdi_display
, physDev
->drawable
, physDev
->gc
,
762 physDev
->dc_rect
.left
+ rc
.left
, physDev
->dc_rect
.top
+ rc
.top
,
763 rc
.right
-rc
.left
-1, rc
.bottom
-rc
.top
-1, 0, 360*64 );
765 physDev
->pen
.width
= oldwidth
;
766 add_pen_device_bounds( physDev
, (POINT
*)&rc
, 2 );
771 /***********************************************************************
774 BOOL CDECL
X11DRV_Rectangle(PHYSDEV dev
, INT left
, INT top
, INT right
, INT bottom
)
776 X11DRV_PDEVICE
*physDev
= get_x11drv_dev( dev
);
777 INT width
, oldwidth
, oldjoinstyle
;
778 RECT rc
= get_device_rect( dev
->hdc
, left
, top
, right
, bottom
);
780 TRACE("(%d %d %d %d)\n", left
, top
, right
, bottom
);
782 if ((rc
.left
== rc
.right
) || (rc
.top
== rc
.bottom
)) return TRUE
;
784 oldwidth
= width
= physDev
->pen
.width
;
785 if (!width
) width
= 1;
786 if(physDev
->pen
.style
== PS_NULL
) width
= 0;
788 if (physDev
->pen
.style
== PS_INSIDEFRAME
)
790 if (2*width
> (rc
.right
-rc
.left
)) width
=(rc
.right
-rc
.left
+ 1)/2;
791 if (2*width
> (rc
.bottom
-rc
.top
)) width
=(rc
.bottom
-rc
.top
+ 1)/2;
792 rc
.left
+= width
/ 2;
793 rc
.right
-= (width
- 1) / 2;
795 rc
.bottom
-= (width
- 1) / 2;
797 if(width
== 1) width
= 0;
798 physDev
->pen
.width
= width
;
799 oldjoinstyle
= physDev
->pen
.linejoin
;
800 if(physDev
->pen
.type
!= PS_GEOMETRIC
)
801 physDev
->pen
.linejoin
= PS_JOIN_MITER
;
805 if ((rc
.right
>= rc
.left
+ width
) && (rc
.bottom
>= rc
.top
+ width
))
807 if (X11DRV_SetupGCForBrush( physDev
))
808 XFillRectangle( gdi_display
, physDev
->drawable
, physDev
->gc
,
809 physDev
->dc_rect
.left
+ rc
.left
+ (width
+ 1) / 2,
810 physDev
->dc_rect
.top
+ rc
.top
+ (width
+ 1) / 2,
811 rc
.right
-rc
.left
-width
, rc
.bottom
-rc
.top
-width
);
813 if (X11DRV_SetupGCForPen( physDev
))
814 XDrawRectangle( gdi_display
, physDev
->drawable
, physDev
->gc
,
815 physDev
->dc_rect
.left
+ rc
.left
, physDev
->dc_rect
.top
+ rc
.top
,
816 rc
.right
-rc
.left
, rc
.bottom
-rc
.top
);
818 physDev
->pen
.width
= oldwidth
;
819 physDev
->pen
.linejoin
= oldjoinstyle
;
820 add_pen_device_bounds( physDev
, (POINT
*)&rc
, 2 );
824 /***********************************************************************
827 BOOL CDECL
X11DRV_RoundRect( PHYSDEV dev
, INT left
, INT top
, INT right
, INT bottom
,
828 INT ell_width
, INT ell_height
)
830 X11DRV_PDEVICE
*physDev
= get_x11drv_dev( dev
);
831 INT width
, oldwidth
, oldendcap
;
833 RECT rc
= get_device_rect( dev
->hdc
, left
, top
, right
, bottom
);
835 TRACE("(%d %d %d %d %d %d\n",
836 left
, top
, right
, bottom
, ell_width
, ell_height
);
838 if ((rc
.left
== rc
.right
) || (rc
.top
== rc
.bottom
))
841 /* Make sure ell_width and ell_height are >= 1 otherwise XDrawArc gets
842 called with width/height < 0 */
843 pts
[0].x
= pts
[0].y
= 0;
844 pts
[1].x
= ell_width
;
845 pts
[1].y
= ell_height
;
846 LPtoDP(dev
->hdc
, pts
, 2);
847 ell_width
= max(abs( pts
[1].x
- pts
[0].x
), 1);
848 ell_height
= max(abs( pts
[1].y
- pts
[0].y
), 1);
850 oldwidth
= width
= physDev
->pen
.width
;
851 oldendcap
= physDev
->pen
.endcap
;
852 if (!width
) width
= 1;
853 if(physDev
->pen
.style
== PS_NULL
) width
= 0;
855 if (physDev
->pen
.style
== PS_INSIDEFRAME
)
857 if (2*width
> (rc
.right
-rc
.left
)) width
=(rc
.right
-rc
.left
+ 1)/2;
858 if (2*width
> (rc
.bottom
-rc
.top
)) width
=(rc
.bottom
-rc
.top
+ 1)/2;
859 rc
.left
+= width
/ 2;
860 rc
.right
-= (width
- 1) / 2;
862 rc
.bottom
-= (width
- 1) / 2;
864 if(width
== 0) width
= 1;
865 physDev
->pen
.width
= width
;
866 physDev
->pen
.endcap
= PS_ENDCAP_SQUARE
;
868 if (X11DRV_SetupGCForBrush( physDev
))
870 if (ell_width
> (rc
.right
-rc
.left
) )
871 if (ell_height
> (rc
.bottom
-rc
.top
) )
872 XFillArc( gdi_display
, physDev
->drawable
, physDev
->gc
,
873 physDev
->dc_rect
.left
+ rc
.left
, physDev
->dc_rect
.top
+ rc
.top
,
874 rc
.right
- rc
.left
- 1, rc
.bottom
- rc
.top
- 1,
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, ell_height
, 0, 180 * 64 );
880 XFillArc( gdi_display
, physDev
->drawable
, physDev
->gc
,
881 physDev
->dc_rect
.left
+ rc
.left
,
882 physDev
->dc_rect
.top
+ rc
.bottom
- ell_height
- 1,
883 rc
.right
- rc
.left
- 1, ell_height
, 180 * 64,
886 else if (ell_height
> (rc
.bottom
-rc
.top
) ){
887 XFillArc( gdi_display
, physDev
->drawable
, physDev
->gc
,
888 physDev
->dc_rect
.left
+ rc
.left
, physDev
->dc_rect
.top
+ rc
.top
,
889 ell_width
, rc
.bottom
- rc
.top
- 1, 90 * 64, 180 * 64 );
890 XFillArc( gdi_display
, physDev
->drawable
, physDev
->gc
,
891 physDev
->dc_rect
.left
+ rc
.right
- ell_width
- 1, physDev
->dc_rect
.top
+ rc
.top
,
892 ell_width
, rc
.bottom
- rc
.top
- 1, 270 * 64, 180 * 64 );
894 XFillArc( gdi_display
, physDev
->drawable
, physDev
->gc
,
895 physDev
->dc_rect
.left
+ rc
.left
, physDev
->dc_rect
.top
+ rc
.top
,
896 ell_width
, ell_height
, 90 * 64, 90 * 64 );
897 XFillArc( gdi_display
, physDev
->drawable
, physDev
->gc
,
898 physDev
->dc_rect
.left
+ rc
.left
,
899 physDev
->dc_rect
.top
+ rc
.bottom
- ell_height
- 1,
900 ell_width
, ell_height
, 180 * 64, 90 * 64 );
901 XFillArc( gdi_display
, physDev
->drawable
, physDev
->gc
,
902 physDev
->dc_rect
.left
+ rc
.right
- ell_width
- 1,
903 physDev
->dc_rect
.top
+ rc
.bottom
- ell_height
- 1,
904 ell_width
, ell_height
, 270 * 64, 90 * 64 );
905 XFillArc( gdi_display
, physDev
->drawable
, physDev
->gc
,
906 physDev
->dc_rect
.left
+ rc
.right
- ell_width
- 1,
907 physDev
->dc_rect
.top
+ rc
.top
,
908 ell_width
, ell_height
, 0, 90 * 64 );
910 if (ell_width
< rc
.right
- rc
.left
)
912 XFillRectangle( gdi_display
, physDev
->drawable
, physDev
->gc
,
913 physDev
->dc_rect
.left
+ rc
.left
+ (ell_width
+ 1) / 2,
914 physDev
->dc_rect
.top
+ rc
.top
+ 1,
915 rc
.right
- rc
.left
- ell_width
- 1,
916 (ell_height
+ 1) / 2 - 1);
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
.bottom
- (ell_height
) / 2 - 1,
920 rc
.right
- rc
.left
- ell_width
- 1,
923 if (ell_height
< rc
.bottom
- rc
.top
)
925 XFillRectangle( gdi_display
, physDev
->drawable
, physDev
->gc
,
926 physDev
->dc_rect
.left
+ rc
.left
+ 1,
927 physDev
->dc_rect
.top
+ rc
.top
+ (ell_height
+ 1) / 2,
928 rc
.right
- rc
.left
- 2,
929 rc
.bottom
- rc
.top
- ell_height
- 1);
932 /* FIXME: this could be done with on X call
933 * more efficient and probably more correct
934 * on any X server: XDrawArcs will draw
935 * straight horizontal and vertical lines
936 * if width or height are zero.
938 * BTW this stuff is optimized for an Xfree86 server
939 * read the comments inside the X11DRV_DrawArc function
941 if (X11DRV_SetupGCForPen( physDev
))
943 if (ell_width
> (rc
.right
-rc
.left
) )
944 if (ell_height
> (rc
.bottom
-rc
.top
) )
945 XDrawArc( gdi_display
, physDev
->drawable
, physDev
->gc
,
946 physDev
->dc_rect
.left
+ rc
.left
, physDev
->dc_rect
.top
+ rc
.top
,
947 rc
.right
- rc
.left
- 1, rc
.bottom
- rc
.top
- 1, 0 , 360 * 64 );
949 XDrawArc( gdi_display
, physDev
->drawable
, physDev
->gc
,
950 physDev
->dc_rect
.left
+ rc
.left
, physDev
->dc_rect
.top
+ rc
.top
,
951 rc
.right
- rc
.left
- 1, ell_height
- 1, 0 , 180 * 64 );
952 XDrawArc( gdi_display
, physDev
->drawable
, physDev
->gc
,
953 physDev
->dc_rect
.left
+ rc
.left
,
954 physDev
->dc_rect
.top
+ rc
.bottom
- ell_height
,
955 rc
.right
- rc
.left
- 1, ell_height
- 1, 180 * 64 , 180 * 64 );
957 else if (ell_height
> (rc
.bottom
-rc
.top
) ){
958 XDrawArc( gdi_display
, physDev
->drawable
, physDev
->gc
,
959 physDev
->dc_rect
.left
+ rc
.left
, physDev
->dc_rect
.top
+ rc
.top
,
960 ell_width
- 1 , rc
.bottom
- rc
.top
- 1, 90 * 64 , 180 * 64 );
961 XDrawArc( gdi_display
, physDev
->drawable
, physDev
->gc
,
962 physDev
->dc_rect
.left
+ rc
.right
- ell_width
,
963 physDev
->dc_rect
.top
+ rc
.top
,
964 ell_width
- 1 , rc
.bottom
- rc
.top
- 1, 270 * 64 , 180 * 64 );
966 XDrawArc( gdi_display
, physDev
->drawable
, physDev
->gc
,
967 physDev
->dc_rect
.left
+ rc
.left
, physDev
->dc_rect
.top
+ rc
.top
,
968 ell_width
- 1, ell_height
- 1, 90 * 64, 90 * 64 );
969 XDrawArc( gdi_display
, physDev
->drawable
, physDev
->gc
,
970 physDev
->dc_rect
.left
+ rc
.left
, physDev
->dc_rect
.top
+ rc
.bottom
- ell_height
,
971 ell_width
- 1, ell_height
- 1, 180 * 64, 90 * 64 );
972 XDrawArc( gdi_display
, physDev
->drawable
, physDev
->gc
,
973 physDev
->dc_rect
.left
+ rc
.right
- ell_width
,
974 physDev
->dc_rect
.top
+ rc
.bottom
- ell_height
,
975 ell_width
- 1, ell_height
- 1, 270 * 64, 90 * 64 );
976 XDrawArc( gdi_display
, physDev
->drawable
, physDev
->gc
,
977 physDev
->dc_rect
.left
+ rc
.right
- ell_width
, physDev
->dc_rect
.top
+ rc
.top
,
978 ell_width
- 1, ell_height
- 1, 0, 90 * 64 );
980 if (ell_width
< rc
.right
- rc
.left
)
982 XDrawLine( gdi_display
, physDev
->drawable
, physDev
->gc
,
983 physDev
->dc_rect
.left
+ rc
.left
+ ell_width
/ 2,
984 physDev
->dc_rect
.top
+ rc
.top
,
985 physDev
->dc_rect
.left
+ rc
.right
- (ell_width
+1) / 2,
986 physDev
->dc_rect
.top
+ rc
.top
);
987 XDrawLine( gdi_display
, physDev
->drawable
, physDev
->gc
,
988 physDev
->dc_rect
.left
+ rc
.left
+ ell_width
/ 2 ,
989 physDev
->dc_rect
.top
+ rc
.bottom
- 1,
990 physDev
->dc_rect
.left
+ rc
.right
- (ell_width
+1)/ 2,
991 physDev
->dc_rect
.top
+ rc
.bottom
- 1);
993 if (ell_height
< rc
.bottom
- rc
.top
)
995 XDrawLine( gdi_display
, physDev
->drawable
, physDev
->gc
,
996 physDev
->dc_rect
.left
+ rc
.right
- 1,
997 physDev
->dc_rect
.top
+ rc
.top
+ ell_height
/ 2,
998 physDev
->dc_rect
.left
+ rc
.right
- 1,
999 physDev
->dc_rect
.top
+ rc
.bottom
- (ell_height
+1) / 2);
1000 XDrawLine( gdi_display
, physDev
->drawable
, physDev
->gc
,
1001 physDev
->dc_rect
.left
+ rc
.left
,
1002 physDev
->dc_rect
.top
+ rc
.top
+ ell_height
/ 2,
1003 physDev
->dc_rect
.left
+ rc
.left
,
1004 physDev
->dc_rect
.top
+ rc
.bottom
- (ell_height
+1) / 2);
1008 physDev
->pen
.width
= oldwidth
;
1009 physDev
->pen
.endcap
= oldendcap
;
1010 add_pen_device_bounds( physDev
, (POINT
*)&rc
, 2 );
1015 /***********************************************************************
1018 COLORREF CDECL
X11DRV_SetPixel( PHYSDEV dev
, INT x
, INT y
, COLORREF color
)
1020 X11DRV_PDEVICE
*physDev
= get_x11drv_dev( dev
);
1021 unsigned long pixel
;
1027 LPtoDP( dev
->hdc
, &pt
, 1 );
1028 pixel
= X11DRV_PALETTE_ToPhysical( physDev
, color
);
1030 XSetForeground( gdi_display
, physDev
->gc
, pixel
);
1031 XSetFunction( gdi_display
, physDev
->gc
, GXcopy
);
1032 XDrawPoint( gdi_display
, physDev
->drawable
, physDev
->gc
,
1033 physDev
->dc_rect
.left
+ pt
.x
, physDev
->dc_rect
.top
+ pt
.y
);
1035 SetRect( &rect
, pt
.x
, pt
.y
, pt
.x
+ 1, pt
.y
+ 1 );
1036 add_device_bounds( physDev
, &rect
);
1037 return X11DRV_PALETTE_ToLogical(physDev
, pixel
);
1041 /***********************************************************************
1044 BOOL CDECL
X11DRV_PaintRgn( PHYSDEV dev
, HRGN hrgn
)
1046 X11DRV_PDEVICE
*physDev
= get_x11drv_dev( dev
);
1049 if (X11DRV_SetupGCForBrush( physDev
))
1053 RGNDATA
*data
= X11DRV_GetRegionData( hrgn
, dev
->hdc
);
1055 if (!data
) return FALSE
;
1056 rect
= (XRectangle
*)data
->Buffer
;
1057 for (i
= 0; i
< data
->rdh
.nCount
; i
++)
1059 rect
[i
].x
+= physDev
->dc_rect
.left
;
1060 rect
[i
].y
+= physDev
->dc_rect
.top
;
1063 XFillRectangles( gdi_display
, physDev
->drawable
, physDev
->gc
, rect
, data
->rdh
.nCount
);
1064 HeapFree( GetProcessHeap(), 0, data
);
1066 if (GetRgnBox( hrgn
, &rc
))
1068 LPtoDP( dev
->hdc
, (POINT
*)&rc
, 2 );
1069 add_device_bounds( physDev
, &rc
);
1074 /**********************************************************************
1077 BOOL CDECL
X11DRV_Polygon( PHYSDEV dev
, const POINT
* pt
, INT count
)
1079 X11DRV_PDEVICE
*physDev
= get_x11drv_dev( dev
);
1084 points
= HeapAlloc( GetProcessHeap(), 0, count
* sizeof(*pt
) );
1085 if (!points
) return FALSE
;
1086 memcpy( points
, pt
, count
* sizeof(*pt
) );
1087 LPtoDP( dev
->hdc
, points
, count
);
1088 add_pen_device_bounds( physDev
, points
, count
);
1090 if (!(xpoints
= HeapAlloc( GetProcessHeap(), 0, sizeof(XPoint
) * (count
+1) )))
1092 HeapFree( GetProcessHeap(), 0, points
);
1095 for (i
= 0; i
< count
; i
++)
1097 xpoints
[i
].x
= physDev
->dc_rect
.left
+ points
[i
].x
;
1098 xpoints
[i
].y
= physDev
->dc_rect
.top
+ points
[i
].y
;
1100 xpoints
[count
] = xpoints
[0];
1102 if (X11DRV_SetupGCForBrush( physDev
))
1103 XFillPolygon( gdi_display
, physDev
->drawable
, physDev
->gc
,
1104 xpoints
, count
+1, Complex
, CoordModeOrigin
);
1106 if (X11DRV_SetupGCForPen ( physDev
))
1107 XDrawLines( gdi_display
, physDev
->drawable
, physDev
->gc
,
1108 xpoints
, count
+1, CoordModeOrigin
);
1110 HeapFree( GetProcessHeap(), 0, xpoints
);
1111 HeapFree( GetProcessHeap(), 0, points
);
1116 /**********************************************************************
1117 * X11DRV_PolyPolygon
1119 BOOL CDECL
X11DRV_PolyPolygon( PHYSDEV dev
, const POINT
* pt
, const INT
* counts
, UINT polygons
)
1121 X11DRV_PDEVICE
*physDev
= get_x11drv_dev( dev
);
1122 DWORD total
= 0, max
= 0, pos
, i
;
1126 for (i
= 0; i
< polygons
; i
++)
1128 if (counts
[i
] < 2) return FALSE
;
1129 if (counts
[i
] > max
) max
= counts
[i
];
1133 points
= HeapAlloc( GetProcessHeap(), 0, total
* sizeof(*pt
) );
1134 if (!points
) return FALSE
;
1135 memcpy( points
, pt
, total
* sizeof(*pt
) );
1136 LPtoDP( dev
->hdc
, points
, total
);
1137 add_pen_device_bounds( physDev
, points
, total
);
1139 if (X11DRV_SetupGCForBrush( physDev
))
1142 HRGN hrgn
= CreatePolyPolygonRgn( points
, counts
, polygons
, GetPolyFillMode( dev
->hdc
) );
1143 RGNDATA
*data
= X11DRV_GetRegionData( hrgn
, 0 );
1145 DeleteObject( hrgn
);
1146 if (!data
) goto done
;
1147 rect
= (XRectangle
*)data
->Buffer
;
1148 for (i
= 0; i
< data
->rdh
.nCount
; i
++)
1150 rect
[i
].x
+= physDev
->dc_rect
.left
;
1151 rect
[i
].y
+= physDev
->dc_rect
.top
;
1154 XFillRectangles( gdi_display
, physDev
->drawable
, physDev
->gc
, rect
, data
->rdh
.nCount
);
1155 HeapFree( GetProcessHeap(), 0, data
);
1158 if (X11DRV_SetupGCForPen ( physDev
))
1163 if (!(xpoints
= HeapAlloc( GetProcessHeap(), 0, sizeof(XPoint
) * (max
+ 1) ))) goto done
;
1164 for (i
= pos
= 0; i
< polygons
; pos
+= counts
[i
++])
1166 for (j
= 0; j
< counts
[i
]; j
++)
1168 xpoints
[j
].x
= physDev
->dc_rect
.left
+ points
[pos
+ j
].x
;
1169 xpoints
[j
].y
= physDev
->dc_rect
.top
+ points
[pos
+ j
].y
;
1171 xpoints
[j
] = xpoints
[0];
1172 XDrawLines( gdi_display
, physDev
->drawable
, physDev
->gc
, xpoints
, j
+ 1, CoordModeOrigin
);
1174 HeapFree( GetProcessHeap(), 0, xpoints
);
1179 HeapFree( GetProcessHeap(), 0, points
);
1184 /**********************************************************************
1185 * X11DRV_PolyPolyline
1187 BOOL CDECL
X11DRV_PolyPolyline( PHYSDEV dev
, const POINT
* pt
, const DWORD
* counts
, DWORD polylines
)
1189 X11DRV_PDEVICE
*physDev
= get_x11drv_dev( dev
);
1190 DWORD total
= 0, max
= 0, pos
, i
, j
;
1193 for (i
= 0; i
< polylines
; i
++)
1195 if (counts
[i
] < 2) return FALSE
;
1196 if (counts
[i
] > max
) max
= counts
[i
];
1200 points
= HeapAlloc( GetProcessHeap(), 0, total
* sizeof(*pt
) );
1201 if (!points
) return FALSE
;
1202 memcpy( points
, pt
, total
* sizeof(*pt
) );
1203 LPtoDP( dev
->hdc
, points
, total
);
1204 add_pen_device_bounds( physDev
, points
, total
);
1206 if (X11DRV_SetupGCForPen ( physDev
))
1210 if (!(xpoints
= HeapAlloc( GetProcessHeap(), 0, sizeof(XPoint
) * max
)))
1212 HeapFree( GetProcessHeap(), 0, points
);
1215 for (i
= pos
= 0; i
< polylines
; pos
+= counts
[i
++])
1217 for (j
= 0; j
< counts
[i
]; j
++)
1219 xpoints
[j
].x
= physDev
->dc_rect
.left
+ points
[pos
+ j
].x
;
1220 xpoints
[j
].y
= physDev
->dc_rect
.top
+ points
[pos
+ j
].y
;
1222 XDrawLines( gdi_display
, physDev
->drawable
, physDev
->gc
, xpoints
, j
, CoordModeOrigin
);
1224 HeapFree( GetProcessHeap(), 0, xpoints
);
1226 HeapFree( GetProcessHeap(), 0, points
);
1230 /* helper for path stroking and filling functions */
1231 static BOOL
x11drv_stroke_and_fill_path( PHYSDEV dev
, BOOL stroke
, BOOL fill
)
1233 X11DRV_PDEVICE
*physDev
= get_x11drv_dev( dev
);
1240 FlattenPath( dev
->hdc
);
1241 if ((size
= GetPath( dev
->hdc
, NULL
, NULL
, 0 )) == -1) return FALSE
;
1244 AbortPath( dev
->hdc
);
1247 xpoints
= HeapAlloc( GetProcessHeap(), 0, (size
+ 1) * sizeof(*xpoints
) );
1248 points
= HeapAlloc( GetProcessHeap(), 0, size
* sizeof(*points
) );
1249 flags
= HeapAlloc( GetProcessHeap(), 0, size
* sizeof(*flags
) );
1250 if (!points
|| !flags
|| !xpoints
) goto done
;
1251 if (GetPath( dev
->hdc
, points
, flags
, size
) == -1) goto done
;
1252 LPtoDP( dev
->hdc
, points
, size
);
1254 if (fill
&& X11DRV_SetupGCForBrush( physDev
))
1257 HRGN hrgn
= PathToRegion( dev
->hdc
);
1258 RGNDATA
*data
= X11DRV_GetRegionData( hrgn
, 0 );
1260 DeleteObject( hrgn
);
1261 if (!data
) goto done
;
1262 rect
= (XRectangle
*)data
->Buffer
;
1263 for (i
= 0; i
< data
->rdh
.nCount
; i
++)
1265 rect
[i
].x
+= physDev
->dc_rect
.left
;
1266 rect
[i
].y
+= physDev
->dc_rect
.top
;
1269 XFillRectangles( gdi_display
, physDev
->drawable
, physDev
->gc
, rect
, data
->rdh
.nCount
);
1270 HeapFree( GetProcessHeap(), 0, data
);
1273 if (stroke
&& X11DRV_SetupGCForPen ( physDev
))
1275 for (i
= j
= 0; i
< size
; i
++, j
++)
1277 if (flags
[i
] == PT_MOVETO
)
1281 if (fill
|| (flags
[i
- 1] & PT_CLOSEFIGURE
)) xpoints
[j
++] = xpoints
[0];
1282 XDrawLines( gdi_display
, physDev
->drawable
, physDev
->gc
, xpoints
, j
, CoordModeOrigin
);
1286 xpoints
[j
].x
= physDev
->dc_rect
.left
+ points
[i
].x
;
1287 xpoints
[j
].y
= physDev
->dc_rect
.top
+ points
[i
].y
;
1291 if (fill
|| (flags
[i
- 1] & PT_CLOSEFIGURE
)) xpoints
[j
++] = xpoints
[0];
1292 XDrawLines( gdi_display
, physDev
->drawable
, physDev
->gc
, xpoints
, j
, CoordModeOrigin
);
1296 add_pen_device_bounds( physDev
, points
, size
);
1297 AbortPath( dev
->hdc
);
1301 HeapFree( GetProcessHeap(), 0, xpoints
);
1302 HeapFree( GetProcessHeap(), 0, points
);
1303 HeapFree( GetProcessHeap(), 0, flags
);
1307 /**********************************************************************
1310 BOOL CDECL
X11DRV_FillPath( PHYSDEV dev
)
1312 return x11drv_stroke_and_fill_path( dev
, FALSE
, TRUE
);
1315 /**********************************************************************
1316 * X11DRV_StrokeAndFillPath
1318 BOOL CDECL
X11DRV_StrokeAndFillPath( PHYSDEV dev
)
1320 return x11drv_stroke_and_fill_path( dev
, TRUE
, TRUE
);
1323 /**********************************************************************
1326 BOOL CDECL
X11DRV_StrokePath( PHYSDEV dev
)
1328 return x11drv_stroke_and_fill_path( dev
, TRUE
, FALSE
);
1332 /**********************************************************************
1333 * X11DRV_InternalFloodFill
1335 * Internal helper function for flood fill.
1336 * (xorg,yorg) is the origin of the X image relative to the drawable.
1337 * (x,y) is relative to the origin of the X image.
1339 static void X11DRV_InternalFloodFill(XImage
*image
, X11DRV_PDEVICE
*physDev
,
1342 unsigned long pixel
, WORD fillType
, RECT
*bounds
)
1346 #define TO_FLOOD(x,y) ((fillType == FLOODFILLBORDER) ? \
1347 (XGetPixel(image,x,y) != pixel) : \
1348 (XGetPixel(image,x,y) == pixel))
1350 if (!TO_FLOOD(x
,y
)) return;
1352 /* Find left and right boundaries */
1355 while ((left
> 0) && TO_FLOOD( left
-1, y
)) left
--;
1356 while ((right
< image
->width
) && TO_FLOOD( right
, y
)) right
++;
1357 bounds
->left
= min( bounds
->left
, left
);
1358 bounds
->top
= min( bounds
->top
, y
);
1359 bounds
->right
= max( bounds
->right
, right
);
1360 bounds
->bottom
= max( bounds
->bottom
, y
+ 1 );
1361 XFillRectangle( gdi_display
, physDev
->drawable
, physDev
->gc
,
1362 xOrg
+ left
, yOrg
+ y
, right
-left
, 1 );
1364 /* Set the pixels of this line so we don't fill it again */
1366 for (x
= left
; x
< right
; x
++)
1368 if (fillType
== FLOODFILLBORDER
) XPutPixel( image
, x
, y
, pixel
);
1369 else XPutPixel( image
, x
, y
, ~pixel
);
1372 /* Fill the line above */
1379 while ((x
< right
) && !TO_FLOOD(x
,y
)) x
++;
1380 if (x
>= right
) break;
1381 while ((x
< right
) && TO_FLOOD(x
,y
)) x
++;
1382 X11DRV_InternalFloodFill(image
, physDev
, x
-1, y
,
1383 xOrg
, yOrg
, pixel
, fillType
, bounds
);
1387 /* Fill the line below */
1389 if ((y
+= 2) < image
->height
)
1394 while ((x
< right
) && !TO_FLOOD(x
,y
)) x
++;
1395 if (x
>= right
) break;
1396 while ((x
< right
) && TO_FLOOD(x
,y
)) x
++;
1397 X11DRV_InternalFloodFill(image
, physDev
, x
-1, y
,
1398 xOrg
, yOrg
, pixel
, fillType
, bounds
);
1405 static int ExtFloodFillXGetImageErrorHandler( Display
*dpy
, XErrorEvent
*event
, void *arg
)
1407 return (event
->request_code
== X_GetImage
&& event
->error_code
== BadMatch
);
1410 /**********************************************************************
1411 * X11DRV_ExtFloodFill
1413 BOOL CDECL
X11DRV_ExtFloodFill( PHYSDEV dev
, INT x
, INT y
, COLORREF color
, UINT fillType
)
1415 X11DRV_PDEVICE
*physDev
= get_x11drv_dev( dev
);
1420 TRACE("X11DRV_ExtFloodFill %d,%d %06x %d\n", x
, y
, color
, fillType
);
1424 LPtoDP( dev
->hdc
, &pt
, 1 );
1426 if (!physDev
->region
)
1430 rect
.right
= physDev
->dc_rect
.right
- physDev
->dc_rect
.left
;
1431 rect
.bottom
= physDev
->dc_rect
.bottom
- physDev
->dc_rect
.top
;
1435 if (!PtInRegion( physDev
->region
, pt
.x
, pt
.y
)) return FALSE
;
1436 GetRgnBox( physDev
->region
, &rect
);
1437 rect
.left
= max( rect
.left
, 0 );
1438 rect
.top
= max( rect
.top
, 0 );
1439 rect
.right
= min( rect
.right
, physDev
->dc_rect
.right
- physDev
->dc_rect
.left
);
1440 rect
.bottom
= min( rect
.bottom
, physDev
->dc_rect
.bottom
- physDev
->dc_rect
.top
);
1442 if (pt
.x
< rect
.left
|| pt
.x
>= rect
.right
|| pt
.y
< rect
.top
|| pt
.y
>= rect
.bottom
) return FALSE
;
1444 X11DRV_expect_error( gdi_display
, ExtFloodFillXGetImageErrorHandler
, NULL
);
1445 image
= XGetImage( gdi_display
, physDev
->drawable
,
1446 physDev
->dc_rect
.left
+ rect
.left
, physDev
->dc_rect
.top
+ rect
.top
,
1447 rect
.right
- rect
.left
, rect
.bottom
- rect
.top
,
1448 AllPlanes
, ZPixmap
);
1449 if(X11DRV_check_error()) image
= NULL
;
1450 if (!image
) return FALSE
;
1452 if (X11DRV_SetupGCForBrush( physDev
))
1454 unsigned long pixel
= X11DRV_PALETTE_ToPhysical( physDev
, color
);
1456 reset_bounds( &bounds
);
1458 X11DRV_InternalFloodFill(image
, physDev
,
1461 physDev
->dc_rect
.left
+ rect
.left
,
1462 physDev
->dc_rect
.top
+ rect
.top
,
1463 pixel
, fillType
, &bounds
);
1465 OffsetRect( &bounds
, rect
.left
, rect
.top
);
1466 add_device_bounds( physDev
, &bounds
);
1469 XDestroyImage( image
);
1473 /**********************************************************************
1474 * X11DRV_GradientFill
1476 BOOL CDECL
X11DRV_GradientFill( PHYSDEV dev
, TRIVERTEX
*vert_array
, ULONG nvert
,
1477 void *grad_array
, ULONG ngrad
, ULONG mode
)
1479 X11DRV_PDEVICE
*physdev
= get_x11drv_dev( dev
);
1480 const GRADIENT_RECT
*rect
= grad_array
;
1487 /* <= 16-bpp use dithering */
1488 if (physdev
->depth
<= 16) goto fallback
;
1492 case GRADIENT_FILL_RECT_H
:
1493 val
.function
= GXcopy
;
1494 val
.fill_style
= FillSolid
;
1496 val
.cap_style
= CapNotLast
;
1497 val
.line_style
= LineSolid
;
1498 XChangeGC( gdi_display
, physdev
->gc
,
1499 GCFunction
| GCLineWidth
| GCLineStyle
| GCCapStyle
| GCFillStyle
, &val
);
1500 reset_bounds( &bounds
);
1502 for (i
= 0; i
< ngrad
; i
++, rect
++)
1506 v
[0] = vert_array
[rect
->UpperLeft
];
1507 v
[1] = vert_array
[rect
->LowerRight
];
1512 LPtoDP( dev
->hdc
, pt
, 2 );
1513 dx
= pt
[1].x
- pt
[0].x
;
1515 if (dx
< 0) /* swap the colors */
1517 v
[0] = vert_array
[rect
->LowerRight
];
1518 v
[1] = vert_array
[rect
->UpperLeft
];
1521 rc
.left
= min( pt
[0].x
, pt
[1].x
);
1522 rc
.top
= min( pt
[0].y
, pt
[1].y
);
1523 rc
.right
= max( pt
[0].x
, pt
[1].x
);
1524 rc
.bottom
= max( pt
[0].y
, pt
[1].y
);
1525 add_bounds_rect( &bounds
, &rc
);
1526 for (x
= 0; x
< dx
; x
++)
1528 int color
= X11DRV_PALETTE_ToPhysical( physdev
,
1529 RGB( (v
[0].Red
* (dx
- x
) + v
[1].Red
* x
) / dx
/ 256,
1530 (v
[0].Green
* (dx
- x
) + v
[1].Green
* x
) / dx
/ 256,
1531 (v
[0].Blue
* (dx
- x
) + v
[1].Blue
* x
) / dx
/ 256) );
1533 XSetForeground( gdi_display
, physdev
->gc
, color
);
1534 XDrawLine( gdi_display
, physdev
->drawable
, physdev
->gc
,
1535 physdev
->dc_rect
.left
+ rc
.left
+ x
, physdev
->dc_rect
.top
+ rc
.top
,
1536 physdev
->dc_rect
.left
+ rc
.left
+ x
, physdev
->dc_rect
.top
+ rc
.bottom
);
1539 add_device_bounds( physdev
, &bounds
);
1542 case GRADIENT_FILL_RECT_V
:
1543 val
.function
= GXcopy
;
1544 val
.fill_style
= FillSolid
;
1546 val
.cap_style
= CapNotLast
;
1547 val
.line_style
= LineSolid
;
1548 XChangeGC( gdi_display
, physdev
->gc
,
1549 GCFunction
| GCLineWidth
| GCLineStyle
| GCCapStyle
| GCFillStyle
, &val
);
1550 reset_bounds( &bounds
);
1552 for (i
= 0; i
< ngrad
; i
++, rect
++)
1556 v
[0] = vert_array
[rect
->UpperLeft
];
1557 v
[1] = vert_array
[rect
->LowerRight
];
1562 LPtoDP( dev
->hdc
, pt
, 2 );
1563 dy
= pt
[1].y
- pt
[0].y
;
1565 if (dy
< 0) /* swap the colors */
1567 v
[0] = vert_array
[rect
->LowerRight
];
1568 v
[1] = vert_array
[rect
->UpperLeft
];
1571 rc
.left
= min( pt
[0].x
, pt
[1].x
);
1572 rc
.top
= min( pt
[0].y
, pt
[1].y
);
1573 rc
.right
= max( pt
[0].x
, pt
[1].x
);
1574 rc
.bottom
= max( pt
[0].y
, pt
[1].y
);
1575 add_bounds_rect( &bounds
, &rc
);
1576 for (y
= 0; y
< dy
; y
++)
1578 int color
= X11DRV_PALETTE_ToPhysical( physdev
,
1579 RGB( (v
[0].Red
* (dy
- y
) + v
[1].Red
* y
) / dy
/ 256,
1580 (v
[0].Green
* (dy
- y
) + v
[1].Green
* y
) / dy
/ 256,
1581 (v
[0].Blue
* (dy
- y
) + v
[1].Blue
* y
) / dy
/ 256) );
1583 XSetForeground( gdi_display
, physdev
->gc
, color
);
1584 XDrawLine( gdi_display
, physdev
->drawable
, physdev
->gc
,
1585 physdev
->dc_rect
.left
+ rc
.left
, physdev
->dc_rect
.top
+ rc
.top
+ y
,
1586 physdev
->dc_rect
.left
+ rc
.right
, physdev
->dc_rect
.top
+ rc
.top
+ y
);
1589 add_device_bounds( physdev
, &bounds
);
1594 dev
= GET_NEXT_PHYSDEV( dev
, pGradientFill
);
1595 return dev
->funcs
->pGradientFill( dev
, vert_array
, nvert
, grad_array
, ngrad
, mode
);
1598 static unsigned char *get_icm_profile( unsigned long *size
)
1602 unsigned long count
, remaining
;
1603 unsigned char *profile
, *ret
= NULL
;
1605 XGetWindowProperty( gdi_display
, DefaultRootWindow(gdi_display
),
1606 x11drv_atom(_ICC_PROFILE
), 0, ~0UL, False
, AnyPropertyType
,
1607 &type
, &format
, &count
, &remaining
, &profile
);
1608 *size
= get_property_size( format
, count
);
1609 if (format
&& count
)
1611 if ((ret
= HeapAlloc( GetProcessHeap(), 0, *size
))) memcpy( ret
, profile
, *size
);
1619 unsigned int unknown
[6];
1620 unsigned int state
[5];
1621 unsigned int count
[2];
1622 unsigned char buffer
[64];
1625 extern void WINAPI
A_SHAInit( sha_ctx
* );
1626 extern void WINAPI
A_SHAUpdate( sha_ctx
*, const unsigned char *, unsigned int );
1627 extern void WINAPI
A_SHAFinal( sha_ctx
*, unsigned char * );
1629 static const WCHAR mntr_key
[] =
1630 {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
1631 'W','i','n','d','o','w','s',' ','N','T','\\','C','u','r','r','e','n','t',
1632 'V','e','r','s','i','o','n','\\','I','C','M','\\','m','n','t','r',0};
1634 static const WCHAR color_path
[] =
1635 {'\\','s','p','o','o','l','\\','d','r','i','v','e','r','s','\\','c','o','l','o','r','\\',0};
1637 /***********************************************************************
1638 * GetICMProfile (X11DRV.@)
1640 BOOL CDECL
X11DRV_GetICMProfile( PHYSDEV dev
, LPDWORD size
, LPWSTR filename
)
1642 static const WCHAR srgb
[] =
1643 {'s','R','G','B',' ','C','o','l','o','r',' ','S','p','a','c','e',' ',
1644 'P','r','o','f','i','l','e','.','i','c','m',0};
1646 DWORD required
, len
;
1647 WCHAR profile
[MAX_PATH
], fullname
[2*MAX_PATH
+ ARRAY_SIZE( color_path
)];
1648 unsigned char *buffer
;
1649 unsigned long buflen
;
1651 if (!size
) return FALSE
;
1653 GetSystemDirectoryW( fullname
, MAX_PATH
);
1654 strcatW( fullname
, color_path
);
1656 len
= ARRAY_SIZE( profile
);
1657 if (!RegCreateKeyExW( HKEY_LOCAL_MACHINE
, mntr_key
, 0, NULL
, 0, KEY_ALL_ACCESS
, NULL
, &hkey
, NULL
) &&
1658 !RegEnumValueW( hkey
, 0, profile
, &len
, NULL
, NULL
, NULL
, NULL
)) /* FIXME handle multiple values */
1660 strcatW( fullname
, profile
);
1661 RegCloseKey( hkey
);
1663 else if ((buffer
= get_icm_profile( &buflen
)))
1665 static const WCHAR fmt
[] = {'%','0','2','x',0};
1666 static const WCHAR icm
[] = {'.','i','c','m',0};
1668 unsigned char sha1sum
[20];
1674 A_SHAUpdate( &ctx
, buffer
, buflen
);
1675 A_SHAFinal( &ctx
, sha1sum
);
1677 for (i
= 0; i
< sizeof(sha1sum
); i
++) sprintfW( &profile
[i
* 2], fmt
, sha1sum
[i
] );
1678 memcpy( &profile
[i
* 2], icm
, sizeof(icm
) );
1680 strcatW( fullname
, profile
);
1681 file
= CreateFileW( fullname
, GENERIC_WRITE
, 0, NULL
, CREATE_NEW
, 0, 0 );
1682 if (file
!= INVALID_HANDLE_VALUE
)
1686 if (!WriteFile( file
, buffer
, buflen
, &written
, NULL
) || written
!= buflen
)
1687 ERR( "Unable to write color profile\n" );
1688 CloseHandle( file
);
1690 HeapFree( GetProcessHeap(), 0, buffer
);
1692 else strcatW( fullname
, srgb
);
1694 required
= strlenW( fullname
) + 1;
1695 if (*size
< required
)
1698 SetLastError( ERROR_INSUFFICIENT_BUFFER
);
1703 strcpyW( filename
, fullname
);
1704 if (GetFileAttributesW( filename
) == INVALID_FILE_ATTRIBUTES
)
1705 WARN( "color profile not found\n" );
1711 /***********************************************************************
1712 * EnumICMProfiles (X11DRV.@)
1714 INT CDECL
X11DRV_EnumICMProfiles( PHYSDEV dev
, ICMENUMPROCW proc
, LPARAM lparam
)
1716 X11DRV_PDEVICE
*physDev
= get_x11drv_dev( dev
);
1718 DWORD len_sysdir
, len_path
, len
, index
= 0;
1719 WCHAR sysdir
[MAX_PATH
], *profile
;
1723 TRACE("%p, %p, %ld\n", physDev
, proc
, lparam
);
1725 if (RegOpenKeyExW( HKEY_LOCAL_MACHINE
, mntr_key
, 0, KEY_ALL_ACCESS
, &hkey
))
1728 len_sysdir
= GetSystemDirectoryW( sysdir
, MAX_PATH
);
1729 len_path
= len_sysdir
+ ARRAY_SIZE( color_path
) - 1;
1733 if (!(profile
= HeapAlloc( GetProcessHeap(), 0, (len_path
+ len
) * sizeof(WCHAR
) )))
1735 RegCloseKey( hkey
);
1738 res
= RegEnumValueW( hkey
, index
, profile
+ len_path
, &len
, NULL
, NULL
, NULL
, NULL
);
1739 while (res
== ERROR_MORE_DATA
)
1742 HeapFree( GetProcessHeap(), 0, profile
);
1743 if (!(profile
= HeapAlloc( GetProcessHeap(), 0, (len_path
+ len
) * sizeof(WCHAR
) )))
1745 RegCloseKey( hkey
);
1748 res
= RegEnumValueW( hkey
, index
, profile
+ len_path
, &len
, NULL
, NULL
, NULL
, NULL
);
1750 if (res
!= ERROR_SUCCESS
)
1752 HeapFree( GetProcessHeap(), 0, profile
);
1755 memcpy( profile
, sysdir
, len_sysdir
* sizeof(WCHAR
) );
1756 memcpy( profile
+ len_sysdir
, color_path
, sizeof(color_path
) - sizeof(WCHAR
) );
1757 ret
= proc( profile
, lparam
);
1758 HeapFree( GetProcessHeap(), 0, profile
);
1762 RegCloseKey( hkey
);