2 * X11 graphics driver graphics functions
4 * Copyright 1993,1994 Alexandre Julliard
9 * FIXME: none of these functions obey the GM_ADVANCED
20 #include <X11/Intrinsic.h>
41 #define ABS(x) ((x)<0?(-(x)):(x))
42 /**********************************************************************
46 X11DRV_MoveToEx(DC
*dc
,INT32 x
,INT32 y
,LPPOINT32 pt
) {
49 pt
->x
= dc
->w
.CursPosX
;
50 pt
->y
= dc
->w
.CursPosY
;
57 /***********************************************************************
61 X11DRV_LineTo( DC
*dc
, INT32 x
, INT32 y
)
63 if (DC_SetupGCForPen( dc
))
64 TSXDrawLine(display
, dc
->u
.x
.drawable
, dc
->u
.x
.gc
,
65 dc
->w
.DCOrgX
+ XLPTODP( dc
, dc
->w
.CursPosX
),
66 dc
->w
.DCOrgY
+ YLPTODP( dc
, dc
->w
.CursPosY
),
67 dc
->w
.DCOrgX
+ XLPTODP( dc
, x
),
68 dc
->w
.DCOrgY
+ YLPTODP( dc
, y
) );
76 /***********************************************************************
79 * Helper functions for Arc(), Chord() and Pie().
80 * 'lines' is the number of lines to draw: 0 for Arc, 1 for Chord, 2 for Pie.
84 X11DRV_DrawArc( DC
*dc
, INT32 left
, INT32 top
, INT32 right
,
85 INT32 bottom
, INT32 xstart
, INT32 ystart
,
86 INT32 xend
, INT32 yend
, INT32 lines
)
88 INT32 xcenter
, ycenter
, istart_angle
, idiff_angle
;
89 INT32 width
, oldwidth
, oldendcap
;
90 double start_angle
, end_angle
;
93 left
= XLPTODP( dc
, left
);
94 top
= YLPTODP( dc
, top
);
95 right
= XLPTODP( dc
, right
);
96 bottom
= YLPTODP( dc
, bottom
);
97 xstart
= XLPTODP( dc
, xstart
);
98 ystart
= YLPTODP( dc
, ystart
);
99 xend
= XLPTODP( dc
, xend
);
100 yend
= YLPTODP( dc
, yend
);
102 if (right
< left
) { INT32 tmp
= right
; right
= left
; left
= tmp
; }
103 if (bottom
< top
) { INT32 tmp
= bottom
; bottom
= top
; top
= tmp
; }
104 if ((left
== right
) || (top
== bottom
)
105 ||(lines
&& ((right
-left
==1)||(bottom
-top
==1)))) return TRUE
;
107 oldwidth
= width
= dc
->u
.x
.pen
.width
;
108 oldendcap
= dc
->u
.x
.pen
.endcap
;
109 if (!width
) width
= 1;
110 if(dc
->u
.x
.pen
.style
== PS_NULL
) width
= 0;
112 if ((dc
->u
.x
.pen
.style
== PS_INSIDEFRAME
))
114 if (2*width
> (right
-left
)) width
=(right
-left
+ 1)/2;
115 if (2*width
> (bottom
-top
)) width
=(bottom
-top
+ 1)/2;
117 right
-= (width
- 1) / 2;
119 bottom
-= (width
- 1) / 2;
121 if(width
== 0) width
=1; /* more accurate */
122 dc
->u
.x
.pen
.width
=width
;
123 dc
->u
.x
.pen
.endcap
=PS_ENDCAP_SQUARE
;
125 xcenter
= (right
+ left
) / 2;
126 ycenter
= (bottom
+ top
) / 2;
127 start_angle
= atan2( (double)(ycenter
-ystart
)*(right
-left
),
128 (double)(xstart
-xcenter
)*(bottom
-top
) );
129 end_angle
= atan2( (double)(ycenter
-yend
)*(right
-left
),
130 (double)(xend
-xcenter
)*(bottom
-top
) );
131 if ((xstart
==xend
)&&(ystart
==yend
))
132 { /* A lazy program delivers xstart=xend=ystart=yend=0) */
136 else /* notorious cases */
137 if ((start_angle
== PI
)&&( end_angle
<0))
140 if ((end_angle
== PI
)&&( start_angle
<0))
142 istart_angle
= (INT32
)(start_angle
* 180 * 64 / PI
+ 0.5);
143 idiff_angle
= (INT32
)((end_angle
- start_angle
) * 180 * 64 / PI
+ 0.5);
144 if (idiff_angle
<= 0) idiff_angle
+= 360 * 64;
146 /* Fill arc with brush if Chord() or Pie() */
148 if ((lines
> 0) && DC_SetupGCForBrush( dc
)) {
149 TSXSetArcMode( display
, dc
->u
.x
.gc
, (lines
==1) ? ArcChord
: ArcPieSlice
);
150 TSXFillArc( display
, dc
->u
.x
.drawable
, dc
->u
.x
.gc
,
151 dc
->w
.DCOrgX
+ left
, dc
->w
.DCOrgY
+ top
,
152 right
-left
-1, bottom
-top
-1, istart_angle
, idiff_angle
);
155 /* Draw arc and lines */
157 if (DC_SetupGCForPen( dc
)){
158 TSXDrawArc( display
, dc
->u
.x
.drawable
, dc
->u
.x
.gc
,
159 dc
->w
.DCOrgX
+ left
, dc
->w
.DCOrgY
+ top
,
160 right
-left
-1, bottom
-top
-1, istart_angle
, idiff_angle
);
162 /* use the truncated values */
163 start_angle
=(double)istart_angle
*PI
/64./180.;
164 end_angle
=(double)(istart_angle
+idiff_angle
)*PI
/64./180.;
165 /* calculate the endpoints and round correctly */
166 points
[0].x
= (int) floor(dc
->w
.DCOrgX
+ (right
+left
)/2.0 +
167 cos(start_angle
) * (right
-left
-width
*2+2) / 2. + 0.5);
168 points
[0].y
= (int) floor(dc
->w
.DCOrgY
+ (top
+bottom
)/2.0 -
169 sin(start_angle
) * (bottom
-top
-width
*2+2) / 2. + 0.5);
170 points
[1].x
= (int) floor(dc
->w
.DCOrgX
+ (right
+left
)/2.0 +
171 cos(end_angle
) * (right
-left
-width
*2+2) / 2. + 0.5);
172 points
[1].y
= (int) floor(dc
->w
.DCOrgY
+ (top
+bottom
)/2.0 -
173 sin(end_angle
) * (bottom
-top
-width
*2+2) / 2. + 0.5);
175 /* OK this stuff is optimized for Xfree86
176 * which is probably the most used server by
177 * wine users. Other X servers will not
178 * display correctly. (eXceed for instance)
179 * so if you feel you must change make sure that
180 * you either use Xfree86 or seperate your changes
181 * from these (compile switch or whatever)
185 points
[3] = points
[1];
186 points
[1].x
= dc
->w
.DCOrgX
+ xcenter
;
187 points
[1].y
= dc
->w
.DCOrgY
+ ycenter
;
188 points
[2] = points
[1];
189 dx1
=points
[1].x
-points
[0].x
;
190 dy1
=points
[1].y
-points
[0].y
;
191 if(((top
-bottom
) | -2) == -2)
192 if(dy1
>0) points
[1].y
--;
194 if (((-dx1
)*64)<=ABS(dy1
)*37) points
[0].x
--;
195 if(((-dx1
*9))<(dy1
*16)) points
[0].y
--;
196 if( dy1
<0 && ((dx1
*9)) < (dy1
*16)) points
[0].y
--;
198 if(dy1
< 0) points
[0].y
--;
199 if(((right
-left
) | -2) == -2) points
[1].x
--;
201 dx1
=points
[3].x
-points
[2].x
;
202 dy1
=points
[3].y
-points
[2].y
;
203 if(((top
-bottom
) | -2 ) == -2)
204 if(dy1
< 0) points
[2].y
--;
206 if( dy1
>0) points
[3].y
--;
207 if(((right
-left
) | -2) == -2 ) points
[2].x
--;
210 if( dx1
* 64 < dy1
* -37 ) points
[3].x
--;
214 TSXDrawLines( display
, dc
->u
.x
.drawable
, dc
->u
.x
.gc
,
215 points
, lines
+1, CoordModeOrigin
);
218 dc
->u
.x
.pen
.width
=oldwidth
;
219 dc
->u
.x
.pen
.endcap
=oldendcap
;
224 /***********************************************************************
228 X11DRV_Arc( DC
*dc
, INT32 left
, INT32 top
, INT32 right
, INT32 bottom
,
229 INT32 xstart
, INT32 ystart
, INT32 xend
, INT32 yend
)
231 return X11DRV_DrawArc( dc
, left
, top
, right
, bottom
,
232 xstart
, ystart
, xend
, yend
, 0 );
236 /***********************************************************************
240 X11DRV_Pie( DC
*dc
, INT32 left
, INT32 top
, INT32 right
, INT32 bottom
,
241 INT32 xstart
, INT32 ystart
, INT32 xend
, INT32 yend
)
243 return X11DRV_DrawArc( dc
, left
, top
, right
, bottom
,
244 xstart
, ystart
, xend
, yend
, 2 );
247 /***********************************************************************
251 X11DRV_Chord( DC
*dc
, INT32 left
, INT32 top
, INT32 right
, INT32 bottom
,
252 INT32 xstart
, INT32 ystart
, INT32 xend
, INT32 yend
)
254 return X11DRV_DrawArc( dc
, left
, top
, right
, bottom
,
255 xstart
, ystart
, xend
, yend
, 1 );
259 /***********************************************************************
263 X11DRV_Ellipse( DC
*dc
, INT32 left
, INT32 top
, INT32 right
, INT32 bottom
)
265 INT32 width
, oldwidth
;
266 left
= XLPTODP( dc
, left
);
267 top
= YLPTODP( dc
, top
);
268 right
= XLPTODP( dc
, right
);
269 bottom
= YLPTODP( dc
, bottom
);
270 if ((left
== right
) || (top
== bottom
)) return TRUE
;
272 if (right
< left
) { INT32 tmp
= right
; right
= left
; left
= tmp
; }
273 if (bottom
< top
) { INT32 tmp
= bottom
; bottom
= top
; top
= tmp
; }
275 oldwidth
= width
= dc
->u
.x
.pen
.width
;
276 if (!width
) width
= 1;
277 if(dc
->u
.x
.pen
.style
== PS_NULL
) width
= 0;
279 if ((dc
->u
.x
.pen
.style
== PS_INSIDEFRAME
))
281 if (2*width
> (right
-left
)) width
=(right
-left
+ 1)/2;
282 if (2*width
> (bottom
-top
)) width
=(bottom
-top
+ 1)/2;
284 right
-= (width
- 1) / 2;
286 bottom
-= (width
- 1) / 2;
288 if(width
== 0) width
=1; /* more accurate */
289 dc
->u
.x
.pen
.width
=width
;
291 if (DC_SetupGCForBrush( dc
))
292 TSXFillArc( display
, dc
->u
.x
.drawable
, dc
->u
.x
.gc
,
293 dc
->w
.DCOrgX
+ left
, dc
->w
.DCOrgY
+ top
,
294 right
-left
-1, bottom
-top
-1, 0, 360*64 );
295 if (DC_SetupGCForPen( dc
))
296 TSXDrawArc( display
, dc
->u
.x
.drawable
, dc
->u
.x
.gc
,
297 dc
->w
.DCOrgX
+ left
, dc
->w
.DCOrgY
+ top
,
298 right
-left
-1, bottom
-top
-1, 0, 360*64 );
299 dc
->u
.x
.pen
.width
=oldwidth
;
304 /***********************************************************************
308 X11DRV_Rectangle(DC
*dc
, INT32 left
, INT32 top
, INT32 right
, INT32 bottom
)
310 INT32 width
, oldwidth
, oldjoinstyle
;
312 TRACE(graphics
, "(%d %d %d %d)\n",
313 left
, top
, right
, bottom
);
315 left
= XLPTODP( dc
, left
);
316 top
= YLPTODP( dc
, top
);
317 right
= XLPTODP( dc
, right
);
318 bottom
= YLPTODP( dc
, bottom
);
320 if ((left
== right
) || (top
== bottom
)) return TRUE
;
322 if (right
< left
) { INT32 tmp
= right
; right
= left
; left
= tmp
; }
323 if (bottom
< top
) { INT32 tmp
= bottom
; bottom
= top
; top
= tmp
; }
325 oldwidth
= width
= dc
->u
.x
.pen
.width
;
326 if (!width
) width
= 1;
327 if(dc
->u
.x
.pen
.style
== PS_NULL
) width
= 0;
329 if ((dc
->u
.x
.pen
.style
== PS_INSIDEFRAME
))
331 if (2*width
> (right
-left
)) width
=(right
-left
+ 1)/2;
332 if (2*width
> (bottom
-top
)) width
=(bottom
-top
+ 1)/2;
334 right
-= (width
- 1) / 2;
336 bottom
-= (width
- 1) / 2;
338 if(width
== 1) width
=0;
339 dc
->u
.x
.pen
.width
=width
;
340 oldjoinstyle
=dc
->u
.x
.pen
.linejoin
;
341 if(dc
->u
.x
.pen
.type
!=PS_GEOMETRIC
)
342 dc
->u
.x
.pen
.linejoin
=PS_JOIN_MITER
;
344 if ((right
> left
+ width
) && (bottom
> top
+ width
))
346 if (DC_SetupGCForBrush( dc
))
347 TSXFillRectangle( display
, dc
->u
.x
.drawable
, dc
->u
.x
.gc
,
348 dc
->w
.DCOrgX
+ left
+ (width
+ 1) / 2,
349 dc
->w
.DCOrgY
+ top
+ (width
+ 1) / 2,
350 right
-left
-width
-1, bottom
-top
-width
-1);
352 if (DC_SetupGCForPen( dc
))
353 TSXDrawRectangle( display
, dc
->u
.x
.drawable
, dc
->u
.x
.gc
,
354 dc
->w
.DCOrgX
+ left
, dc
->w
.DCOrgY
+ top
,
355 right
-left
-1, bottom
-top
-1 );
357 dc
->u
.x
.pen
.width
=oldwidth
;
358 dc
->u
.x
.pen
.linejoin
=oldjoinstyle
;
362 /***********************************************************************
366 X11DRV_RoundRect( DC
*dc
, INT32 left
, INT32 top
, INT32 right
,
367 INT32 bottom
, INT32 ell_width
, INT32 ell_height
)
369 INT32 width
, oldwidth
, oldendcap
;
371 TRACE(graphics
, "(%d %d %d %d %d %d\n",
372 left
, top
, right
, bottom
, ell_width
, ell_height
);
374 left
= XLPTODP( dc
, left
);
375 top
= YLPTODP( dc
, top
);
376 right
= XLPTODP( dc
, right
);
377 bottom
= YLPTODP( dc
, bottom
);
379 if ((left
== right
) || (top
== bottom
))
382 ell_width
= abs( ell_width
* dc
->vportExtX
/ dc
->wndExtX
);
383 ell_height
= abs( ell_height
* dc
->vportExtY
/ dc
->wndExtY
);
385 /* Fix the coordinates */
387 if (right
< left
) { INT32 tmp
= right
; right
= left
; left
= tmp
; }
388 if (bottom
< top
) { INT32 tmp
= bottom
; bottom
= top
; top
= tmp
; }
390 oldwidth
=width
= dc
->u
.x
.pen
.width
;
391 oldendcap
= dc
->u
.x
.pen
.endcap
;
392 if (!width
) width
= 1;
393 if(dc
->u
.x
.pen
.style
== PS_NULL
) width
= 0;
395 if ((dc
->u
.x
.pen
.style
== PS_INSIDEFRAME
))
397 if (2*width
> (right
-left
)) width
=(right
-left
+ 1)/2;
398 if (2*width
> (bottom
-top
)) width
=(bottom
-top
+ 1)/2;
400 right
-= (width
- 1) / 2;
402 bottom
-= (width
- 1) / 2;
404 if(width
== 0) width
=1;
405 dc
->u
.x
.pen
.width
=width
;
406 dc
->u
.x
.pen
.endcap
=PS_ENDCAP_SQUARE
;
408 if (DC_SetupGCForBrush( dc
))
410 if (ell_width
> (right
-left
) )
411 if (ell_height
> (bottom
-top
) )
412 TSXFillArc( display
, dc
->u
.x
.drawable
, dc
->u
.x
.gc
,
413 dc
->w
.DCOrgX
+ left
, dc
->w
.DCOrgY
+ top
,
414 right
- left
- 1, bottom
- top
- 1,
417 TSXFillArc( display
, dc
->u
.x
.drawable
, dc
->u
.x
.gc
,
418 dc
->w
.DCOrgX
+ left
, dc
->w
.DCOrgY
+ top
,
419 right
- left
- 1, ell_height
, 0, 180 * 64 );
420 TSXFillArc( display
, dc
->u
.x
.drawable
, dc
->u
.x
.gc
,
422 dc
->w
.DCOrgY
+ bottom
- ell_height
- 1,
423 right
- left
- 1, ell_height
, 180 * 64, 180 * 64 );
425 else if (ell_height
> (bottom
-top
) ){
426 TSXFillArc( display
, dc
->u
.x
.drawable
, dc
->u
.x
.gc
,
427 dc
->w
.DCOrgX
+ left
, dc
->w
.DCOrgY
+ top
,
428 ell_width
, bottom
- top
- 1, 90 * 64, 180 * 64 );
429 TSXFillArc( display
, dc
->u
.x
.drawable
, dc
->u
.x
.gc
,
430 dc
->w
.DCOrgX
+ right
- ell_width
-1, dc
->w
.DCOrgY
+ top
,
431 ell_width
, bottom
- top
- 1, 270 * 64, 180 * 64 );
433 TSXFillArc( display
, dc
->u
.x
.drawable
, dc
->u
.x
.gc
,
434 dc
->w
.DCOrgX
+ left
, dc
->w
.DCOrgY
+ top
,
435 ell_width
, ell_height
, 90 * 64, 90 * 64 );
436 TSXFillArc( display
, dc
->u
.x
.drawable
, dc
->u
.x
.gc
,
438 dc
->w
.DCOrgY
+ bottom
- ell_height
- 1,
439 ell_width
, ell_height
, 180 * 64, 90 * 64 );
440 TSXFillArc( display
, dc
->u
.x
.drawable
, dc
->u
.x
.gc
,
441 dc
->w
.DCOrgX
+ right
- ell_width
- 1,
442 dc
->w
.DCOrgY
+ bottom
- ell_height
- 1,
443 ell_width
, ell_height
, 270 * 64, 90 * 64 );
444 TSXFillArc( display
, dc
->u
.x
.drawable
, dc
->u
.x
.gc
,
445 dc
->w
.DCOrgX
+ right
- ell_width
- 1,
447 ell_width
, ell_height
, 0, 90 * 64 );
449 if (ell_width
< right
- left
)
451 TSXFillRectangle( display
, dc
->u
.x
.drawable
, dc
->u
.x
.gc
,
452 dc
->w
.DCOrgX
+ left
+ (ell_width
+ 1) / 2,
453 dc
->w
.DCOrgY
+ top
+ 1,
454 right
- left
- ell_width
- 1,
455 (ell_height
+ 1) / 2 - 1);
456 TSXFillRectangle( display
, dc
->u
.x
.drawable
, dc
->u
.x
.gc
,
457 dc
->w
.DCOrgX
+ left
+ (ell_width
+ 1) / 2,
458 dc
->w
.DCOrgY
+ bottom
- (ell_height
) / 2 - 1,
459 right
- left
- ell_width
- 1,
462 if (ell_height
< bottom
- top
)
464 TSXFillRectangle( display
, dc
->u
.x
.drawable
, dc
->u
.x
.gc
,
465 dc
->w
.DCOrgX
+ left
+ 1,
466 dc
->w
.DCOrgY
+ top
+ (ell_height
+ 1) / 2,
468 bottom
- top
- ell_height
- 1);
471 /* FIXME: this could be done with on X call
472 * more efficient and probably more correct
473 * on any X server: XDrawArcs will draw
474 * straight horizontal and vertical lines
475 * if width or height are zero.
477 * BTW this stuff is optimized for an Xfree86 server
478 * read the comments inside the X11DRV_DrawArc function
480 if (DC_SetupGCForPen(dc
)) {
481 if (ell_width
> (right
-left
) )
482 if (ell_height
> (bottom
-top
) )
483 TSXDrawArc( display
, dc
->u
.x
.drawable
, dc
->u
.x
.gc
,
484 dc
->w
.DCOrgX
+ left
, dc
->w
.DCOrgY
+ top
,
485 right
- left
- 1, bottom
-top
- 1, 0 , 360 * 64 );
487 TSXDrawArc( display
, dc
->u
.x
.drawable
, dc
->u
.x
.gc
,
488 dc
->w
.DCOrgX
+ left
, dc
->w
.DCOrgY
+ top
,
489 right
- left
- 1, ell_height
- 1, 0 , 180 * 64 );
490 TSXDrawArc( display
, dc
->u
.x
.drawable
, dc
->u
.x
.gc
,
492 dc
->w
.DCOrgY
+ bottom
- ell_height
,
493 right
- left
- 1, ell_height
- 1, 180 * 64 , 180 * 64 );
495 else if (ell_height
> (bottom
-top
) ){
496 TSXDrawArc( display
, dc
->u
.x
.drawable
, dc
->u
.x
.gc
,
497 dc
->w
.DCOrgX
+ left
, dc
->w
.DCOrgY
+ top
,
498 ell_width
- 1 , bottom
- top
- 1, 90 * 64 , 180 * 64 );
499 TSXDrawArc( display
, dc
->u
.x
.drawable
, dc
->u
.x
.gc
,
500 dc
->w
.DCOrgX
+ right
- ell_width
,
502 ell_width
- 1 , bottom
- top
- 1, 270 * 64 , 180 * 64 );
504 TSXDrawArc( display
, dc
->u
.x
.drawable
, dc
->u
.x
.gc
,
505 dc
->w
.DCOrgX
+ left
, dc
->w
.DCOrgY
+ top
,
506 ell_width
- 1, ell_height
- 1, 90 * 64, 90 * 64 );
507 TSXDrawArc( display
, dc
->u
.x
.drawable
, dc
->u
.x
.gc
,
508 dc
->w
.DCOrgX
+ left
, dc
->w
.DCOrgY
+ bottom
- ell_height
,
509 ell_width
- 1, ell_height
- 1, 180 * 64, 90 * 64 );
510 TSXDrawArc( display
, dc
->u
.x
.drawable
, dc
->u
.x
.gc
,
511 dc
->w
.DCOrgX
+ right
- ell_width
,
512 dc
->w
.DCOrgY
+ bottom
- ell_height
,
513 ell_width
- 1, ell_height
- 1, 270 * 64, 90 * 64 );
514 TSXDrawArc( display
, dc
->u
.x
.drawable
, dc
->u
.x
.gc
,
515 dc
->w
.DCOrgX
+ right
- ell_width
, dc
->w
.DCOrgY
+ top
,
516 ell_width
- 1, ell_height
- 1, 0, 90 * 64 );
518 if (ell_width
< right
- left
)
520 TSXDrawLine( display
, dc
->u
.x
.drawable
, dc
->u
.x
.gc
,
521 dc
->w
.DCOrgX
+ left
+ ell_width
/ 2,
523 dc
->w
.DCOrgX
+ right
- (ell_width
+1) / 2,
525 TSXDrawLine( display
, dc
->u
.x
.drawable
, dc
->u
.x
.gc
,
526 dc
->w
.DCOrgX
+ left
+ ell_width
/ 2 ,
527 dc
->w
.DCOrgY
+ bottom
- 1,
528 dc
->w
.DCOrgX
+ right
- (ell_width
+1)/ 2,
529 dc
->w
.DCOrgY
+ bottom
- 1);
531 if (ell_height
< bottom
- top
)
533 TSXDrawLine( display
, dc
->u
.x
.drawable
, dc
->u
.x
.gc
,
534 dc
->w
.DCOrgX
+ right
- 1,
535 dc
->w
.DCOrgY
+ top
+ ell_height
/ 2,
536 dc
->w
.DCOrgX
+ right
- 1,
537 dc
->w
.DCOrgY
+ bottom
- (ell_height
+1) / 2);
538 TSXDrawLine( display
, dc
->u
.x
.drawable
, dc
->u
.x
.gc
,
540 dc
->w
.DCOrgY
+ top
+ ell_height
/ 2,
542 dc
->w
.DCOrgY
+ bottom
- (ell_height
+1) / 2);
545 dc
->u
.x
.pen
.width
=oldwidth
;
546 dc
->u
.x
.pen
.endcap
=oldendcap
;
551 /***********************************************************************
555 X11DRV_SetPixel( DC
*dc
, INT32 x
, INT32 y
, COLORREF color
)
559 x
= dc
->w
.DCOrgX
+ XLPTODP( dc
, x
);
560 y
= dc
->w
.DCOrgY
+ YLPTODP( dc
, y
);
561 pixel
= COLOR_ToPhysical( dc
, color
);
563 TSXSetForeground( display
, dc
->u
.x
.gc
, pixel
);
564 TSXSetFunction( display
, dc
->u
.x
.gc
, GXcopy
);
565 TSXDrawPoint( display
, dc
->u
.x
.drawable
, dc
->u
.x
.gc
, x
, y
);
567 /* inefficient but simple... */
569 return COLOR_ToLogical(pixel
);
573 /***********************************************************************
577 X11DRV_GetPixel( DC
*dc
, INT32 x
, INT32 y
)
579 static Pixmap pixmap
= 0;
583 x
= dc
->w
.DCOrgX
+ XLPTODP( dc
, x
);
584 y
= dc
->w
.DCOrgY
+ YLPTODP( dc
, y
);
585 EnterCriticalSection( &X11DRV_CritSection
);
586 if (dc
->w
.flags
& DC_MEMORY
)
588 image
= XGetImage( display
, dc
->u
.x
.drawable
, x
, y
, 1, 1,
589 AllPlanes
, ZPixmap
);
593 /* If we are reading from the screen, use a temporary copy */
594 /* to avoid a BadMatch error */
595 if (!pixmap
) pixmap
= XCreatePixmap( display
, rootWindow
,
596 1, 1, dc
->w
.bitsPerPixel
);
597 XCopyArea( display
, dc
->u
.x
.drawable
, pixmap
, BITMAP_colorGC
,
599 image
= XGetImage( display
, pixmap
, 0, 0, 1, 1, AllPlanes
, ZPixmap
);
601 pixel
= XGetPixel( image
, 0, 0 );
602 XDestroyImage( image
);
603 LeaveCriticalSection( &X11DRV_CritSection
);
605 return COLOR_ToLogical(pixel
);
609 /***********************************************************************
613 X11DRV_PaintRgn( DC
*dc
, HRGN32 hrgn
)
616 HRGN32 tmpVisRgn
, prevVisRgn
;
617 HDC32 hdc
= dc
->hSelf
; /* FIXME: should not mix dc/hdc this way */
619 if (!(tmpVisRgn
= CreateRectRgn32( 0, 0, 0, 0 ))) return FALSE
;
621 /* Transform region into device co-ords */
622 if ( !REGION_LPTODP( hdc
, tmpVisRgn
, hrgn
)
623 || OffsetRgn32( tmpVisRgn
, dc
->w
.DCOrgX
, dc
->w
.DCOrgY
) == ERROR
) {
624 DeleteObject32( tmpVisRgn
);
628 /* Modify visible region */
629 if (!(prevVisRgn
= SaveVisRgn( hdc
))) {
630 DeleteObject32( tmpVisRgn
);
633 CombineRgn32( tmpVisRgn
, prevVisRgn
, tmpVisRgn
, RGN_AND
);
634 SelectVisRgn( hdc
, tmpVisRgn
);
635 DeleteObject32( tmpVisRgn
);
637 /* Fill the region */
639 GetRgnBox32( dc
->w
.hGCClipRgn
, &box
);
640 if (DC_SetupGCForBrush( dc
))
641 TSXFillRectangle( display
, dc
->u
.x
.drawable
, dc
->u
.x
.gc
,
643 box
.right
-box
.left
, box
.bottom
-box
.top
);
645 /* Restore the visible region */
647 RestoreVisRgn( hdc
);
651 /**********************************************************************
655 X11DRV_Polyline( DC
*dc
, LPPOINT32 pt
, INT32 count
)
660 if((oldwidth
=dc
->u
.x
.pen
.width
)==0) dc
->u
.x
.pen
.width
=1;
662 points
= (XPoint
*) xmalloc (sizeof (XPoint
) * (count
));
663 for (i
= 0; i
< count
; i
++)
665 points
[i
].x
= dc
->w
.DCOrgX
+ XLPTODP( dc
, pt
[i
].x
);
666 points
[i
].y
= dc
->w
.DCOrgY
+ YLPTODP( dc
, pt
[i
].y
);
669 if (DC_SetupGCForPen ( dc
))
670 TSXDrawLines( display
, dc
->u
.x
.drawable
, dc
->u
.x
.gc
,
671 points
, count
, CoordModeOrigin
);
674 dc
->u
.x
.pen
.width
=oldwidth
;
679 /**********************************************************************
683 X11DRV_Polygon( DC
*dc
, LPPOINT32 pt
, INT32 count
)
688 points
= (XPoint
*) xmalloc (sizeof (XPoint
) * (count
+1));
689 for (i
= 0; i
< count
; i
++)
691 points
[i
].x
= dc
->w
.DCOrgX
+ XLPTODP( dc
, pt
[i
].x
);
692 points
[i
].y
= dc
->w
.DCOrgY
+ YLPTODP( dc
, pt
[i
].y
);
694 points
[count
] = points
[0];
696 if (DC_SetupGCForBrush( dc
))
697 TSXFillPolygon( display
, dc
->u
.x
.drawable
, dc
->u
.x
.gc
,
698 points
, count
+1, Complex
, CoordModeOrigin
);
700 if (DC_SetupGCForPen ( dc
))
701 TSXDrawLines( display
, dc
->u
.x
.drawable
, dc
->u
.x
.gc
,
702 points
, count
+1, CoordModeOrigin
);
709 /**********************************************************************
713 X11DRV_PolyPolygon( DC
*dc
, LPPOINT32 pt
, LPINT32 counts
, UINT32 polygons
)
717 /* FIXME: The points should be converted to device coords before */
718 /* creating the region. But as CreatePolyPolygonRgn is not */
719 /* really correct either, it doesn't matter much... */
720 /* At least the outline will be correct :-) */
721 hrgn
= CreatePolyPolygonRgn32( pt
, counts
, polygons
, dc
->w
.polyFillMode
);
722 X11DRV_PaintRgn( dc
, hrgn
);
723 DeleteObject32( hrgn
);
725 /* Draw the outline of the polygons */
727 if (DC_SetupGCForPen ( dc
))
732 for (i
= 0; i
< polygons
; i
++) if (counts
[i
] > max
) max
= counts
[i
];
733 points
= (XPoint
*) xmalloc( sizeof(XPoint
) * (max
+1) );
735 for (i
= 0; i
< polygons
; i
++)
737 for (j
= 0; j
< counts
[i
]; j
++)
739 points
[j
].x
= dc
->w
.DCOrgX
+ XLPTODP( dc
, pt
->x
);
740 points
[j
].y
= dc
->w
.DCOrgY
+ YLPTODP( dc
, pt
->y
);
743 points
[j
] = points
[0];
744 TSXDrawLines( display
, dc
->u
.x
.drawable
, dc
->u
.x
.gc
,
745 points
, j
+ 1, CoordModeOrigin
);
753 /**********************************************************************
754 * X11DRV_PolyPolyline
757 X11DRV_PolyPolyline( DC
*dc
, LPPOINT32 pt
, LPDWORD counts
, DWORD polylines
)
759 if (DC_SetupGCForPen ( dc
))
764 for (i
= 0; i
< polylines
; i
++) if (counts
[i
] > max
) max
= counts
[i
];
765 points
= (XPoint
*) xmalloc( sizeof(XPoint
) * (max
+1) );
767 for (i
= 0; i
< polylines
; i
++)
769 for (j
= 0; j
< counts
[i
]; j
++)
771 points
[j
].x
= dc
->w
.DCOrgX
+ XLPTODP( dc
, pt
->x
);
772 points
[j
].y
= dc
->w
.DCOrgY
+ YLPTODP( dc
, pt
->y
);
775 points
[j
] = points
[0];
776 TSXDrawLines( display
, dc
->u
.x
.drawable
, dc
->u
.x
.gc
,
777 points
, j
+ 1, CoordModeOrigin
);
785 /**********************************************************************
786 * X11DRV_InternalFloodFill
788 * Internal helper function for flood fill.
789 * (xorg,yorg) is the origin of the X image relative to the drawable.
790 * (x,y) is relative to the origin of the X image.
792 static void X11DRV_InternalFloodFill(XImage
*image
, DC
*dc
,
795 Pixel pixel
, WORD fillType
)
799 #define TO_FLOOD(x,y) ((fillType == FLOODFILLBORDER) ? \
800 (XGetPixel(image,x,y) != pixel) : \
801 (XGetPixel(image,x,y) == pixel))
803 if (!TO_FLOOD(x
,y
)) return;
805 /* Find left and right boundaries */
808 while ((left
> 0) && TO_FLOOD( left
-1, y
)) left
--;
809 while ((right
< image
->width
) && TO_FLOOD( right
, y
)) right
++;
810 XFillRectangle( display
, dc
->u
.x
.drawable
, dc
->u
.x
.gc
,
811 xOrg
+ left
, yOrg
+ y
, right
-left
, 1 );
813 /* Set the pixels of this line so we don't fill it again */
815 for (x
= left
; x
< right
; x
++)
817 if (fillType
== FLOODFILLBORDER
) XPutPixel( image
, x
, y
, pixel
);
818 else XPutPixel( image
, x
, y
, ~pixel
);
821 /* Fill the line above */
828 while ((x
< right
) && !TO_FLOOD(x
,y
)) x
++;
829 if (x
>= right
) break;
830 while ((x
< right
) && TO_FLOOD(x
,y
)) x
++;
831 X11DRV_InternalFloodFill(image
, dc
, x
-1, y
,
832 xOrg
, yOrg
, pixel
, fillType
);
836 /* Fill the line below */
838 if ((y
+= 2) < image
->height
)
843 while ((x
< right
) && !TO_FLOOD(x
,y
)) x
++;
844 if (x
>= right
) break;
845 while ((x
< right
) && TO_FLOOD(x
,y
)) x
++;
846 X11DRV_InternalFloodFill(image
, dc
, x
-1, y
,
847 xOrg
, yOrg
, pixel
, fillType
);
854 /**********************************************************************
857 * Main flood-fill routine.
859 * The Xlib critical section must be entered before calling this function.
862 struct FloodFill_params
871 static BOOL32
X11DRV_DoFloodFill( const struct FloodFill_params
*params
)
877 if (GetRgnBox32( dc
->w
.hGCClipRgn
, &rect
) == ERROR
) return FALSE
;
879 if (!(image
= XGetImage( display
, dc
->u
.x
.drawable
,
882 rect
.right
- rect
.left
,
883 rect
.bottom
- rect
.top
,
884 AllPlanes
, ZPixmap
))) return FALSE
;
886 if (DC_SetupGCForBrush( dc
))
888 /* ROP mode is always GXcopy for flood-fill */
889 XSetFunction( display
, dc
->u
.x
.gc
, GXcopy
);
890 X11DRV_InternalFloodFill(image
, dc
,
891 XLPTODP(dc
,params
->x
) + dc
->w
.DCOrgX
- rect
.left
,
892 YLPTODP(dc
,params
->y
) + dc
->w
.DCOrgY
- rect
.top
,
895 COLOR_ToPhysical( dc
, params
->color
),
899 XDestroyImage( image
);
904 /**********************************************************************
905 * X11DRV_ExtFloodFill
908 X11DRV_ExtFloodFill( DC
*dc
, INT32 x
, INT32 y
, COLORREF color
,
912 struct FloodFill_params params
= { dc
, x
, y
, color
, fillType
};
914 TRACE(graphics
, "X11DRV_ExtFloodFill %d,%d %06lx %d\n",
915 x
, y
, color
, fillType
);
917 if (!PtVisible32( dc
->hSelf
, x
, y
)) return FALSE
;
918 EnterCriticalSection( &X11DRV_CritSection
);
919 result
= CALL_LARGE_STACK( X11DRV_DoFloodFill
, ¶ms
);
920 LeaveCriticalSection( &X11DRV_CritSection
);
924 /******************************************************************
926 * *Very* simple bezier drawing code,
928 * It uses a recursive algorithm to divide the curve in a series
929 * of straight line segements. Not ideal but for me sufficient.
930 * If you are in need for something better look for some incremental
933 * 7 July 1998 Rein Klazes
937 * some macro definitions for bezier drawing
939 * to avoid trucation errors the coordinates are
940 * shifted upwards. When used in drawing they are
941 * shifted down again, including correct rounding
942 * and avoiding floating point arithmatic
943 * 4 bits should allow 27 bits coordinates which I saw
944 * somewere in the win32 doc's
948 #define BEZIERSHIFTBITS 4
949 #define BEZIERSHIFTUP(x) ((x)<<BEZIERSHIFTBITS)
950 #define BEZIERPIXEL BEZIERSHIFTUP(1)
951 #define BEZIERSHIFTDOWN(x) (((x)+(1<<(BEZIERSHIFTBITS-1)))>>BEZIERSHIFTBITS)
952 /* maximum depth of recursion */
953 #define BEZIERMAXDEPTH 8
955 /* size of array to store points on */
956 /* enough for one curve */
957 #define BEZMAXPOINTS (150)
959 /* calculate Bezier average, in this case the middle
960 * correctly rounded...
963 #define BEZIERMIDDLE(Mid, P1, P2) \
964 (Mid).x=((P1).x+(P2).x + 1)/2;\
965 (Mid).y=((P1).y+(P2).y + 1)/2;
967 /**********************************************************
968 * BezierCheck helper function to check
969 * that recursion can be terminated
970 * Points[0] and Points[3] are begin and endpoint
971 * Points[1] and Points[2] are control points
972 * level is the recursion depth
973 * returns true if the recusion can be terminated
975 static BOOL32
BezierCheck( int level
, POINT32
*Points
)
978 dx
=Points
[3].x
-Points
[0].x
;
979 dy
=Points
[3].y
-Points
[0].y
;
980 if(ABS(dy
)<=ABS(dx
)){/* shallow line */
981 /* check that control points are between begin and end */
982 if(Points
[1].x
< Points
[0].x
){
983 if(Points
[1].x
< Points
[3].x
)
986 if(Points
[1].x
> Points
[3].x
)
988 if(Points
[2].x
< Points
[0].x
){
989 if(Points
[2].x
< Points
[3].x
)
992 if(Points
[2].x
> Points
[3].x
)
994 dx
=BEZIERSHIFTDOWN(dx
);
996 if(abs(Points
[1].y
-Points
[0].y
-(dy
/dx
)*
997 BEZIERSHIFTDOWN(Points
[1].x
-Points
[0].x
)) > BEZIERPIXEL
||
998 abs(Points
[2].y
-Points
[0].y
-(dy
/dx
)*
999 BEZIERSHIFTDOWN(Points
[2].x
-Points
[0].x
)) > BEZIERPIXEL
)
1003 }else{ /* steep line */
1004 /* check that control points are between begin and end */
1005 if(Points
[1].y
< Points
[0].y
){
1006 if(Points
[1].y
< Points
[3].y
)
1009 if(Points
[1].y
> Points
[3].y
)
1011 if(Points
[2].y
< Points
[0].y
){
1012 if(Points
[2].y
< Points
[3].y
)
1015 if(Points
[2].y
> Points
[3].y
)
1017 dy
=BEZIERSHIFTDOWN(dy
);
1018 if(!dy
) return TRUE
;
1019 if(abs(Points
[1].x
-Points
[0].x
-(dx
/dy
)*
1020 BEZIERSHIFTDOWN(Points
[1].y
-Points
[0].y
)) > BEZIERPIXEL
||
1021 abs(Points
[2].x
-Points
[0].x
-(dx
/dy
)*
1022 BEZIERSHIFTDOWN(Points
[2].y
-Points
[0].y
)) > BEZIERPIXEL
)
1029 /***********************************************************************
1031 * Draw a -what microsoft calls- bezier curve
1032 * The routine recursively devides the curve
1033 * in two parts until a straight line can be drawn
1035 * level recusion depth counted backwards
1037 * Points array of begin(0), end(3) and control points(1 and 2)
1038 * XPoints array with points calculated sofar
1039 * *pIx nr points calculated sofar
1042 static void X11DRV_Bezier(int level
, DC
* dc
, POINT32
*Points
,
1043 XPoint
* xpoints
, unsigned int* pIx
)
1045 if(*pIx
== BEZMAXPOINTS
){
1046 TSXDrawLines( display
, dc
->u
.x
.drawable
, dc
->u
.x
.gc
,
1047 xpoints
, *pIx
, CoordModeOrigin
);
1050 if(!level
|| BezierCheck(level
, Points
)) {
1052 xpoints
[*pIx
].x
= dc
->w
.DCOrgX
+ BEZIERSHIFTDOWN(Points
[0].x
);
1053 xpoints
[*pIx
].y
= dc
->w
.DCOrgY
+ BEZIERSHIFTDOWN(Points
[0].y
);
1056 xpoints
[*pIx
].x
= dc
->w
.DCOrgX
+ BEZIERSHIFTDOWN(Points
[3].x
);
1057 xpoints
[*pIx
].y
= dc
->w
.DCOrgY
+ BEZIERSHIFTDOWN(Points
[3].y
);
1060 POINT32 Points2
[4]; /* for the second recursive call */
1061 Points2
[3]=Points
[3];
1062 BEZIERMIDDLE(Points2
[2], Points
[2], Points
[3]);
1063 BEZIERMIDDLE(Points2
[0], Points
[1], Points
[2]);
1064 BEZIERMIDDLE(Points2
[1],Points2
[0],Points2
[2]);
1066 BEZIERMIDDLE(Points
[1], Points
[0], Points
[1]);
1067 BEZIERMIDDLE(Points
[2], Points
[1], Points2
[0]);
1068 BEZIERMIDDLE(Points
[3], Points
[2], Points2
[1]);
1070 Points2
[0]=Points
[3];
1072 /* do the two halves */
1073 X11DRV_Bezier(level
-1, dc
, Points
, xpoints
, pIx
);
1074 X11DRV_Bezier(level
-1, dc
, Points2
, xpoints
, pIx
);
1078 /***********************************************************************
1080 * Implement functionality for PolyBezier and PolyBezierTo
1082 * [i] dc pointer to device context
1083 * [i] start, first point in curve
1084 * [i] BezierPoints , array of point filled with rest of the points
1085 * [i] count, number of points in BezierPoints, must be a
1089 X11DRV_PolyBezier(DC
*dc
, POINT32 start
, POINT32
*BezierPoints
, DWORD count
)
1095 TRACE(graphics
, "dc=%04x count=%ld %d,%d - %d,%d - %d,%d -%d,%d \n",
1098 (Points
+0)->x
, (Points
+0)->y
,
1099 (Points
+1)->x
, (Points
+1)->y
,
1100 (Points
+2)->x
, (Points
+2)->y
);
1101 if(!count
|| count
% 3){/* paranoid */
1102 WARN(graphics
," bad value for count : %ld\n", count
);
1105 xpoints
=(XPoint
*) xmalloc( sizeof(XPoint
)*BEZMAXPOINTS
);
1106 Points
[3].x
=BEZIERSHIFTUP(XLPTODP(dc
,start
.x
));
1107 Points
[3].y
=BEZIERSHIFTUP(YLPTODP(dc
,start
.y
));
1109 Points
[0]=Points
[3];
1111 Points
[i
].x
= BEZIERSHIFTUP(XLPTODP(dc
,BezierPoints
->x
));
1112 Points
[i
].y
= BEZIERSHIFTUP(YLPTODP(dc
,BezierPoints
->y
));
1115 X11DRV_Bezier(BEZIERMAXDEPTH
, dc
, Points
, xpoints
, &ix
);
1118 if( ix
) TSXDrawLines( display
, dc
->u
.x
.drawable
, dc
->u
.x
.gc
,
1119 xpoints
, ix
, CoordModeOrigin
);
1124 /**********************************************************************
1128 X11DRV_SetBkColor( DC
*dc
, COLORREF color
)
1130 X11DRV_PDEVICE
*physDev
= (X11DRV_PDEVICE
*)dc
->physDev
;
1133 oldColor
= dc
->w
.backgroundColor
;
1134 dc
->w
.backgroundColor
= color
;
1136 physDev
->backgroundPixel
= COLOR_ToPhysical( dc
, color
);
1141 /**********************************************************************
1142 * X11DRV_SetTextColor
1145 X11DRV_SetTextColor( DC
*dc
, COLORREF color
)
1147 X11DRV_PDEVICE
*physDev
= (X11DRV_PDEVICE
*)dc
->physDev
;
1150 oldColor
= dc
->w
.textColor
;
1151 dc
->w
.textColor
= color
;
1153 physDev
->textPixel
= COLOR_ToPhysical( dc
, color
);