Release 981025.
[wine/multimedia.git] / graphics / x11drv / graphics.c
blob750c757841a2b44ec65467ec968a637c2f79cddf
1 /*
2 * X11 graphics driver graphics functions
4 * Copyright 1993,1994 Alexandre Julliard
5 */
8 /*
9 * FIXME: none of these functions obey the GM_ADVANCED
10 * graphics mode
13 #include <math.h>
14 #ifdef HAVE_FLOAT_H
15 # include <float.h>
16 #endif
17 #include <stdlib.h>
18 #include "ts_xlib.h"
19 #include "ts_xutil.h"
20 #include <X11/Intrinsic.h>
21 #ifndef PI
22 #define PI M_PI
23 #endif
24 #include <string.h>
26 #include "x11drv.h"
27 #include "bitmap.h"
28 #include "gdi.h"
29 #include "graphics.h"
30 #include "dc.h"
31 #include "bitmap.h"
32 #include "callback.h"
33 #include "metafile.h"
34 #include "palette.h"
35 #include "color.h"
36 #include "region.h"
37 #include "struct32.h"
38 #include "debug.h"
39 #include "xmalloc.h"
41 #define ABS(x) ((x)<0?(-(x)):(x))
42 /**********************************************************************
43 * X11DRV_MoveToEx
45 BOOL32
46 X11DRV_MoveToEx(DC *dc,INT32 x,INT32 y,LPPOINT32 pt) {
47 if (pt)
49 pt->x = dc->w.CursPosX;
50 pt->y = dc->w.CursPosY;
52 dc->w.CursPosX = x;
53 dc->w.CursPosY = y;
54 return TRUE;
57 /***********************************************************************
58 * X11DRV_LineTo
60 BOOL32
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 ) );
69 dc->w.CursPosX = x;
70 dc->w.CursPosY = y;
71 return TRUE;
76 /***********************************************************************
77 * GRAPH_DrawArc
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.
83 static BOOL32
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;
91 XPoint points[4];
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;
116 left += width / 2;
117 right -= (width - 1) / 2;
118 top += width / 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) */
133 start_angle = 0;
134 end_angle = 2* PI;
136 else /* notorious cases */
137 if ((start_angle == PI)&&( end_angle <0))
138 start_angle = - PI;
139 else
140 if ((end_angle == PI)&&( start_angle <0))
141 end_angle = - PI;
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 );
161 if (lines) {
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)
183 if (lines == 2) {
184 INT32 dx1,dy1;
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--;
193 if(dx1<0) {
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--;
197 } else {
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--;
205 if( dx1<0){
206 if( dy1>0) points[3].y--;
207 if(((right-left) | -2) == -2 ) points[2].x--;
208 }else {
209 points[3].y--;
210 if( dx1 * 64 < dy1 * -37 ) points[3].x--;
212 lines++;
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;
220 return TRUE;
224 /***********************************************************************
225 * X11DRV_Arc
227 BOOL32
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 /***********************************************************************
237 * X11DRV_Pie
239 BOOL32
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 /***********************************************************************
248 * X11DRV_Chord
250 BOOL32
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 /***********************************************************************
260 * X11DRV_Ellipse
262 BOOL32
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;
283 left += width / 2;
284 right -= (width - 1) / 2;
285 top += width / 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;
300 return TRUE;
304 /***********************************************************************
305 * X11DRV_Rectangle
307 BOOL32
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;
333 left += width / 2;
334 right -= (width - 1) / 2;
335 top += width / 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;
359 return TRUE;
362 /***********************************************************************
363 * X11DRV_RoundRect
365 BOOL32
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))
380 return TRUE;
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;
399 left += width / 2;
400 right -= (width - 1) / 2;
401 top += width / 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,
415 0, 360 * 64 );
416 else{
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,
421 dc->w.DCOrgX + left,
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 );
432 }else{
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,
437 dc->w.DCOrgX + left,
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,
446 dc->w.DCOrgY + top,
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,
460 (ell_height) / 2 );
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,
467 right - left - 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 );
486 else{
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,
491 dc->w.DCOrgX + left,
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,
501 dc->w.DCOrgY + top,
502 ell_width - 1 , bottom - top - 1, 270 * 64 , 180 * 64 );
503 }else{
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,
522 dc->w.DCOrgY + top,
523 dc->w.DCOrgX + right - (ell_width+1) / 2,
524 dc->w.DCOrgY + top);
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,
539 dc->w.DCOrgX + left,
540 dc->w.DCOrgY + top + ell_height / 2,
541 dc->w.DCOrgX + left,
542 dc->w.DCOrgY + bottom - (ell_height+1) / 2);
545 dc->u.x.pen.width=oldwidth;
546 dc->u.x.pen.endcap=oldendcap;
547 return TRUE;
551 /***********************************************************************
552 * X11DRV_SetPixel
554 COLORREF
555 X11DRV_SetPixel( DC *dc, INT32 x, INT32 y, COLORREF color )
557 Pixel pixel;
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 /***********************************************************************
574 * X11DRV_GetPixel
576 COLORREF
577 X11DRV_GetPixel( DC *dc, INT32 x, INT32 y )
579 static Pixmap pixmap = 0;
580 XImage * image;
581 int pixel;
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 );
591 else
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,
598 x, y, 1, 1, 0, 0 );
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 /***********************************************************************
610 * X11DRV_PaintRgn
612 BOOL32
613 X11DRV_PaintRgn( DC *dc, HRGN32 hrgn )
615 RECT32 box;
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 );
625 return FALSE;
628 /* Modify visible region */
629 if (!(prevVisRgn = SaveVisRgn( hdc ))) {
630 DeleteObject32( tmpVisRgn );
631 return FALSE;
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,
642 box.left, box.top,
643 box.right-box.left, box.bottom-box.top );
645 /* Restore the visible region */
647 RestoreVisRgn( hdc );
648 return TRUE;
651 /**********************************************************************
652 * X11DRV_Polyline
654 BOOL32
655 X11DRV_Polyline( DC *dc, LPPOINT32 pt, INT32 count )
657 INT32 oldwidth;
658 register int i;
659 XPoint *points;
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 );
673 free( points );
674 dc->u.x.pen.width=oldwidth;
675 return TRUE;
679 /**********************************************************************
680 * X11DRV_Polygon
682 BOOL32
683 X11DRV_Polygon( DC *dc, LPPOINT32 pt, INT32 count )
685 register int i;
686 XPoint *points;
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 );
704 free( points );
705 return TRUE;
709 /**********************************************************************
710 * X11DRV_PolyPolygon
712 BOOL32
713 X11DRV_PolyPolygon( DC *dc, LPPOINT32 pt, LPINT32 counts, UINT32 polygons)
715 HRGN32 hrgn;
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 ))
729 int i, j, max = 0;
730 XPoint *points;
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 );
741 pt++;
743 points[j] = points[0];
744 TSXDrawLines( display, dc->u.x.drawable, dc->u.x.gc,
745 points, j + 1, CoordModeOrigin );
747 free( points );
749 return TRUE;
753 /**********************************************************************
754 * X11DRV_PolyPolyline
756 BOOL32
757 X11DRV_PolyPolyline( DC *dc, LPPOINT32 pt, LPDWORD counts, DWORD polylines )
759 if (DC_SetupGCForPen ( dc ))
761 int i, j, max = 0;
762 XPoint *points;
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 );
773 pt++;
775 points[j] = points[0];
776 TSXDrawLines( display, dc->u.x.drawable, dc->u.x.gc,
777 points, j + 1, CoordModeOrigin );
779 free( points );
781 return TRUE;
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,
793 int x, int y,
794 int xOrg, int yOrg,
795 Pixel pixel, WORD fillType )
797 int left, right;
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 */
807 left = right = x;
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 */
823 if (--y >= 0)
825 x = left;
826 while (x < right)
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)
840 x = left;
841 while (x < right)
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 );
850 #undef TO_FLOOD
854 /**********************************************************************
855 * X11DRV_DoFloodFill
857 * Main flood-fill routine.
859 * The Xlib critical section must be entered before calling this function.
862 struct FloodFill_params
864 DC *dc;
865 INT32 x;
866 INT32 y;
867 COLORREF color;
868 UINT32 fillType;
871 static BOOL32 X11DRV_DoFloodFill( const struct FloodFill_params *params )
873 XImage *image;
874 RECT32 rect;
875 DC *dc = params->dc;
877 if (GetRgnBox32( dc->w.hGCClipRgn, &rect ) == ERROR) return FALSE;
879 if (!(image = XGetImage( display, dc->u.x.drawable,
880 rect.left,
881 rect.top,
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,
893 rect.left,
894 rect.top,
895 COLOR_ToPhysical( dc, params->color ),
896 params->fillType );
899 XDestroyImage( image );
900 return TRUE;
904 /**********************************************************************
905 * X11DRV_ExtFloodFill
907 BOOL32
908 X11DRV_ExtFloodFill( DC *dc, INT32 x, INT32 y, COLORREF color,
909 UINT32 fillType )
911 BOOL32 result;
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, &params );
920 LeaveCriticalSection( &X11DRV_CritSection );
921 return result;
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
931 * algorithm.
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...
961 * */
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)
977 INT32 dx, dy;
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)
984 return FALSE;
985 }else
986 if(Points[1].x > Points[3].x)
987 return FALSE;
988 if(Points[2].x < Points[0].x){
989 if(Points[2].x < Points[3].x)
990 return FALSE;
991 }else
992 if(Points[2].x > Points[3].x)
993 return FALSE;
994 dx=BEZIERSHIFTDOWN(dx);
995 if(!dx) return TRUE;
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 )
1000 return FALSE;
1001 else
1002 return TRUE;
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)
1007 return FALSE;
1008 }else
1009 if(Points[1].y > Points[3].y)
1010 return FALSE;
1011 if(Points[2].y < Points[0].y){
1012 if(Points[2].y < Points[3].y)
1013 return FALSE;
1014 }else
1015 if(Points[2].y > Points[3].y)
1016 return FALSE;
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 )
1023 return FALSE;
1024 else
1025 return TRUE;
1029 /***********************************************************************
1030 * X11DRV_Bezier
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
1036 * dc device context
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 );
1048 *pIx=0;
1050 if(!level || BezierCheck(level, Points)) {
1051 if(*pIx == 0){
1052 xpoints[*pIx].x= dc->w.DCOrgX + BEZIERSHIFTDOWN(Points[0].x);
1053 xpoints[*pIx].y= dc->w.DCOrgY + BEZIERSHIFTDOWN(Points[0].y);
1054 *pIx=1;
1056 xpoints[*pIx].x= dc->w.DCOrgX + BEZIERSHIFTDOWN(Points[3].x);
1057 xpoints[*pIx].y= dc->w.DCOrgY + BEZIERSHIFTDOWN(Points[3].y);
1058 (*pIx) ++;
1059 } else {
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 /***********************************************************************
1079 * X11DRV_PolyBezier
1080 * Implement functionality for PolyBezier and PolyBezierTo
1081 * calls.
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
1086 * multiple of 3.
1088 BOOL32
1089 X11DRV_PolyBezier(DC *dc, POINT32 start, POINT32 *BezierPoints, DWORD count)
1091 POINT32 Points[4];
1092 int i;
1093 unsigned int ix=0;
1094 XPoint* xpoints;
1095 TRACE(graphics, "dc=%04x count=%ld %d,%d - %d,%d - %d,%d -%d,%d \n",
1096 (int)dc, count,
1097 start.x, start.y,
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);
1103 return FALSE;
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));
1108 while(count){
1109 Points[0]=Points[3];
1110 for(i=1;i<4;i++) {
1111 Points[i].x= BEZIERSHIFTUP(XLPTODP(dc,BezierPoints->x));
1112 Points[i].y= BEZIERSHIFTUP(YLPTODP(dc,BezierPoints->y));
1113 BezierPoints++;
1115 X11DRV_Bezier(BEZIERMAXDEPTH , dc, Points, xpoints, &ix );
1116 count -=3;
1118 if( ix) TSXDrawLines( display, dc->u.x.drawable, dc->u.x.gc,
1119 xpoints, ix, CoordModeOrigin );
1120 free(xpoints);
1121 return TRUE;
1124 /**********************************************************************
1125 * X11DRV_SetBkColor
1127 COLORREF
1128 X11DRV_SetBkColor( DC *dc, COLORREF color )
1130 X11DRV_PDEVICE *physDev = (X11DRV_PDEVICE *)dc->physDev;
1131 COLORREF oldColor;
1133 oldColor = dc->w.backgroundColor;
1134 dc->w.backgroundColor = color;
1136 physDev->backgroundPixel = COLOR_ToPhysical( dc, color );
1138 return oldColor;
1141 /**********************************************************************
1142 * X11DRV_SetTextColor
1144 COLORREF
1145 X11DRV_SetTextColor( DC *dc, COLORREF color )
1147 X11DRV_PDEVICE *physDev = (X11DRV_PDEVICE *)dc->physDev;
1148 COLORREF oldColor;
1150 oldColor = dc->w.textColor;
1151 dc->w.textColor = color;
1153 physDev->textPixel = COLOR_ToPhysical( dc, color );
1155 return oldColor;