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 DeleteObject32( tmpVisRgn );
627 /* Modify visible region */
628 if (!(prevVisRgn = SaveVisRgn( hdc ))) {
629 DeleteObject32( tmpVisRgn );
632 CombineRgn32( tmpVisRgn, prevVisRgn, tmpVisRgn, RGN_AND );
633 SelectVisRgn( hdc, tmpVisRgn );
634 DeleteObject32( tmpVisRgn );
636 /* Fill the region */
638 GetRgnBox32( dc->w.hGCClipRgn, &box );
639 if (DC_SetupGCForBrush( dc ))
640 TSXFillRectangle( display, dc->u.x.drawable, dc->u.x.gc,
641 dc->w.DCOrgX + box.left, dc->w.DCOrgY + box.top,
642 box.right-box.left, box.bottom-box.top );
644 /* Restore the visible region */
646 RestoreVisRgn( hdc );
650 /**********************************************************************
654 X11DRV_Polyline( DC *dc, LPPOINT32 pt, INT32 count )
659 if((oldwidth=dc->u.x.pen.width)==0) dc->u.x.pen.width=1;
661 points = (XPoint *) xmalloc (sizeof (XPoint) * (count));
662 for (i = 0; i < count; i++)
664 points[i].x = dc->w.DCOrgX + XLPTODP( dc, pt[i].x );
665 points[i].y = dc->w.DCOrgY + YLPTODP( dc, pt[i].y );
668 if (DC_SetupGCForPen ( dc ))
669 TSXDrawLines( display, dc->u.x.drawable, dc->u.x.gc,
670 points, count, CoordModeOrigin );
673 dc->u.x.pen.width=oldwidth;
678 /**********************************************************************
682 X11DRV_Polygon( DC *dc, LPPOINT32 pt, INT32 count )
687 points = (XPoint *) xmalloc (sizeof (XPoint) * (count+1));
688 for (i = 0; i < count; i++)
690 points[i].x = dc->w.DCOrgX + XLPTODP( dc, pt[i].x );
691 points[i].y = dc->w.DCOrgY + YLPTODP( dc, pt[i].y );
693 points[count] = points[0];
695 if (DC_SetupGCForBrush( dc ))
696 TSXFillPolygon( display, dc->u.x.drawable, dc->u.x.gc,
697 points, count+1, Complex, CoordModeOrigin);
699 if (DC_SetupGCForPen ( dc ))
700 TSXDrawLines( display, dc->u.x.drawable, dc->u.x.gc,
701 points, count+1, CoordModeOrigin );
708 /**********************************************************************
712 X11DRV_PolyPolygon( DC *dc, LPPOINT32 pt, LPINT32 counts, UINT32 polygons)
716 /* FIXME: The points should be converted to device coords before */
717 /* creating the region. But as CreatePolyPolygonRgn is not */
718 /* really correct either, it doesn't matter much... */
719 /* At least the outline will be correct :-) */
720 hrgn = CreatePolyPolygonRgn32( pt, counts, polygons, dc->w.polyFillMode );
721 X11DRV_PaintRgn( dc, hrgn );
722 DeleteObject32( hrgn );
724 /* Draw the outline of the polygons */
726 if (DC_SetupGCForPen ( dc ))
731 for (i = 0; i < polygons; i++) if (counts[i] > max) max = counts[i];
732 points = (XPoint *) xmalloc( sizeof(XPoint) * (max+1) );
734 for (i = 0; i < polygons; i++)
736 for (j = 0; j < counts[i]; j++)
738 points[j].x = dc->w.DCOrgX + XLPTODP( dc, pt->x );
739 points[j].y = dc->w.DCOrgY + YLPTODP( dc, pt->y );
742 points[j] = points[0];
743 TSXDrawLines( display, dc->u.x.drawable, dc->u.x.gc,
744 points, j + 1, CoordModeOrigin );
752 /**********************************************************************
753 * X11DRV_PolyPolyline
756 X11DRV_PolyPolyline( DC *dc, LPPOINT32 pt, LPDWORD counts, DWORD polylines )
758 if (DC_SetupGCForPen ( dc ))
763 for (i = 0; i < polylines; i++) if (counts[i] > max) max = counts[i];
764 points = (XPoint *) xmalloc( sizeof(XPoint) * (max+1) );
766 for (i = 0; i < polylines; i++)
768 for (j = 0; j < counts[i]; j++)
770 points[j].x = dc->w.DCOrgX + XLPTODP( dc, pt->x );
771 points[j].y = dc->w.DCOrgY + YLPTODP( dc, pt->y );
774 points[j] = points[0];
775 TSXDrawLines( display, dc->u.x.drawable, dc->u.x.gc,
776 points, j + 1, CoordModeOrigin );
784 /**********************************************************************
785 * X11DRV_InternalFloodFill
787 * Internal helper function for flood fill.
788 * (xorg,yorg) is the origin of the X image relative to the drawable.
789 * (x,y) is relative to the origin of the X image.
791 static void X11DRV_InternalFloodFill(XImage *image, DC *dc,
794 Pixel pixel, WORD fillType )
798 #define TO_FLOOD(x,y) ((fillType == FLOODFILLBORDER) ? \
799 (XGetPixel(image,x,y) != pixel) : \
800 (XGetPixel(image,x,y) == pixel))
802 if (!TO_FLOOD(x,y)) return;
804 /* Find left and right boundaries */
807 while ((left > 0) && TO_FLOOD( left-1, y )) left--;
808 while ((right < image->width) && TO_FLOOD( right, y )) right++;
809 XFillRectangle( display, dc->u.x.drawable, dc->u.x.gc,
810 xOrg + left, yOrg + y, right-left, 1 );
812 /* Set the pixels of this line so we don't fill it again */
814 for (x = left; x < right; x++)
816 if (fillType == FLOODFILLBORDER) XPutPixel( image, x, y, pixel );
817 else XPutPixel( image, x, y, ~pixel );
820 /* Fill the line above */
827 while ((x < right) && !TO_FLOOD(x,y)) x++;
828 if (x >= right) break;
829 while ((x < right) && TO_FLOOD(x,y)) x++;
830 X11DRV_InternalFloodFill(image, dc, x-1, y,
831 xOrg, yOrg, pixel, fillType );
835 /* Fill the line below */
837 if ((y += 2) < image->height)
842 while ((x < right) && !TO_FLOOD(x,y)) x++;
843 if (x >= right) break;
844 while ((x < right) && TO_FLOOD(x,y)) x++;
845 X11DRV_InternalFloodFill(image, dc, x-1, y,
846 xOrg, yOrg, pixel, fillType );
853 /**********************************************************************
856 * Main flood-fill routine.
858 * The Xlib critical section must be entered before calling this function.
861 struct FloodFill_params
870 static BOOL32 X11DRV_DoFloodFill( const struct FloodFill_params *params )
876 if (GetRgnBox32( dc->w.hGCClipRgn, &rect ) == ERROR) return FALSE;
878 if (!(image = XGetImage( display, dc->u.x.drawable,
879 dc->w.DCOrgX + rect.left,
880 dc->w.DCOrgY + rect.top,
881 rect.right - rect.left,
882 rect.bottom - rect.top,
883 AllPlanes, ZPixmap ))) return FALSE;
885 if (DC_SetupGCForBrush( dc ))
887 /* ROP mode is always GXcopy for flood-fill */
888 XSetFunction( display, dc->u.x.gc, GXcopy );
889 X11DRV_InternalFloodFill(image, dc,
890 XLPTODP(dc,params->x) - rect.left,
891 YLPTODP(dc,params->y) - rect.top,
892 dc->w.DCOrgX + rect.left,
893 dc->w.DCOrgY + rect.top,
894 COLOR_ToPhysical( dc, params->color ),
898 XDestroyImage( image );
903 /**********************************************************************
904 * X11DRV_ExtFloodFill
907 X11DRV_ExtFloodFill( DC *dc, INT32 x, INT32 y, COLORREF color,
911 struct FloodFill_params params = { dc, x, y, color, fillType };
913 TRACE(graphics, "X11DRV_ExtFloodFill %d,%d %06lx %d\n",
914 x, y, color, fillType );
916 if (!PtVisible32( dc->hSelf, x, y )) return FALSE;
917 EnterCriticalSection( &X11DRV_CritSection );
918 result = CALL_LARGE_STACK( X11DRV_DoFloodFill, ¶ms );
919 LeaveCriticalSection( &X11DRV_CritSection );
923 /******************************************************************
925 * *Very* simple bezier drawing code,
927 * It uses a recursive algorithm to divide the curve in a series
928 * of straight line segements. Not ideal but for me sufficient.
929 * If you are in need for something better look for some incremental
932 * 7 July 1998 Rein Klazes
936 * some macro definitions for bezier drawing
938 * to avoid trucation errors the coordinates are
939 * shifted upwards. When used in drawing they are
940 * shifted down again, including correct rounding
941 * and avoiding floating point arithmatic
942 * 4 bits should allow 27 bits coordinates which I saw
943 * somewere in the win32 doc's
947 #define BEZIERSHIFTBITS 4
948 #define BEZIERSHIFTUP(x) ((x)<<BEZIERSHIFTBITS)
949 #define BEZIERPIXEL BEZIERSHIFTUP(1)
950 #define BEZIERSHIFTDOWN(x) (((x)+(1<<(BEZIERSHIFTBITS-1)))>>BEZIERSHIFTBITS)
951 /* maximum depth of recursion */
952 #define BEZIERMAXDEPTH 8
954 /* size of array to store points on */
955 /* enough for one curve */
956 #define BEZMAXPOINTS (150)
958 /* calculate Bezier average, in this case the middle
959 * correctly rounded...
962 #define BEZIERMIDDLE(Mid, P1, P2) \
963 (Mid).x=((P1).x+(P2).x + 1)/2;\
964 (Mid).y=((P1).y+(P2).y + 1)/2;
966 /**********************************************************
967 * BezierCheck helper function to check
968 * that recursion can be terminated
969 * Points[0] and Points[3] are begin and endpoint
970 * Points[1] and Points[2] are control points
971 * level is the recursion depth
972 * returns true if the recusion can be terminated
974 static BOOL32 BezierCheck( int level, POINT32 *Points)
977 dx=Points[3].x-Points[0].x;
978 dy=Points[3].y-Points[0].y;
979 if(ABS(dy)<ABS(dx)){/* shallow line */
980 /* check that control points are between begin and end */
981 if( (Points[1].x-Points[0].x)*dx < 0 ||
982 (Points[2].x-Points[0].x)*dx < 0 ) return FALSE;
983 dx=BEZIERSHIFTDOWN(dx);
985 if(abs(Points[1].y-Points[0].y-(dy/dx)*
986 BEZIERSHIFTDOWN(Points[1].x-Points[0].x)) > BEZIERPIXEL ||
987 abs(Points[2].y-Points[0].y-(dy/dx)*
988 BEZIERSHIFTDOWN(Points[2].x-Points[0].x)) > BEZIERPIXEL )
992 }else{ /* steep line */
993 /* check that control points are between begin and end */
994 if( (Points[1].y-Points[0].y)*dy < 0 ||
995 (Points[2].y-Points[0].y)*dy < 0 ) return FALSE;
996 dy=BEZIERSHIFTDOWN(dy);
998 if(abs(Points[1].x-Points[0].x-(dx/dy)*
999 BEZIERSHIFTDOWN(Points[1].y-Points[0].y)) > BEZIERPIXEL ||
1000 abs(Points[2].x-Points[0].x-(dx/dy)*
1001 BEZIERSHIFTDOWN(Points[2].y-Points[0].y)) > BEZIERPIXEL )
1008 /***********************************************************************
1010 * Draw a -what microsoft calls- bezier curve
1011 * The routine recursively devides the curve
1012 * in two parts until a straight line can be drawn
1014 * level recusion depth counted backwards
1016 * Points array of begin(0), end(3) and control points(1 and 2)
1017 * XPoints array with points calculated sofar
1018 * *pIx nr points calculated sofar
1021 static void X11DRV_Bezier(int level, DC * dc, POINT32 *Points,
1022 XPoint* xpoints, unsigned int* pIx)
1024 if(*pIx == BEZMAXPOINTS){
1025 TSXDrawLines( display, dc->u.x.drawable, dc->u.x.gc,
1026 xpoints, *pIx, CoordModeOrigin );
1029 if(!level || BezierCheck(level, Points)) {
1031 xpoints[*pIx].x= dc->w.DCOrgX + BEZIERSHIFTDOWN(Points[0].x);
1032 xpoints[*pIx].y= dc->w.DCOrgY + BEZIERSHIFTDOWN(Points[0].y);
1035 xpoints[*pIx].x= dc->w.DCOrgX + BEZIERSHIFTDOWN(Points[3].x);
1036 xpoints[*pIx].y= dc->w.DCOrgY + BEZIERSHIFTDOWN(Points[3].y);
1039 POINT32 Points2[4]; /* for the second recursive call */
1040 Points2[3]=Points[3];
1041 BEZIERMIDDLE(Points2[2], Points[2], Points[3]);
1042 BEZIERMIDDLE(Points2[0], Points[1], Points[2]);
1043 BEZIERMIDDLE(Points2[1],Points2[0],Points2[2]);
1045 BEZIERMIDDLE(Points[1], Points[0], Points[1]);
1046 BEZIERMIDDLE(Points[2], Points[1], Points2[0]);
1047 BEZIERMIDDLE(Points[3], Points[2], Points2[1]);
1049 Points2[0]=Points[3];
1051 /* do the two halves */
1052 X11DRV_Bezier(level-1, dc, Points, xpoints, pIx);
1053 X11DRV_Bezier(level-1, dc, Points2, xpoints, pIx);
1057 /***********************************************************************
1059 * Implement functionality for PolyBezier and PolyBezierTo
1061 * [i] dc pointer to device context
1062 * [i] start, first point in curve
1063 * [i] BezierPoints , array of point filled with rest of the points
1064 * [i] count, number of points in BezierPoints, must be a
1068 X11DRV_PolyBezier(DC *dc, POINT32 start, POINT32 *BezierPoints, DWORD count)
1074 TRACE(graphics, "dc=%04x count=%ld %d,%d - %d,%d - %d,%d -%d,%d \n",
1077 (Points+0)->x, (Points+0)->y,
1078 (Points+1)->x, (Points+1)->y,
1079 (Points+2)->x, (Points+2)->y);
1080 if(!count || count % 3){/* paranoid */
1081 WARN(graphics," bad value for count : %ld\n", count);
1084 xpoints=(XPoint*) xmalloc( sizeof(XPoint)*BEZMAXPOINTS);
1085 Points[3].x=BEZIERSHIFTUP(XLPTODP(dc,start.x));
1086 Points[3].y=BEZIERSHIFTUP(YLPTODP(dc,start.y));
1088 Points[0]=Points[3];
1090 Points[i].x= BEZIERSHIFTUP(XLPTODP(dc,BezierPoints->x));
1091 Points[i].y= BEZIERSHIFTUP(YLPTODP(dc,BezierPoints->y));
1094 X11DRV_Bezier(BEZIERMAXDEPTH , dc, Points, xpoints, &ix );
1097 if( ix) TSXDrawLines( display, dc->u.x.drawable, dc->u.x.gc,
1098 xpoints, ix, CoordModeOrigin );
1103 /**********************************************************************
1107 X11DRV_SetBkColor( DC *dc, COLORREF color )
1109 X11DRV_PDEVICE *physDev = (X11DRV_PDEVICE *)dc->physDev;
1112 oldColor = dc->w.backgroundColor;
1113 dc->w.backgroundColor = color;
1115 physDev->backgroundPixel = COLOR_ToPhysical( dc, color );
1120 /**********************************************************************
1121 * X11DRV_SetTextColor
1124 X11DRV_SetTextColor( DC *dc, COLORREF color )
1126 X11DRV_PDEVICE *physDev = (X11DRV_PDEVICE *)dc->physDev;
1129 oldColor = dc->w.textColor;
1130 dc->w.textColor = color;
1132 physDev->textPixel = COLOR_ToPhysical( dc, color );