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>
42 #define ABS(x) ((x)<0?(-(x)):(x))
44 /* ROP code to GC function conversion */
45 const int X11DRV_XROPfunction[16] =
47 GXclear, /* R2_BLACK */
48 GXnor, /* R2_NOTMERGEPEN */
49 GXandInverted, /* R2_MASKNOTPEN */
50 GXcopyInverted, /* R2_NOTCOPYPEN */
51 GXandReverse, /* R2_MASKPENNOT */
52 GXinvert, /* R2_NOT */
53 GXxor, /* R2_XORPEN */
54 GXnand, /* R2_NOTMASKPEN */
55 GXand, /* R2_MASKPEN */
56 GXequiv, /* R2_NOTXORPEN */
58 GXorInverted, /* R2_MERGENOTPEN */
59 GXcopy, /* R2_COPYPEN */
60 GXorReverse, /* R2_MERGEPENNOT */
61 GXor, /* R2_MERGEPEN */
66 /***********************************************************************
67 * X11DRV_SetupGCForPatBlt
69 * Setup the GC for a PatBlt operation using current brush.
70 * If fMapColors is TRUE, X pixels are mapped to Windows colors.
71 * Return FALSE if brush is BS_NULL, TRUE otherwise.
73 BOOL32 X11DRV_SetupGCForPatBlt( DC * dc, GC gc, BOOL32 fMapColors )
79 if (dc->u.x.brush.style == BS_NULL) return FALSE;
80 if (dc->u.x.brush.pixel == -1)
82 /* Special case used for monochrome pattern brushes.
83 * We need to swap foreground and background because
84 * Windows does it the wrong way...
86 val.foreground = dc->u.x.backgroundPixel;
87 val.background = dc->u.x.textPixel;
91 val.foreground = dc->u.x.brush.pixel;
92 val.background = dc->u.x.backgroundPixel;
94 if (fMapColors && COLOR_PixelToPalette)
96 val.foreground = COLOR_PixelToPalette[val.foreground];
97 val.background = COLOR_PixelToPalette[val.background];
100 if (dc->w.flags & DC_DIRTY) CLIPPING_UpdateGCRegion(dc);
102 val.function = X11DRV_XROPfunction[dc->w.ROPmode-1];
104 ** Let's replace GXinvert by GXxor with (black xor white)
105 ** This solves the selection color and leak problems in excel
106 ** FIXME : Let's do that only if we work with X-pixels, not with Win-pixels
108 if (val.function == GXinvert)
110 val.foreground = BlackPixelOfScreen(screen) ^ WhitePixelOfScreen(screen);
111 val.function = GXxor;
113 val.fill_style = dc->u.x.brush.fillStyle;
114 switch(val.fill_style)
117 case FillOpaqueStippled:
118 if (dc->w.backgroundMode==OPAQUE) val.fill_style = FillOpaqueStippled;
119 val.stipple = dc->u.x.brush.pixmap;
124 if (fMapColors && COLOR_PixelToPalette)
128 EnterCriticalSection( &X11DRV_CritSection );
129 pixmap = XCreatePixmap( display, rootWindow, 8, 8, screenDepth );
130 image = XGetImage( display, dc->u.x.brush.pixmap, 0, 0, 8, 8,
131 AllPlanes, ZPixmap );
132 for (y = 0; y < 8; y++)
133 for (x = 0; x < 8; x++)
134 XPutPixel( image, x, y,
135 COLOR_PixelToPalette[XGetPixel( image, x, y)] );
136 XPutImage( display, pixmap, gc, image, 0, 0, 0, 0, 8, 8 );
137 XDestroyImage( image );
138 LeaveCriticalSection( &X11DRV_CritSection );
141 else val.tile = dc->u.x.brush.pixmap;
149 val.ts_x_origin = dc->w.DCOrgX + dc->w.brushOrgX;
150 val.ts_y_origin = dc->w.DCOrgY + dc->w.brushOrgY;
151 val.fill_rule = (dc->w.polyFillMode==WINDING) ? WindingRule : EvenOddRule;
152 TSXChangeGC( display, gc,
153 GCFunction | GCForeground | GCBackground | GCFillStyle |
154 GCFillRule | GCTileStipXOrigin | GCTileStipYOrigin | mask,
156 if (pixmap) TSXFreePixmap( display, pixmap );
161 /***********************************************************************
162 * X11DRV_SetupGCForBrush
164 * Setup dc->u.x.gc for drawing operations using current brush.
165 * Return FALSE if brush is BS_NULL, TRUE otherwise.
167 BOOL32 X11DRV_SetupGCForBrush( DC * dc )
169 return X11DRV_SetupGCForPatBlt( dc, dc->u.x.gc, FALSE );
173 /***********************************************************************
174 * X11DRV_SetupGCForPen
176 * Setup dc->u.x.gc for drawing operations using current pen.
177 * Return FALSE if pen is PS_NULL, TRUE otherwise.
179 BOOL32 X11DRV_SetupGCForPen( DC * dc )
183 if (dc->u.x.pen.style == PS_NULL) return FALSE;
185 if (dc->w.flags & DC_DIRTY) CLIPPING_UpdateGCRegion(dc);
187 switch (dc->w.ROPmode)
190 val.foreground = BlackPixelOfScreen( screen );
191 val.function = GXcopy;
194 val.foreground = WhitePixelOfScreen( screen );
195 val.function = GXcopy;
198 val.foreground = dc->u.x.pen.pixel;
199 /* It is very unlikely someone wants to XOR with 0 */
200 /* This fixes the rubber-drawings in paintbrush */
201 if (val.foreground == 0)
202 val.foreground = BlackPixelOfScreen( screen )
203 ^ WhitePixelOfScreen( screen );
204 val.function = GXxor;
207 val.foreground = dc->u.x.pen.pixel;
208 val.function = X11DRV_XROPfunction[dc->w.ROPmode-1];
210 val.background = dc->u.x.backgroundPixel;
211 val.fill_style = FillSolid;
212 if ((dc->u.x.pen.style!=PS_SOLID) && (dc->u.x.pen.style!=PS_INSIDEFRAME))
214 TSXSetDashes( display, dc->u.x.gc, 0,
215 dc->u.x.pen.dashes, dc->u.x.pen.dash_len );
216 val.line_style = (dc->w.backgroundMode == OPAQUE) ?
217 LineDoubleDash : LineOnOffDash;
219 else val.line_style = LineSolid;
220 val.line_width = dc->u.x.pen.width;
221 if (val.line_width <= 1) {
222 val.cap_style = CapNotLast;
224 switch (dc->u.x.pen.endcap)
226 case PS_ENDCAP_SQUARE:
227 val.cap_style = CapProjecting;
230 val.cap_style = CapButt;
232 case PS_ENDCAP_ROUND:
234 val.cap_style = CapRound;
237 switch (dc->u.x.pen.linejoin)
240 val.join_style = JoinBevel;
243 val.join_style = JoinMiter;
247 val.join_style = JoinRound;
249 TSXChangeGC( display, dc->u.x.gc,
250 GCFunction | GCForeground | GCBackground | GCLineWidth |
251 GCLineStyle | GCCapStyle | GCJoinStyle | GCFillStyle, &val );
256 /***********************************************************************
257 * X11DRV_SetupGCForText
259 * Setup dc->u.x.gc for text drawing operations.
260 * Return FALSE if the font is null, TRUE otherwise.
262 BOOL32 X11DRV_SetupGCForText( DC * dc )
264 XFontStruct* xfs = XFONT_GetFontStruct( dc->u.x.font );
270 if (dc->w.flags & DC_DIRTY) CLIPPING_UpdateGCRegion(dc);
272 val.function = GXcopy; /* Text is always GXcopy */
273 val.foreground = dc->u.x.textPixel;
274 val.background = dc->u.x.backgroundPixel;
275 val.fill_style = FillSolid;
278 TSXChangeGC( display, dc->u.x.gc,
279 GCFunction | GCForeground | GCBackground | GCFillStyle |
283 WARN(dc, "Physical font failure\n" );
291 /**********************************************************************
295 X11DRV_MoveToEx(DC *dc,INT32 x,INT32 y,LPPOINT32 pt) {
298 pt->x = dc->w.CursPosX;
299 pt->y = dc->w.CursPosY;
306 /***********************************************************************
310 X11DRV_LineTo( DC *dc, INT32 x, INT32 y )
312 if (X11DRV_SetupGCForPen( dc ))
313 TSXDrawLine(display, dc->u.x.drawable, dc->u.x.gc,
314 dc->w.DCOrgX + XLPTODP( dc, dc->w.CursPosX ),
315 dc->w.DCOrgY + YLPTODP( dc, dc->w.CursPosY ),
316 dc->w.DCOrgX + XLPTODP( dc, x ),
317 dc->w.DCOrgY + YLPTODP( dc, y ) );
325 /***********************************************************************
328 * Helper functions for Arc(), Chord() and Pie().
329 * 'lines' is the number of lines to draw: 0 for Arc, 1 for Chord, 2 for Pie.
333 X11DRV_DrawArc( DC *dc, INT32 left, INT32 top, INT32 right,
334 INT32 bottom, INT32 xstart, INT32 ystart,
335 INT32 xend, INT32 yend, INT32 lines )
337 INT32 xcenter, ycenter, istart_angle, idiff_angle;
338 INT32 width, oldwidth, oldendcap;
339 double start_angle, end_angle;
342 left = XLPTODP( dc, left );
343 top = YLPTODP( dc, top );
344 right = XLPTODP( dc, right );
345 bottom = YLPTODP( dc, bottom );
346 xstart = XLPTODP( dc, xstart );
347 ystart = YLPTODP( dc, ystart );
348 xend = XLPTODP( dc, xend );
349 yend = YLPTODP( dc, yend );
351 if (right < left) { INT32 tmp = right; right = left; left = tmp; }
352 if (bottom < top) { INT32 tmp = bottom; bottom = top; top = tmp; }
353 if ((left == right) || (top == bottom)
354 ||(lines && ((right-left==1)||(bottom-top==1)))) return TRUE;
356 oldwidth = width = dc->u.x.pen.width;
357 oldendcap= dc->u.x.pen.endcap;
358 if (!width) width = 1;
359 if(dc->u.x.pen.style == PS_NULL) width = 0;
361 if ((dc->u.x.pen.style == PS_INSIDEFRAME))
363 if (2*width > (right-left)) width=(right-left + 1)/2;
364 if (2*width > (bottom-top)) width=(bottom-top + 1)/2;
366 right -= (width - 1) / 2;
368 bottom -= (width - 1) / 2;
370 if(width == 0) width=1; /* more accurate */
371 dc->u.x.pen.width=width;
372 dc->u.x.pen.endcap=PS_ENDCAP_SQUARE;
374 xcenter = (right + left) / 2;
375 ycenter = (bottom + top) / 2;
376 start_angle = atan2( (double)(ycenter-ystart)*(right-left),
377 (double)(xstart-xcenter)*(bottom-top) );
378 end_angle = atan2( (double)(ycenter-yend)*(right-left),
379 (double)(xend-xcenter)*(bottom-top) );
380 if ((xstart==xend)&&(ystart==yend))
381 { /* A lazy program delivers xstart=xend=ystart=yend=0) */
385 else /* notorious cases */
386 if ((start_angle == PI)&&( end_angle <0))
389 if ((end_angle == PI)&&( start_angle <0))
391 istart_angle = (INT32)(start_angle * 180 * 64 / PI + 0.5);
392 idiff_angle = (INT32)((end_angle - start_angle) * 180 * 64 / PI + 0.5);
393 if (idiff_angle <= 0) idiff_angle += 360 * 64;
395 /* Fill arc with brush if Chord() or Pie() */
397 if ((lines > 0) && X11DRV_SetupGCForBrush( dc )) {
398 TSXSetArcMode( display, dc->u.x.gc, (lines==1) ? ArcChord : ArcPieSlice);
399 TSXFillArc( display, dc->u.x.drawable, dc->u.x.gc,
400 dc->w.DCOrgX + left, dc->w.DCOrgY + top,
401 right-left-1, bottom-top-1, istart_angle, idiff_angle );
404 /* Draw arc and lines */
406 if (X11DRV_SetupGCForPen( dc )){
407 TSXDrawArc( display, dc->u.x.drawable, dc->u.x.gc,
408 dc->w.DCOrgX + left, dc->w.DCOrgY + top,
409 right-left-1, bottom-top-1, istart_angle, idiff_angle );
411 /* use the truncated values */
412 start_angle=(double)istart_angle*PI/64./180.;
413 end_angle=(double)(istart_angle+idiff_angle)*PI/64./180.;
414 /* calculate the endpoints and round correctly */
415 points[0].x = (int) floor(dc->w.DCOrgX + (right+left)/2.0 +
416 cos(start_angle) * (right-left-width*2+2) / 2. + 0.5);
417 points[0].y = (int) floor(dc->w.DCOrgY + (top+bottom)/2.0 -
418 sin(start_angle) * (bottom-top-width*2+2) / 2. + 0.5);
419 points[1].x = (int) floor(dc->w.DCOrgX + (right+left)/2.0 +
420 cos(end_angle) * (right-left-width*2+2) / 2. + 0.5);
421 points[1].y = (int) floor(dc->w.DCOrgY + (top+bottom)/2.0 -
422 sin(end_angle) * (bottom-top-width*2+2) / 2. + 0.5);
424 /* OK this stuff is optimized for Xfree86
425 * which is probably the most used server by
426 * wine users. Other X servers will not
427 * display correctly. (eXceed for instance)
428 * so if you feel you must change make sure that
429 * you either use Xfree86 or seperate your changes
430 * from these (compile switch or whatever)
434 points[3] = points[1];
435 points[1].x = dc->w.DCOrgX + xcenter;
436 points[1].y = dc->w.DCOrgY + ycenter;
437 points[2] = points[1];
438 dx1=points[1].x-points[0].x;
439 dy1=points[1].y-points[0].y;
440 if(((top-bottom) | -2) == -2)
441 if(dy1>0) points[1].y--;
443 if (((-dx1)*64)<=ABS(dy1)*37) points[0].x--;
444 if(((-dx1*9))<(dy1*16)) points[0].y--;
445 if( dy1<0 && ((dx1*9)) < (dy1*16)) points[0].y--;
447 if(dy1 < 0) points[0].y--;
448 if(((right-left) | -2) == -2) points[1].x--;
450 dx1=points[3].x-points[2].x;
451 dy1=points[3].y-points[2].y;
452 if(((top-bottom) | -2 ) == -2)
453 if(dy1 < 0) points[2].y--;
455 if( dy1>0) points[3].y--;
456 if(((right-left) | -2) == -2 ) points[2].x--;
459 if( dx1 * 64 < dy1 * -37 ) points[3].x--;
463 TSXDrawLines( display, dc->u.x.drawable, dc->u.x.gc,
464 points, lines+1, CoordModeOrigin );
467 dc->u.x.pen.width=oldwidth;
468 dc->u.x.pen.endcap=oldendcap;
473 /***********************************************************************
477 X11DRV_Arc( DC *dc, INT32 left, INT32 top, INT32 right, INT32 bottom,
478 INT32 xstart, INT32 ystart, INT32 xend, INT32 yend )
480 return X11DRV_DrawArc( dc, left, top, right, bottom,
481 xstart, ystart, xend, yend, 0 );
485 /***********************************************************************
489 X11DRV_Pie( DC *dc, INT32 left, INT32 top, INT32 right, INT32 bottom,
490 INT32 xstart, INT32 ystart, INT32 xend, INT32 yend )
492 return X11DRV_DrawArc( dc, left, top, right, bottom,
493 xstart, ystart, xend, yend, 2 );
496 /***********************************************************************
500 X11DRV_Chord( DC *dc, INT32 left, INT32 top, INT32 right, INT32 bottom,
501 INT32 xstart, INT32 ystart, INT32 xend, INT32 yend )
503 return X11DRV_DrawArc( dc, left, top, right, bottom,
504 xstart, ystart, xend, yend, 1 );
508 /***********************************************************************
512 X11DRV_Ellipse( DC *dc, INT32 left, INT32 top, INT32 right, INT32 bottom )
514 INT32 width, oldwidth;
515 left = XLPTODP( dc, left );
516 top = YLPTODP( dc, top );
517 right = XLPTODP( dc, right );
518 bottom = YLPTODP( dc, bottom );
519 if ((left == right) || (top == bottom)) return TRUE;
521 if (right < left) { INT32 tmp = right; right = left; left = tmp; }
522 if (bottom < top) { INT32 tmp = bottom; bottom = top; top = tmp; }
524 oldwidth = width = dc->u.x.pen.width;
525 if (!width) width = 1;
526 if(dc->u.x.pen.style == PS_NULL) width = 0;
528 if ((dc->u.x.pen.style == PS_INSIDEFRAME))
530 if (2*width > (right-left)) width=(right-left + 1)/2;
531 if (2*width > (bottom-top)) width=(bottom-top + 1)/2;
533 right -= (width - 1) / 2;
535 bottom -= (width - 1) / 2;
537 if(width == 0) width=1; /* more accurate */
538 dc->u.x.pen.width=width;
540 if (X11DRV_SetupGCForBrush( dc ))
541 TSXFillArc( display, dc->u.x.drawable, dc->u.x.gc,
542 dc->w.DCOrgX + left, dc->w.DCOrgY + top,
543 right-left-1, bottom-top-1, 0, 360*64 );
544 if (X11DRV_SetupGCForPen( dc ))
545 TSXDrawArc( display, dc->u.x.drawable, dc->u.x.gc,
546 dc->w.DCOrgX + left, dc->w.DCOrgY + top,
547 right-left-1, bottom-top-1, 0, 360*64 );
548 dc->u.x.pen.width=oldwidth;
553 /***********************************************************************
557 X11DRV_Rectangle(DC *dc, INT32 left, INT32 top, INT32 right, INT32 bottom)
559 INT32 width, oldwidth, oldjoinstyle;
561 TRACE(graphics, "(%d %d %d %d)\n",
562 left, top, right, bottom);
564 left = XLPTODP( dc, left );
565 top = YLPTODP( dc, top );
566 right = XLPTODP( dc, right );
567 bottom = YLPTODP( dc, bottom );
569 if ((left == right) || (top == bottom)) return TRUE;
571 if (right < left) { INT32 tmp = right; right = left; left = tmp; }
572 if (bottom < top) { INT32 tmp = bottom; bottom = top; top = tmp; }
574 oldwidth = width = dc->u.x.pen.width;
575 if (!width) width = 1;
576 if(dc->u.x.pen.style == PS_NULL) width = 0;
578 if ((dc->u.x.pen.style == PS_INSIDEFRAME))
580 if (2*width > (right-left)) width=(right-left + 1)/2;
581 if (2*width > (bottom-top)) width=(bottom-top + 1)/2;
583 right -= (width - 1) / 2;
585 bottom -= (width - 1) / 2;
587 if(width == 1) width=0;
588 dc->u.x.pen.width=width;
589 oldjoinstyle=dc->u.x.pen.linejoin;
590 if(dc->u.x.pen.type!=PS_GEOMETRIC)
591 dc->u.x.pen.linejoin=PS_JOIN_MITER;
593 if ((right > left + width) && (bottom > top + width))
595 if (X11DRV_SetupGCForBrush( dc ))
596 TSXFillRectangle( display, dc->u.x.drawable, dc->u.x.gc,
597 dc->w.DCOrgX + left + (width + 1) / 2,
598 dc->w.DCOrgY + top + (width + 1) / 2,
599 right-left-width-1, bottom-top-width-1);
601 if (X11DRV_SetupGCForPen( dc ))
602 TSXDrawRectangle( display, dc->u.x.drawable, dc->u.x.gc,
603 dc->w.DCOrgX + left, dc->w.DCOrgY + top,
604 right-left-1, bottom-top-1 );
606 dc->u.x.pen.width=oldwidth;
607 dc->u.x.pen.linejoin=oldjoinstyle;
611 /***********************************************************************
615 X11DRV_RoundRect( DC *dc, INT32 left, INT32 top, INT32 right,
616 INT32 bottom, INT32 ell_width, INT32 ell_height )
618 INT32 width, oldwidth, oldendcap;
620 TRACE(graphics, "(%d %d %d %d %d %d\n",
621 left, top, right, bottom, ell_width, ell_height);
623 left = XLPTODP( dc, left );
624 top = YLPTODP( dc, top );
625 right = XLPTODP( dc, right );
626 bottom = YLPTODP( dc, bottom );
628 if ((left == right) || (top == bottom))
631 /* Make sure ell_width and ell_height are >= 1 otherwise XDrawArc gets
632 called with width/height < 0 */
633 ell_width = MAX(abs( ell_width * dc->vportExtX / dc->wndExtX ), 1);
634 ell_height = MAX(abs( ell_height * dc->vportExtY / dc->wndExtY ), 1);
636 /* Fix the coordinates */
638 if (right < left) { INT32 tmp = right; right = left; left = tmp; }
639 if (bottom < top) { INT32 tmp = bottom; bottom = top; top = tmp; }
641 oldwidth=width = dc->u.x.pen.width;
642 oldendcap = dc->u.x.pen.endcap;
643 if (!width) width = 1;
644 if(dc->u.x.pen.style == PS_NULL) width = 0;
646 if ((dc->u.x.pen.style == PS_INSIDEFRAME))
648 if (2*width > (right-left)) width=(right-left + 1)/2;
649 if (2*width > (bottom-top)) width=(bottom-top + 1)/2;
651 right -= (width - 1) / 2;
653 bottom -= (width - 1) / 2;
655 if(width == 0) width=1;
656 dc->u.x.pen.width=width;
657 dc->u.x.pen.endcap=PS_ENDCAP_SQUARE;
659 if (X11DRV_SetupGCForBrush( dc ))
661 if (ell_width > (right-left) )
662 if (ell_height > (bottom-top) )
663 TSXFillArc( display, dc->u.x.drawable, dc->u.x.gc,
664 dc->w.DCOrgX + left, dc->w.DCOrgY + top,
665 right - left - 1, bottom - top - 1,
668 TSXFillArc( display, dc->u.x.drawable, dc->u.x.gc,
669 dc->w.DCOrgX + left, dc->w.DCOrgY + top,
670 right - left - 1, ell_height, 0, 180 * 64 );
671 TSXFillArc( display, dc->u.x.drawable, dc->u.x.gc,
673 dc->w.DCOrgY + bottom - ell_height - 1,
674 right - left - 1, ell_height, 180 * 64, 180 * 64 );
676 else if (ell_height > (bottom-top) ){
677 TSXFillArc( display, dc->u.x.drawable, dc->u.x.gc,
678 dc->w.DCOrgX + left, dc->w.DCOrgY + top,
679 ell_width, bottom - top - 1, 90 * 64, 180 * 64 );
680 TSXFillArc( display, dc->u.x.drawable, dc->u.x.gc,
681 dc->w.DCOrgX + right - ell_width -1, dc->w.DCOrgY + top,
682 ell_width, bottom - top - 1, 270 * 64, 180 * 64 );
684 TSXFillArc( display, dc->u.x.drawable, dc->u.x.gc,
685 dc->w.DCOrgX + left, dc->w.DCOrgY + top,
686 ell_width, ell_height, 90 * 64, 90 * 64 );
687 TSXFillArc( display, dc->u.x.drawable, dc->u.x.gc,
689 dc->w.DCOrgY + bottom - ell_height - 1,
690 ell_width, ell_height, 180 * 64, 90 * 64 );
691 TSXFillArc( display, dc->u.x.drawable, dc->u.x.gc,
692 dc->w.DCOrgX + right - ell_width - 1,
693 dc->w.DCOrgY + bottom - ell_height - 1,
694 ell_width, ell_height, 270 * 64, 90 * 64 );
695 TSXFillArc( display, dc->u.x.drawable, dc->u.x.gc,
696 dc->w.DCOrgX + right - ell_width - 1,
698 ell_width, ell_height, 0, 90 * 64 );
700 if (ell_width < right - left)
702 TSXFillRectangle( display, dc->u.x.drawable, dc->u.x.gc,
703 dc->w.DCOrgX + left + (ell_width + 1) / 2,
704 dc->w.DCOrgY + top + 1,
705 right - left - ell_width - 1,
706 (ell_height + 1) / 2 - 1);
707 TSXFillRectangle( display, dc->u.x.drawable, dc->u.x.gc,
708 dc->w.DCOrgX + left + (ell_width + 1) / 2,
709 dc->w.DCOrgY + bottom - (ell_height) / 2 - 1,
710 right - left - ell_width - 1,
713 if (ell_height < bottom - top)
715 TSXFillRectangle( display, dc->u.x.drawable, dc->u.x.gc,
716 dc->w.DCOrgX + left + 1,
717 dc->w.DCOrgY + top + (ell_height + 1) / 2,
719 bottom - top - ell_height - 1);
722 /* FIXME: this could be done with on X call
723 * more efficient and probably more correct
724 * on any X server: XDrawArcs will draw
725 * straight horizontal and vertical lines
726 * if width or height are zero.
728 * BTW this stuff is optimized for an Xfree86 server
729 * read the comments inside the X11DRV_DrawArc function
731 if (X11DRV_SetupGCForPen(dc)) {
732 if (ell_width > (right-left) )
733 if (ell_height > (bottom-top) )
734 TSXDrawArc( display, dc->u.x.drawable, dc->u.x.gc,
735 dc->w.DCOrgX + left, dc->w.DCOrgY + top,
736 right - left - 1, bottom -top - 1, 0 , 360 * 64 );
738 TSXDrawArc( display, dc->u.x.drawable, dc->u.x.gc,
739 dc->w.DCOrgX + left, dc->w.DCOrgY + top,
740 right - left - 1, ell_height - 1, 0 , 180 * 64 );
741 TSXDrawArc( display, dc->u.x.drawable, dc->u.x.gc,
743 dc->w.DCOrgY + bottom - ell_height,
744 right - left - 1, ell_height - 1, 180 * 64 , 180 * 64 );
746 else if (ell_height > (bottom-top) ){
747 TSXDrawArc( display, dc->u.x.drawable, dc->u.x.gc,
748 dc->w.DCOrgX + left, dc->w.DCOrgY + top,
749 ell_width - 1 , bottom - top - 1, 90 * 64 , 180 * 64 );
750 TSXDrawArc( display, dc->u.x.drawable, dc->u.x.gc,
751 dc->w.DCOrgX + right - ell_width,
753 ell_width - 1 , bottom - top - 1, 270 * 64 , 180 * 64 );
755 TSXDrawArc( display, dc->u.x.drawable, dc->u.x.gc,
756 dc->w.DCOrgX + left, dc->w.DCOrgY + top,
757 ell_width - 1, ell_height - 1, 90 * 64, 90 * 64 );
758 TSXDrawArc( display, dc->u.x.drawable, dc->u.x.gc,
759 dc->w.DCOrgX + left, dc->w.DCOrgY + bottom - ell_height,
760 ell_width - 1, ell_height - 1, 180 * 64, 90 * 64 );
761 TSXDrawArc( display, dc->u.x.drawable, dc->u.x.gc,
762 dc->w.DCOrgX + right - ell_width,
763 dc->w.DCOrgY + bottom - ell_height,
764 ell_width - 1, ell_height - 1, 270 * 64, 90 * 64 );
765 TSXDrawArc( display, dc->u.x.drawable, dc->u.x.gc,
766 dc->w.DCOrgX + right - ell_width, dc->w.DCOrgY + top,
767 ell_width - 1, ell_height - 1, 0, 90 * 64 );
769 if (ell_width < right - left)
771 TSXDrawLine( display, dc->u.x.drawable, dc->u.x.gc,
772 dc->w.DCOrgX + left + ell_width / 2,
774 dc->w.DCOrgX + right - (ell_width+1) / 2,
776 TSXDrawLine( display, dc->u.x.drawable, dc->u.x.gc,
777 dc->w.DCOrgX + left + ell_width / 2 ,
778 dc->w.DCOrgY + bottom - 1,
779 dc->w.DCOrgX + right - (ell_width+1)/ 2,
780 dc->w.DCOrgY + bottom - 1);
782 if (ell_height < bottom - top)
784 TSXDrawLine( display, dc->u.x.drawable, dc->u.x.gc,
785 dc->w.DCOrgX + right - 1,
786 dc->w.DCOrgY + top + ell_height / 2,
787 dc->w.DCOrgX + right - 1,
788 dc->w.DCOrgY + bottom - (ell_height+1) / 2);
789 TSXDrawLine( display, dc->u.x.drawable, dc->u.x.gc,
791 dc->w.DCOrgY + top + ell_height / 2,
793 dc->w.DCOrgY + bottom - (ell_height+1) / 2);
796 dc->u.x.pen.width=oldwidth;
797 dc->u.x.pen.endcap=oldendcap;
802 /***********************************************************************
806 X11DRV_SetPixel( DC *dc, INT32 x, INT32 y, COLORREF color )
810 x = dc->w.DCOrgX + XLPTODP( dc, x );
811 y = dc->w.DCOrgY + YLPTODP( dc, y );
812 pixel = COLOR_ToPhysical( dc, color );
814 TSXSetForeground( display, dc->u.x.gc, pixel );
815 TSXSetFunction( display, dc->u.x.gc, GXcopy );
816 TSXDrawPoint( display, dc->u.x.drawable, dc->u.x.gc, x, y );
818 /* inefficient but simple... */
820 return COLOR_ToLogical(pixel);
824 /***********************************************************************
828 X11DRV_GetPixel( DC *dc, INT32 x, INT32 y )
830 static Pixmap pixmap = 0;
834 x = dc->w.DCOrgX + XLPTODP( dc, x );
835 y = dc->w.DCOrgY + YLPTODP( dc, y );
836 EnterCriticalSection( &X11DRV_CritSection );
837 if (dc->w.flags & DC_MEMORY)
839 image = XGetImage( display, dc->u.x.drawable, x, y, 1, 1,
840 AllPlanes, ZPixmap );
844 /* If we are reading from the screen, use a temporary copy */
845 /* to avoid a BadMatch error */
846 if (!pixmap) pixmap = XCreatePixmap( display, rootWindow,
847 1, 1, dc->w.bitsPerPixel );
848 XCopyArea( display, dc->u.x.drawable, pixmap, BITMAP_colorGC,
850 image = XGetImage( display, pixmap, 0, 0, 1, 1, AllPlanes, ZPixmap );
852 pixel = XGetPixel( image, 0, 0 );
853 XDestroyImage( image );
854 LeaveCriticalSection( &X11DRV_CritSection );
856 return COLOR_ToLogical(pixel);
860 /***********************************************************************
864 X11DRV_PaintRgn( DC *dc, HRGN32 hrgn )
867 HRGN32 tmpVisRgn, prevVisRgn;
868 HDC32 hdc = dc->hSelf; /* FIXME: should not mix dc/hdc this way */
870 if (!(tmpVisRgn = CreateRectRgn32( 0, 0, 0, 0 ))) return FALSE;
872 /* Transform region into device co-ords */
873 if ( !REGION_LPTODP( hdc, tmpVisRgn, hrgn )
874 || OffsetRgn32( tmpVisRgn, dc->w.DCOrgX, dc->w.DCOrgY ) == ERROR) {
875 DeleteObject32( tmpVisRgn );
879 /* Modify visible region */
880 if (!(prevVisRgn = SaveVisRgn( hdc ))) {
881 DeleteObject32( tmpVisRgn );
884 CombineRgn32( tmpVisRgn, prevVisRgn, tmpVisRgn, RGN_AND );
885 SelectVisRgn( hdc, tmpVisRgn );
886 DeleteObject32( tmpVisRgn );
888 /* Fill the region */
890 GetRgnBox32( dc->w.hGCClipRgn, &box );
891 if (X11DRV_SetupGCForBrush( dc ))
892 TSXFillRectangle( display, dc->u.x.drawable, dc->u.x.gc,
894 box.right-box.left, box.bottom-box.top );
896 /* Restore the visible region */
898 RestoreVisRgn( hdc );
902 /**********************************************************************
906 X11DRV_Polyline( DC *dc, const POINT32* pt, INT32 count )
911 if((oldwidth=dc->u.x.pen.width)==0) dc->u.x.pen.width=1;
913 points = (XPoint *) xmalloc (sizeof (XPoint) * (count));
914 for (i = 0; i < count; i++)
916 points[i].x = dc->w.DCOrgX + XLPTODP( dc, pt[i].x );
917 points[i].y = dc->w.DCOrgY + YLPTODP( dc, pt[i].y );
920 if (X11DRV_SetupGCForPen ( dc ))
921 TSXDrawLines( display, dc->u.x.drawable, dc->u.x.gc,
922 points, count, CoordModeOrigin );
925 dc->u.x.pen.width=oldwidth;
930 /**********************************************************************
934 X11DRV_Polygon( DC *dc, const POINT32* pt, INT32 count )
939 points = (XPoint *) xmalloc (sizeof (XPoint) * (count+1));
940 for (i = 0; i < count; i++)
942 points[i].x = dc->w.DCOrgX + XLPTODP( dc, pt[i].x );
943 points[i].y = dc->w.DCOrgY + YLPTODP( dc, pt[i].y );
945 points[count] = points[0];
947 if (X11DRV_SetupGCForBrush( dc ))
948 TSXFillPolygon( display, dc->u.x.drawable, dc->u.x.gc,
949 points, count+1, Complex, CoordModeOrigin);
951 if (X11DRV_SetupGCForPen ( dc ))
952 TSXDrawLines( display, dc->u.x.drawable, dc->u.x.gc,
953 points, count+1, CoordModeOrigin );
960 /**********************************************************************
964 X11DRV_PolyPolygon( DC *dc, const POINT32* pt, const INT32* counts, UINT32 polygons)
968 /* FIXME: The points should be converted to device coords before */
969 /* creating the region. But as CreatePolyPolygonRgn is not */
970 /* really correct either, it doesn't matter much... */
971 /* At least the outline will be correct :-) */
972 hrgn = CreatePolyPolygonRgn32( pt, counts, polygons, dc->w.polyFillMode );
973 X11DRV_PaintRgn( dc, hrgn );
974 DeleteObject32( hrgn );
976 /* Draw the outline of the polygons */
978 if (X11DRV_SetupGCForPen ( dc ))
983 for (i = 0; i < polygons; i++) if (counts[i] > max) max = counts[i];
984 points = (XPoint *) xmalloc( sizeof(XPoint) * (max+1) );
986 for (i = 0; i < polygons; i++)
988 for (j = 0; j < counts[i]; j++)
990 points[j].x = dc->w.DCOrgX + XLPTODP( dc, pt->x );
991 points[j].y = dc->w.DCOrgY + YLPTODP( dc, pt->y );
994 points[j] = points[0];
995 TSXDrawLines( display, dc->u.x.drawable, dc->u.x.gc,
996 points, j + 1, CoordModeOrigin );
1004 /**********************************************************************
1005 * X11DRV_PolyPolyline
1008 X11DRV_PolyPolyline( DC *dc, const POINT32* pt, const DWORD* counts, DWORD polylines )
1010 if (X11DRV_SetupGCForPen ( dc ))
1015 for (i = 0; i < polylines; i++) if (counts[i] > max) max = counts[i];
1016 points = (XPoint *) xmalloc( sizeof(XPoint) * (max+1) );
1018 for (i = 0; i < polylines; i++)
1020 for (j = 0; j < counts[i]; j++)
1022 points[j].x = dc->w.DCOrgX + XLPTODP( dc, pt->x );
1023 points[j].y = dc->w.DCOrgY + YLPTODP( dc, pt->y );
1026 points[j] = points[0];
1027 TSXDrawLines( display, dc->u.x.drawable, dc->u.x.gc,
1028 points, j + 1, CoordModeOrigin );
1036 /**********************************************************************
1037 * X11DRV_InternalFloodFill
1039 * Internal helper function for flood fill.
1040 * (xorg,yorg) is the origin of the X image relative to the drawable.
1041 * (x,y) is relative to the origin of the X image.
1043 static void X11DRV_InternalFloodFill(XImage *image, DC *dc,
1046 Pixel pixel, WORD fillType )
1050 #define TO_FLOOD(x,y) ((fillType == FLOODFILLBORDER) ? \
1051 (XGetPixel(image,x,y) != pixel) : \
1052 (XGetPixel(image,x,y) == pixel))
1054 if (!TO_FLOOD(x,y)) return;
1056 /* Find left and right boundaries */
1059 while ((left > 0) && TO_FLOOD( left-1, y )) left--;
1060 while ((right < image->width) && TO_FLOOD( right, y )) right++;
1061 XFillRectangle( display, dc->u.x.drawable, dc->u.x.gc,
1062 xOrg + left, yOrg + y, right-left, 1 );
1064 /* Set the pixels of this line so we don't fill it again */
1066 for (x = left; x < right; x++)
1068 if (fillType == FLOODFILLBORDER) XPutPixel( image, x, y, pixel );
1069 else XPutPixel( image, x, y, ~pixel );
1072 /* Fill the line above */
1079 while ((x < right) && !TO_FLOOD(x,y)) x++;
1080 if (x >= right) break;
1081 while ((x < right) && TO_FLOOD(x,y)) x++;
1082 X11DRV_InternalFloodFill(image, dc, x-1, y,
1083 xOrg, yOrg, pixel, fillType );
1087 /* Fill the line below */
1089 if ((y += 2) < image->height)
1094 while ((x < right) && !TO_FLOOD(x,y)) x++;
1095 if (x >= right) break;
1096 while ((x < right) && TO_FLOOD(x,y)) x++;
1097 X11DRV_InternalFloodFill(image, dc, x-1, y,
1098 xOrg, yOrg, pixel, fillType );
1105 /**********************************************************************
1106 * X11DRV_DoFloodFill
1108 * Main flood-fill routine.
1110 * The Xlib critical section must be entered before calling this function.
1113 struct FloodFill_params
1122 static BOOL32 X11DRV_DoFloodFill( const struct FloodFill_params *params )
1126 DC *dc = params->dc;
1128 if (GetRgnBox32( dc->w.hGCClipRgn, &rect ) == ERROR) return FALSE;
1130 if (!(image = XGetImage( display, dc->u.x.drawable,
1133 rect.right - rect.left,
1134 rect.bottom - rect.top,
1135 AllPlanes, ZPixmap ))) return FALSE;
1137 if (X11DRV_SetupGCForBrush( dc ))
1139 /* ROP mode is always GXcopy for flood-fill */
1140 XSetFunction( display, dc->u.x.gc, GXcopy );
1141 X11DRV_InternalFloodFill(image, dc,
1142 XLPTODP(dc,params->x) + dc->w.DCOrgX - rect.left,
1143 YLPTODP(dc,params->y) + dc->w.DCOrgY - rect.top,
1146 COLOR_ToPhysical( dc, params->color ),
1150 XDestroyImage( image );
1155 /**********************************************************************
1156 * X11DRV_ExtFloodFill
1159 X11DRV_ExtFloodFill( DC *dc, INT32 x, INT32 y, COLORREF color,
1163 struct FloodFill_params params = { dc, x, y, color, fillType };
1165 TRACE(graphics, "X11DRV_ExtFloodFill %d,%d %06lx %d\n",
1166 x, y, color, fillType );
1168 if (!PtVisible32( dc->hSelf, x, y )) return FALSE;
1169 EnterCriticalSection( &X11DRV_CritSection );
1170 result = CALL_LARGE_STACK( X11DRV_DoFloodFill, ¶ms );
1171 LeaveCriticalSection( &X11DRV_CritSection );
1175 /******************************************************************
1177 * *Very* simple bezier drawing code,
1179 * It uses a recursive algorithm to divide the curve in a series
1180 * of straight line segements. Not ideal but for me sufficient.
1181 * If you are in need for something better look for some incremental
1184 * 7 July 1998 Rein Klazes
1188 * some macro definitions for bezier drawing
1190 * to avoid trucation errors the coordinates are
1191 * shifted upwards. When used in drawing they are
1192 * shifted down again, including correct rounding
1193 * and avoiding floating point arithmatic
1194 * 4 bits should allow 27 bits coordinates which I saw
1195 * somewere in the win32 doc's
1199 #define BEZIERSHIFTBITS 4
1200 #define BEZIERSHIFTUP(x) ((x)<<BEZIERSHIFTBITS)
1201 #define BEZIERPIXEL BEZIERSHIFTUP(1)
1202 #define BEZIERSHIFTDOWN(x) (((x)+(1<<(BEZIERSHIFTBITS-1)))>>BEZIERSHIFTBITS)
1203 /* maximum depth of recursion */
1204 #define BEZIERMAXDEPTH 8
1206 /* size of array to store points on */
1207 /* enough for one curve */
1208 #define BEZMAXPOINTS (150)
1210 /* calculate Bezier average, in this case the middle
1211 * correctly rounded...
1214 #define BEZIERMIDDLE(Mid, P1, P2) \
1215 (Mid).x=((P1).x+(P2).x + 1)/2;\
1216 (Mid).y=((P1).y+(P2).y + 1)/2;
1218 /**********************************************************
1219 * BezierCheck helper function to check
1220 * that recursion can be terminated
1221 * Points[0] and Points[3] are begin and endpoint
1222 * Points[1] and Points[2] are control points
1223 * level is the recursion depth
1224 * returns true if the recusion can be terminated
1226 static BOOL32 BezierCheck( int level, POINT32 *Points)
1229 dx=Points[3].x-Points[0].x;
1230 dy=Points[3].y-Points[0].y;
1231 if(ABS(dy)<=ABS(dx)){/* shallow line */
1232 /* check that control points are between begin and end */
1233 if(Points[1].x < Points[0].x){
1234 if(Points[1].x < Points[3].x)
1237 if(Points[1].x > Points[3].x)
1239 if(Points[2].x < Points[0].x){
1240 if(Points[2].x < Points[3].x)
1243 if(Points[2].x > Points[3].x)
1245 dx=BEZIERSHIFTDOWN(dx);
1246 if(!dx) return TRUE;
1247 if(abs(Points[1].y-Points[0].y-(dy/dx)*
1248 BEZIERSHIFTDOWN(Points[1].x-Points[0].x)) > BEZIERPIXEL ||
1249 abs(Points[2].y-Points[0].y-(dy/dx)*
1250 BEZIERSHIFTDOWN(Points[2].x-Points[0].x)) > BEZIERPIXEL )
1254 }else{ /* steep line */
1255 /* check that control points are between begin and end */
1256 if(Points[1].y < Points[0].y){
1257 if(Points[1].y < Points[3].y)
1260 if(Points[1].y > Points[3].y)
1262 if(Points[2].y < Points[0].y){
1263 if(Points[2].y < Points[3].y)
1266 if(Points[2].y > Points[3].y)
1268 dy=BEZIERSHIFTDOWN(dy);
1269 if(!dy) return TRUE;
1270 if(abs(Points[1].x-Points[0].x-(dx/dy)*
1271 BEZIERSHIFTDOWN(Points[1].y-Points[0].y)) > BEZIERPIXEL ||
1272 abs(Points[2].x-Points[0].x-(dx/dy)*
1273 BEZIERSHIFTDOWN(Points[2].y-Points[0].y)) > BEZIERPIXEL )
1280 /***********************************************************************
1282 * Draw a -what microsoft calls- bezier curve
1283 * The routine recursively devides the curve
1284 * in two parts until a straight line can be drawn
1286 * level recusion depth counted backwards
1288 * Points array of begin(0), end(3) and control points(1 and 2)
1289 * XPoints array with points calculated sofar
1290 * *pIx nr points calculated sofar
1293 static void X11DRV_Bezier(int level, DC * dc, POINT32 *Points,
1294 XPoint* xpoints, unsigned int* pIx)
1296 if(*pIx == BEZMAXPOINTS){
1297 TSXDrawLines( display, dc->u.x.drawable, dc->u.x.gc,
1298 xpoints, *pIx, CoordModeOrigin );
1301 if(!level || BezierCheck(level, Points)) {
1303 xpoints[*pIx].x= dc->w.DCOrgX + BEZIERSHIFTDOWN(Points[0].x);
1304 xpoints[*pIx].y= dc->w.DCOrgY + BEZIERSHIFTDOWN(Points[0].y);
1307 xpoints[*pIx].x= dc->w.DCOrgX + BEZIERSHIFTDOWN(Points[3].x);
1308 xpoints[*pIx].y= dc->w.DCOrgY + BEZIERSHIFTDOWN(Points[3].y);
1311 POINT32 Points2[4]; /* for the second recursive call */
1312 Points2[3]=Points[3];
1313 BEZIERMIDDLE(Points2[2], Points[2], Points[3]);
1314 BEZIERMIDDLE(Points2[0], Points[1], Points[2]);
1315 BEZIERMIDDLE(Points2[1],Points2[0],Points2[2]);
1317 BEZIERMIDDLE(Points[1], Points[0], Points[1]);
1318 BEZIERMIDDLE(Points[2], Points[1], Points2[0]);
1319 BEZIERMIDDLE(Points[3], Points[2], Points2[1]);
1321 Points2[0]=Points[3];
1323 /* do the two halves */
1324 X11DRV_Bezier(level-1, dc, Points, xpoints, pIx);
1325 X11DRV_Bezier(level-1, dc, Points2, xpoints, pIx);
1329 /***********************************************************************
1331 * Implement functionality for PolyBezier and PolyBezierTo
1333 * [i] dc pointer to device context
1334 * [i] start, first point in curve
1335 * [i] BezierPoints , array of point filled with rest of the points
1336 * [i] count, number of points in BezierPoints, must be a
1340 X11DRV_PolyBezier(DC *dc, POINT32 start, const POINT32* BezierPoints, DWORD count)
1346 TRACE(graphics, "dc=%04x count=%ld %d,%d - %d,%d - %d,%d -%d,%d \n",
1349 (Points+0)->x, (Points+0)->y,
1350 (Points+1)->x, (Points+1)->y,
1351 (Points+2)->x, (Points+2)->y);
1352 if(!count || count % 3){/* paranoid */
1353 WARN(graphics," bad value for count : %ld\n", count);
1356 xpoints=(XPoint*) xmalloc( sizeof(XPoint)*BEZMAXPOINTS);
1357 Points[3].x=BEZIERSHIFTUP(XLPTODP(dc,start.x));
1358 Points[3].y=BEZIERSHIFTUP(YLPTODP(dc,start.y));
1360 Points[0]=Points[3];
1362 Points[i].x= BEZIERSHIFTUP(XLPTODP(dc,BezierPoints->x));
1363 Points[i].y= BEZIERSHIFTUP(YLPTODP(dc,BezierPoints->y));
1366 X11DRV_Bezier(BEZIERMAXDEPTH , dc, Points, xpoints, &ix );
1369 if( ix) TSXDrawLines( display, dc->u.x.drawable, dc->u.x.gc,
1370 xpoints, ix, CoordModeOrigin );
1375 /**********************************************************************
1379 X11DRV_SetBkColor( DC *dc, COLORREF color )
1381 X11DRV_PDEVICE *physDev = (X11DRV_PDEVICE *)dc->physDev;
1384 oldColor = dc->w.backgroundColor;
1385 dc->w.backgroundColor = color;
1387 physDev->backgroundPixel = COLOR_ToPhysical( dc, color );
1392 /**********************************************************************
1393 * X11DRV_SetTextColor
1396 X11DRV_SetTextColor( DC *dc, COLORREF color )
1398 X11DRV_PDEVICE *physDev = (X11DRV_PDEVICE *)dc->physDev;
1401 oldColor = dc->w.textColor;
1402 dc->w.textColor = color;
1404 physDev->textPixel = COLOR_ToPhysical( dc, color );