2 * X11 graphics driver graphics functions
4 * Copyright 1993,1994 Alexandre Julliard
8 * FIXME: none of these functions obey the GM_ADVANCED
14 #ifndef X_DISPLAY_MISSING
16 #include <X11/Intrinsic.h>
46 #define ABS(x) ((x)<0?(-(x)):(x))
48 /* ROP code to GC function conversion */
49 const int X11DRV_XROPfunction[16] =
51 GXclear, /* R2_BLACK */
52 GXnor, /* R2_NOTMERGEPEN */
53 GXandInverted, /* R2_MASKNOTPEN */
54 GXcopyInverted, /* R2_NOTCOPYPEN */
55 GXandReverse, /* R2_MASKPENNOT */
56 GXinvert, /* R2_NOT */
57 GXxor, /* R2_XORPEN */
58 GXnand, /* R2_NOTMASKPEN */
59 GXand, /* R2_MASKPEN */
60 GXequiv, /* R2_NOTXORPEN */
62 GXorInverted, /* R2_MERGENOTPEN */
63 GXcopy, /* R2_COPYPEN */
64 GXorReverse, /* R2_MERGEPENNOT */
65 GXor, /* R2_MERGEPEN */
70 /***********************************************************************
71 * X11DRV_SetupGCForPatBlt
73 * Setup the GC for a PatBlt operation using current brush.
74 * If fMapColors is TRUE, X pixels are mapped to Windows colors.
75 * Return FALSE if brush is BS_NULL, TRUE otherwise.
77 BOOL X11DRV_SetupGCForPatBlt( DC * dc, GC gc, BOOL fMapColors )
82 X11DRV_PDEVICE *physDev = (X11DRV_PDEVICE *)dc->physDev;
84 if (physDev->brush.style == BS_NULL) return FALSE;
85 if (physDev->brush.pixel == -1)
87 /* Special case used for monochrome pattern brushes.
88 * We need to swap foreground and background because
89 * Windows does it the wrong way...
91 val.foreground = physDev->backgroundPixel;
92 val.background = physDev->textPixel;
96 val.foreground = physDev->brush.pixel;
97 val.background = physDev->backgroundPixel;
99 if (fMapColors && COLOR_PixelToPalette)
101 val.foreground = COLOR_PixelToPalette[val.foreground];
102 val.background = COLOR_PixelToPalette[val.background];
105 if (dc->w.flags & DC_DIRTY) CLIPPING_UpdateGCRegion(dc);
107 val.function = X11DRV_XROPfunction[dc->w.ROPmode-1];
109 ** Let's replace GXinvert by GXxor with (black xor white)
110 ** This solves the selection color and leak problems in excel
111 ** FIXME : Let's do that only if we work with X-pixels, not with Win-pixels
113 if (val.function == GXinvert)
115 val.foreground = BlackPixelOfScreen(X11DRV_GetXScreen()) ^ WhitePixelOfScreen(X11DRV_GetXScreen());
116 val.function = GXxor;
118 val.fill_style = physDev->brush.fillStyle;
119 switch(val.fill_style)
122 case FillOpaqueStippled:
123 if (dc->w.backgroundMode==OPAQUE) val.fill_style = FillOpaqueStippled;
124 val.stipple = physDev->brush.pixmap;
129 if (fMapColors && COLOR_PixelToPalette)
133 EnterCriticalSection( &X11DRV_CritSection );
134 pixmap = XCreatePixmap( display,
135 X11DRV_GetXRootWindow(),
137 MONITOR_GetDepth(&MONITOR_PrimaryMonitor) );
138 image = XGetImage( display, physDev->brush.pixmap, 0, 0, 8, 8,
139 AllPlanes, ZPixmap );
140 for (y = 0; y < 8; y++)
141 for (x = 0; x < 8; x++)
142 XPutPixel( image, x, y,
143 COLOR_PixelToPalette[XGetPixel( image, x, y)] );
144 XPutImage( display, pixmap, gc, image, 0, 0, 0, 0, 8, 8 );
145 XDestroyImage( image );
146 LeaveCriticalSection( &X11DRV_CritSection );
149 else val.tile = physDev->brush.pixmap;
157 val.ts_x_origin = dc->w.DCOrgX + dc->w.brushOrgX;
158 val.ts_y_origin = dc->w.DCOrgY + dc->w.brushOrgY;
159 val.fill_rule = (dc->w.polyFillMode==WINDING) ? WindingRule : EvenOddRule;
160 TSXChangeGC( display, gc,
161 GCFunction | GCForeground | GCBackground | GCFillStyle |
162 GCFillRule | GCTileStipXOrigin | GCTileStipYOrigin | mask,
164 if (pixmap) TSXFreePixmap( display, pixmap );
169 /***********************************************************************
170 * X11DRV_SetupGCForBrush
172 * Setup physDev->gc for drawing operations using current brush.
173 * Return FALSE if brush is BS_NULL, TRUE otherwise.
175 BOOL X11DRV_SetupGCForBrush( DC * dc )
177 X11DRV_PDEVICE *physDev = (X11DRV_PDEVICE *)dc->physDev;
178 return X11DRV_SetupGCForPatBlt( dc, physDev->gc, FALSE );
182 /***********************************************************************
183 * X11DRV_SetupGCForPen
185 * Setup physDev->gc for drawing operations using current pen.
186 * Return FALSE if pen is PS_NULL, TRUE otherwise.
188 BOOL X11DRV_SetupGCForPen( DC * dc )
191 X11DRV_PDEVICE *physDev = (X11DRV_PDEVICE *)dc->physDev;
193 if (physDev->pen.style == PS_NULL) return FALSE;
195 if (dc->w.flags & DC_DIRTY) CLIPPING_UpdateGCRegion(dc);
197 switch (dc->w.ROPmode)
200 val.foreground = BlackPixelOfScreen( X11DRV_GetXScreen() );
201 val.function = GXcopy;
204 val.foreground = WhitePixelOfScreen( X11DRV_GetXScreen() );
205 val.function = GXcopy;
208 val.foreground = physDev->pen.pixel;
209 /* It is very unlikely someone wants to XOR with 0 */
210 /* This fixes the rubber-drawings in paintbrush */
211 if (val.foreground == 0)
212 val.foreground = BlackPixelOfScreen( X11DRV_GetXScreen() )
213 ^ WhitePixelOfScreen( X11DRV_GetXScreen() );
214 val.function = GXxor;
217 val.foreground = physDev->pen.pixel;
218 val.function = X11DRV_XROPfunction[dc->w.ROPmode-1];
220 val.background = physDev->backgroundPixel;
221 val.fill_style = FillSolid;
222 if ((physDev->pen.style!=PS_SOLID) && (physDev->pen.style!=PS_INSIDEFRAME))
224 TSXSetDashes( display, physDev->gc, 0, physDev->pen.dashes,
225 physDev->pen.dash_len );
226 val.line_style = (dc->w.backgroundMode == OPAQUE) ?
227 LineDoubleDash : LineOnOffDash;
229 else val.line_style = LineSolid;
230 val.line_width = physDev->pen.width;
231 if (val.line_width <= 1) {
232 val.cap_style = CapNotLast;
234 switch (physDev->pen.endcap)
236 case PS_ENDCAP_SQUARE:
237 val.cap_style = CapProjecting;
240 val.cap_style = CapButt;
242 case PS_ENDCAP_ROUND:
244 val.cap_style = CapRound;
247 switch (physDev->pen.linejoin)
250 val.join_style = JoinBevel;
253 val.join_style = JoinMiter;
257 val.join_style = JoinRound;
259 TSXChangeGC( display, physDev->gc,
260 GCFunction | GCForeground | GCBackground | GCLineWidth |
261 GCLineStyle | GCCapStyle | GCJoinStyle | GCFillStyle, &val );
266 /***********************************************************************
267 * X11DRV_SetupGCForText
269 * Setup physDev->gc for text drawing operations.
270 * Return FALSE if the font is null, TRUE otherwise.
272 BOOL X11DRV_SetupGCForText( DC * dc )
274 X11DRV_PDEVICE *physDev = (X11DRV_PDEVICE *)dc->physDev;
275 XFontStruct* xfs = XFONT_GetFontStruct( physDev->font );
281 if (dc->w.flags & DC_DIRTY) CLIPPING_UpdateGCRegion(dc);
283 val.function = GXcopy; /* Text is always GXcopy */
284 val.foreground = physDev->textPixel;
285 val.background = physDev->backgroundPixel;
286 val.fill_style = FillSolid;
289 TSXChangeGC( display, physDev->gc,
290 GCFunction | GCForeground | GCBackground | GCFillStyle |
294 WARN(dc, "Physical font failure\n" );
299 /**********************************************************************
303 X11DRV_MoveToEx(DC *dc,INT x,INT y,LPPOINT pt) {
306 pt->x = dc->w.CursPosX;
307 pt->y = dc->w.CursPosY;
314 /***********************************************************************
318 X11DRV_LineTo( DC *dc, INT x, INT y )
320 X11DRV_PDEVICE *physDev = (X11DRV_PDEVICE *)dc->physDev;
322 if (X11DRV_SetupGCForPen( dc ))
323 TSXDrawLine(display, physDev->drawable, physDev->gc,
324 dc->w.DCOrgX + XLPTODP( dc, dc->w.CursPosX ),
325 dc->w.DCOrgY + YLPTODP( dc, dc->w.CursPosY ),
326 dc->w.DCOrgX + XLPTODP( dc, x ),
327 dc->w.DCOrgY + YLPTODP( dc, y ) );
335 /***********************************************************************
338 * Helper functions for Arc(), Chord() and Pie().
339 * 'lines' is the number of lines to draw: 0 for Arc, 1 for Chord, 2 for Pie.
343 X11DRV_DrawArc( DC *dc, INT left, INT top, INT right,
344 INT bottom, INT xstart, INT ystart,
345 INT xend, INT yend, INT lines )
347 INT xcenter, ycenter, istart_angle, idiff_angle;
348 INT width, oldwidth, oldendcap;
349 double start_angle, end_angle;
351 X11DRV_PDEVICE *physDev = (X11DRV_PDEVICE *)dc->physDev;
353 left = XLPTODP( dc, left );
354 top = YLPTODP( dc, top );
355 right = XLPTODP( dc, right );
356 bottom = YLPTODP( dc, bottom );
357 xstart = XLPTODP( dc, xstart );
358 ystart = YLPTODP( dc, ystart );
359 xend = XLPTODP( dc, xend );
360 yend = YLPTODP( dc, yend );
362 if (right < left) { INT tmp = right; right = left; left = tmp; }
363 if (bottom < top) { INT tmp = bottom; bottom = top; top = tmp; }
364 if ((left == right) || (top == bottom)
365 ||(lines && ((right-left==1)||(bottom-top==1)))) return TRUE;
367 oldwidth = width = physDev->pen.width;
368 oldendcap = physDev->pen.endcap;
369 if (!width) width = 1;
370 if(physDev->pen.style == PS_NULL) width = 0;
372 if ((physDev->pen.style == PS_INSIDEFRAME))
374 if (2*width > (right-left)) width=(right-left + 1)/2;
375 if (2*width > (bottom-top)) width=(bottom-top + 1)/2;
377 right -= (width - 1) / 2;
379 bottom -= (width - 1) / 2;
381 if(width == 0) width = 1; /* more accurate */
382 physDev->pen.width = width;
383 physDev->pen.endcap = PS_ENDCAP_SQUARE;
385 xcenter = (right + left) / 2;
386 ycenter = (bottom + top) / 2;
387 start_angle = atan2( (double)(ycenter-ystart)*(right-left),
388 (double)(xstart-xcenter)*(bottom-top) );
389 end_angle = atan2( (double)(ycenter-yend)*(right-left),
390 (double)(xend-xcenter)*(bottom-top) );
391 if ((xstart==xend)&&(ystart==yend))
392 { /* A lazy program delivers xstart=xend=ystart=yend=0) */
396 else /* notorious cases */
397 if ((start_angle == PI)&&( end_angle <0))
400 if ((end_angle == PI)&&( start_angle <0))
402 istart_angle = (INT)(start_angle * 180 * 64 / PI + 0.5);
403 idiff_angle = (INT)((end_angle - start_angle) * 180 * 64 / PI + 0.5);
404 if (idiff_angle <= 0) idiff_angle += 360 * 64;
406 /* Fill arc with brush if Chord() or Pie() */
408 if ((lines > 0) && X11DRV_SetupGCForBrush( dc )) {
409 TSXSetArcMode( display, physDev->gc,
410 (lines==1) ? ArcChord : ArcPieSlice);
411 TSXFillArc( display, physDev->drawable, physDev->gc,
412 dc->w.DCOrgX + left, dc->w.DCOrgY + top,
413 right-left-1, bottom-top-1, istart_angle, idiff_angle );
416 /* Draw arc and lines */
418 if (X11DRV_SetupGCForPen( dc )){
419 TSXDrawArc( display, physDev->drawable, physDev->gc,
420 dc->w.DCOrgX + left, dc->w.DCOrgY + top,
421 right-left-1, bottom-top-1, istart_angle, idiff_angle );
423 /* use the truncated values */
424 start_angle=(double)istart_angle*PI/64./180.;
425 end_angle=(double)(istart_angle+idiff_angle)*PI/64./180.;
426 /* calculate the endpoints and round correctly */
427 points[0].x = (int) floor(dc->w.DCOrgX + (right+left)/2.0 +
428 cos(start_angle) * (right-left-width*2+2) / 2. + 0.5);
429 points[0].y = (int) floor(dc->w.DCOrgY + (top+bottom)/2.0 -
430 sin(start_angle) * (bottom-top-width*2+2) / 2. + 0.5);
431 points[1].x = (int) floor(dc->w.DCOrgX + (right+left)/2.0 +
432 cos(end_angle) * (right-left-width*2+2) / 2. + 0.5);
433 points[1].y = (int) floor(dc->w.DCOrgY + (top+bottom)/2.0 -
434 sin(end_angle) * (bottom-top-width*2+2) / 2. + 0.5);
436 /* OK this stuff is optimized for Xfree86
437 * which is probably the most used server by
438 * wine users. Other X servers will not
439 * display correctly. (eXceed for instance)
440 * so if you feel you must change make sure that
441 * you either use Xfree86 or seperate your changes
442 * from these (compile switch or whatever)
446 points[3] = points[1];
447 points[1].x = dc->w.DCOrgX + xcenter;
448 points[1].y = dc->w.DCOrgY + ycenter;
449 points[2] = points[1];
450 dx1=points[1].x-points[0].x;
451 dy1=points[1].y-points[0].y;
452 if(((top-bottom) | -2) == -2)
453 if(dy1>0) points[1].y--;
455 if (((-dx1)*64)<=ABS(dy1)*37) points[0].x--;
456 if(((-dx1*9))<(dy1*16)) points[0].y--;
457 if( dy1<0 && ((dx1*9)) < (dy1*16)) points[0].y--;
459 if(dy1 < 0) points[0].y--;
460 if(((right-left) | -2) == -2) points[1].x--;
462 dx1=points[3].x-points[2].x;
463 dy1=points[3].y-points[2].y;
464 if(((top-bottom) | -2 ) == -2)
465 if(dy1 < 0) points[2].y--;
467 if( dy1>0) points[3].y--;
468 if(((right-left) | -2) == -2 ) points[2].x--;
471 if( dx1 * 64 < dy1 * -37 ) points[3].x--;
475 TSXDrawLines( display, physDev->drawable, physDev->gc,
476 points, lines+1, CoordModeOrigin );
479 physDev->pen.width = oldwidth;
480 physDev->pen.endcap = oldendcap;
485 /***********************************************************************
489 X11DRV_Arc( DC *dc, INT left, INT top, INT right, INT bottom,
490 INT xstart, INT ystart, INT xend, INT yend )
492 return X11DRV_DrawArc( dc, left, top, right, bottom,
493 xstart, ystart, xend, yend, 0 );
497 /***********************************************************************
501 X11DRV_Pie( DC *dc, INT left, INT top, INT right, INT bottom,
502 INT xstart, INT ystart, INT xend, INT yend )
504 return X11DRV_DrawArc( dc, left, top, right, bottom,
505 xstart, ystart, xend, yend, 2 );
508 /***********************************************************************
512 X11DRV_Chord( DC *dc, INT left, INT top, INT right, INT bottom,
513 INT xstart, INT ystart, INT xend, INT yend )
515 return X11DRV_DrawArc( dc, left, top, right, bottom,
516 xstart, ystart, xend, yend, 1 );
520 /***********************************************************************
524 X11DRV_Ellipse( DC *dc, INT left, INT top, INT right, INT bottom )
527 X11DRV_PDEVICE *physDev = (X11DRV_PDEVICE *)dc->physDev;
529 left = XLPTODP( dc, left );
530 top = YLPTODP( dc, top );
531 right = XLPTODP( dc, right );
532 bottom = YLPTODP( dc, bottom );
533 if ((left == right) || (top == bottom)) return TRUE;
535 if (right < left) { INT tmp = right; right = left; left = tmp; }
536 if (bottom < top) { INT tmp = bottom; bottom = top; top = tmp; }
538 oldwidth = width = physDev->pen.width;
539 if (!width) width = 1;
540 if(physDev->pen.style == PS_NULL) width = 0;
542 if ((physDev->pen.style == PS_INSIDEFRAME))
544 if (2*width > (right-left)) width=(right-left + 1)/2;
545 if (2*width > (bottom-top)) width=(bottom-top + 1)/2;
547 right -= (width - 1) / 2;
549 bottom -= (width - 1) / 2;
551 if(width == 0) width = 1; /* more accurate */
552 physDev->pen.width = width;
554 if (X11DRV_SetupGCForBrush( dc ))
555 TSXFillArc( display, physDev->drawable, physDev->gc,
556 dc->w.DCOrgX + left, dc->w.DCOrgY + top,
557 right-left-1, bottom-top-1, 0, 360*64 );
558 if (X11DRV_SetupGCForPen( dc ))
559 TSXDrawArc( display, physDev->drawable, physDev->gc,
560 dc->w.DCOrgX + left, dc->w.DCOrgY + top,
561 right-left-1, bottom-top-1, 0, 360*64 );
562 physDev->pen.width = oldwidth;
567 /***********************************************************************
571 X11DRV_Rectangle(DC *dc, INT left, INT top, INT right, INT bottom)
573 INT width, oldwidth, oldjoinstyle;
574 X11DRV_PDEVICE *physDev = (X11DRV_PDEVICE *)dc->physDev;
576 TRACE(graphics, "(%d %d %d %d)\n",
577 left, top, right, bottom);
579 left = XLPTODP( dc, left );
580 top = YLPTODP( dc, top );
581 right = XLPTODP( dc, right );
582 bottom = YLPTODP( dc, bottom );
584 if ((left == right) || (top == bottom)) return TRUE;
586 if (right < left) { INT tmp = right; right = left; left = tmp; }
587 if (bottom < top) { INT tmp = bottom; bottom = top; top = tmp; }
589 oldwidth = width = physDev->pen.width;
590 if (!width) width = 1;
591 if(physDev->pen.style == PS_NULL) width = 0;
593 if ((physDev->pen.style == PS_INSIDEFRAME))
595 if (2*width > (right-left)) width=(right-left + 1)/2;
596 if (2*width > (bottom-top)) width=(bottom-top + 1)/2;
598 right -= (width - 1) / 2;
600 bottom -= (width - 1) / 2;
602 if(width == 1) width = 0;
603 physDev->pen.width = width;
604 oldjoinstyle = physDev->pen.linejoin;
605 if(physDev->pen.type != PS_GEOMETRIC)
606 physDev->pen.linejoin = PS_JOIN_MITER;
608 if ((right > left + width) && (bottom > top + width))
610 if (X11DRV_SetupGCForBrush( dc ))
611 TSXFillRectangle( display, physDev->drawable, physDev->gc,
612 dc->w.DCOrgX + left + (width + 1) / 2,
613 dc->w.DCOrgY + top + (width + 1) / 2,
614 right-left-width-1, bottom-top-width-1);
616 if (X11DRV_SetupGCForPen( dc ))
617 TSXDrawRectangle( display, physDev->drawable, physDev->gc,
618 dc->w.DCOrgX + left, dc->w.DCOrgY + top,
619 right-left-1, bottom-top-1 );
621 physDev->pen.width = oldwidth;
622 physDev->pen.linejoin = oldjoinstyle;
626 /***********************************************************************
630 X11DRV_RoundRect( DC *dc, INT left, INT top, INT right,
631 INT bottom, INT ell_width, INT ell_height )
633 INT width, oldwidth, oldendcap;
634 X11DRV_PDEVICE *physDev = (X11DRV_PDEVICE *)dc->physDev;
636 TRACE(graphics, "(%d %d %d %d %d %d\n",
637 left, top, right, bottom, ell_width, ell_height);
639 left = XLPTODP( dc, left );
640 top = YLPTODP( dc, top );
641 right = XLPTODP( dc, right );
642 bottom = YLPTODP( dc, bottom );
644 if ((left == right) || (top == bottom))
647 /* Make sure ell_width and ell_height are >= 1 otherwise XDrawArc gets
648 called with width/height < 0 */
649 ell_width = MAX(abs( ell_width * dc->vportExtX / dc->wndExtX ), 1);
650 ell_height = MAX(abs( ell_height * dc->vportExtY / dc->wndExtY ), 1);
652 /* Fix the coordinates */
654 if (right < left) { INT tmp = right; right = left; left = tmp; }
655 if (bottom < top) { INT tmp = bottom; bottom = top; top = tmp; }
657 oldwidth = width = physDev->pen.width;
658 oldendcap = physDev->pen.endcap;
659 if (!width) width = 1;
660 if(physDev->pen.style == PS_NULL) width = 0;
662 if ((physDev->pen.style == PS_INSIDEFRAME))
664 if (2*width > (right-left)) width=(right-left + 1)/2;
665 if (2*width > (bottom-top)) width=(bottom-top + 1)/2;
667 right -= (width - 1) / 2;
669 bottom -= (width - 1) / 2;
671 if(width == 0) width = 1;
672 physDev->pen.width = width;
673 physDev->pen.endcap = PS_ENDCAP_SQUARE;
675 if (X11DRV_SetupGCForBrush( dc ))
677 if (ell_width > (right-left) )
678 if (ell_height > (bottom-top) )
679 TSXFillArc( display, physDev->drawable, physDev->gc,
680 dc->w.DCOrgX + left, dc->w.DCOrgY + top,
681 right - left - 1, bottom - top - 1,
684 TSXFillArc( display, physDev->drawable, physDev->gc,
685 dc->w.DCOrgX + left, dc->w.DCOrgY + top,
686 right - left - 1, ell_height, 0, 180 * 64 );
687 TSXFillArc( display, physDev->drawable, physDev->gc,
689 dc->w.DCOrgY + bottom - ell_height - 1,
690 right - left - 1, ell_height, 180 * 64,
693 else if (ell_height > (bottom-top) ){
694 TSXFillArc( display, physDev->drawable, physDev->gc,
695 dc->w.DCOrgX + left, dc->w.DCOrgY + top,
696 ell_width, bottom - top - 1, 90 * 64, 180 * 64 );
697 TSXFillArc( display, physDev->drawable, physDev->gc,
698 dc->w.DCOrgX + right - ell_width -1, dc->w.DCOrgY + top,
699 ell_width, bottom - top - 1, 270 * 64, 180 * 64 );
701 TSXFillArc( display, physDev->drawable, physDev->gc,
702 dc->w.DCOrgX + left, dc->w.DCOrgY + top,
703 ell_width, ell_height, 90 * 64, 90 * 64 );
704 TSXFillArc( display, physDev->drawable, physDev->gc,
706 dc->w.DCOrgY + bottom - ell_height - 1,
707 ell_width, ell_height, 180 * 64, 90 * 64 );
708 TSXFillArc( display, physDev->drawable, physDev->gc,
709 dc->w.DCOrgX + right - ell_width - 1,
710 dc->w.DCOrgY + bottom - ell_height - 1,
711 ell_width, ell_height, 270 * 64, 90 * 64 );
712 TSXFillArc( display, physDev->drawable, physDev->gc,
713 dc->w.DCOrgX + right - ell_width - 1,
715 ell_width, ell_height, 0, 90 * 64 );
717 if (ell_width < right - left)
719 TSXFillRectangle( display, physDev->drawable, physDev->gc,
720 dc->w.DCOrgX + left + (ell_width + 1) / 2,
721 dc->w.DCOrgY + top + 1,
722 right - left - ell_width - 1,
723 (ell_height + 1) / 2 - 1);
724 TSXFillRectangle( display, physDev->drawable, physDev->gc,
725 dc->w.DCOrgX + left + (ell_width + 1) / 2,
726 dc->w.DCOrgY + bottom - (ell_height) / 2 - 1,
727 right - left - ell_width - 1,
730 if (ell_height < bottom - top)
732 TSXFillRectangle( display, physDev->drawable, physDev->gc,
733 dc->w.DCOrgX + left + 1,
734 dc->w.DCOrgY + top + (ell_height + 1) / 2,
736 bottom - top - ell_height - 1);
739 /* FIXME: this could be done with on X call
740 * more efficient and probably more correct
741 * on any X server: XDrawArcs will draw
742 * straight horizontal and vertical lines
743 * if width or height are zero.
745 * BTW this stuff is optimized for an Xfree86 server
746 * read the comments inside the X11DRV_DrawArc function
748 if (X11DRV_SetupGCForPen(dc)) {
749 if (ell_width > (right-left) )
750 if (ell_height > (bottom-top) )
751 TSXDrawArc( display, physDev->drawable, physDev->gc,
752 dc->w.DCOrgX + left, dc->w.DCOrgY + top,
753 right - left - 1, bottom -top - 1, 0 , 360 * 64 );
755 TSXDrawArc( display, physDev->drawable, physDev->gc,
756 dc->w.DCOrgX + left, dc->w.DCOrgY + top,
757 right - left - 1, ell_height - 1, 0 , 180 * 64 );
758 TSXDrawArc( display, physDev->drawable, physDev->gc,
760 dc->w.DCOrgY + bottom - ell_height,
761 right - left - 1, ell_height - 1, 180 * 64 , 180 * 64 );
763 else if (ell_height > (bottom-top) ){
764 TSXDrawArc( display, physDev->drawable, physDev->gc,
765 dc->w.DCOrgX + left, dc->w.DCOrgY + top,
766 ell_width - 1 , bottom - top - 1, 90 * 64 , 180 * 64 );
767 TSXDrawArc( display, physDev->drawable, physDev->gc,
768 dc->w.DCOrgX + right - ell_width,
770 ell_width - 1 , bottom - top - 1, 270 * 64 , 180 * 64 );
772 TSXDrawArc( display, physDev->drawable, physDev->gc,
773 dc->w.DCOrgX + left, dc->w.DCOrgY + top,
774 ell_width - 1, ell_height - 1, 90 * 64, 90 * 64 );
775 TSXDrawArc( display, physDev->drawable, physDev->gc,
776 dc->w.DCOrgX + left, dc->w.DCOrgY + bottom - ell_height,
777 ell_width - 1, ell_height - 1, 180 * 64, 90 * 64 );
778 TSXDrawArc( display, physDev->drawable, physDev->gc,
779 dc->w.DCOrgX + right - ell_width,
780 dc->w.DCOrgY + bottom - ell_height,
781 ell_width - 1, ell_height - 1, 270 * 64, 90 * 64 );
782 TSXDrawArc( display, physDev->drawable, physDev->gc,
783 dc->w.DCOrgX + right - ell_width, dc->w.DCOrgY + top,
784 ell_width - 1, ell_height - 1, 0, 90 * 64 );
786 if (ell_width < right - left)
788 TSXDrawLine( display, physDev->drawable, physDev->gc,
789 dc->w.DCOrgX + left + ell_width / 2,
791 dc->w.DCOrgX + right - (ell_width+1) / 2,
793 TSXDrawLine( display, physDev->drawable, physDev->gc,
794 dc->w.DCOrgX + left + ell_width / 2 ,
795 dc->w.DCOrgY + bottom - 1,
796 dc->w.DCOrgX + right - (ell_width+1)/ 2,
797 dc->w.DCOrgY + bottom - 1);
799 if (ell_height < bottom - top)
801 TSXDrawLine( display, physDev->drawable, physDev->gc,
802 dc->w.DCOrgX + right - 1,
803 dc->w.DCOrgY + top + ell_height / 2,
804 dc->w.DCOrgX + right - 1,
805 dc->w.DCOrgY + bottom - (ell_height+1) / 2);
806 TSXDrawLine( display, physDev->drawable, physDev->gc,
808 dc->w.DCOrgY + top + ell_height / 2,
810 dc->w.DCOrgY + bottom - (ell_height+1) / 2);
813 physDev->pen.width = oldwidth;
814 physDev->pen.endcap = oldendcap;
819 /***********************************************************************
823 X11DRV_SetPixel( DC *dc, INT x, INT y, COLORREF color )
826 X11DRV_PDEVICE *physDev = (X11DRV_PDEVICE *)dc->physDev;
828 x = dc->w.DCOrgX + XLPTODP( dc, x );
829 y = dc->w.DCOrgY + YLPTODP( dc, y );
830 pixel = COLOR_ToPhysical( dc, color );
832 TSXSetForeground( display, physDev->gc, pixel );
833 TSXSetFunction( display, physDev->gc, GXcopy );
834 TSXDrawPoint( display, physDev->drawable, physDev->gc, x, y );
836 /* inefficient but simple... */
838 return COLOR_ToLogical(pixel);
842 /***********************************************************************
846 X11DRV_GetPixel( DC *dc, INT x, INT y )
848 static Pixmap pixmap = 0;
851 X11DRV_PDEVICE *physDev = (X11DRV_PDEVICE *)dc->physDev;
853 x = dc->w.DCOrgX + XLPTODP( dc, x );
854 y = dc->w.DCOrgY + YLPTODP( dc, y );
855 EnterCriticalSection( &X11DRV_CritSection );
856 if (dc->w.flags & DC_MEMORY)
858 image = XGetImage( display, physDev->drawable, x, y, 1, 1,
859 AllPlanes, ZPixmap );
863 /* If we are reading from the screen, use a temporary copy */
864 /* to avoid a BadMatch error */
865 if (!pixmap) pixmap = XCreatePixmap( display, X11DRV_GetXRootWindow(),
866 1, 1, dc->w.bitsPerPixel );
867 XCopyArea( display, physDev->drawable, pixmap, BITMAP_colorGC,
869 image = XGetImage( display, pixmap, 0, 0, 1, 1, AllPlanes, ZPixmap );
871 pixel = XGetPixel( image, 0, 0 );
872 XDestroyImage( image );
873 LeaveCriticalSection( &X11DRV_CritSection );
875 return COLOR_ToLogical(pixel);
879 /***********************************************************************
883 X11DRV_PaintRgn( DC *dc, HRGN hrgn )
886 HRGN tmpVisRgn, prevVisRgn;
887 HDC hdc = dc->hSelf; /* FIXME: should not mix dc/hdc this way */
888 X11DRV_PDEVICE *physDev = (X11DRV_PDEVICE *)dc->physDev;
890 if (!(tmpVisRgn = CreateRectRgn( 0, 0, 0, 0 ))) return FALSE;
892 /* Transform region into device co-ords */
893 if ( !REGION_LPTODP( hdc, tmpVisRgn, hrgn )
894 || OffsetRgn( tmpVisRgn, dc->w.DCOrgX, dc->w.DCOrgY ) == ERROR) {
895 DeleteObject( tmpVisRgn );
899 /* Modify visible region */
900 if (!(prevVisRgn = SaveVisRgn16( hdc ))) {
901 DeleteObject( tmpVisRgn );
904 CombineRgn( tmpVisRgn, prevVisRgn, tmpVisRgn, RGN_AND );
905 SelectVisRgn16( hdc, tmpVisRgn );
906 DeleteObject( tmpVisRgn );
908 /* Fill the region */
910 GetRgnBox( dc->w.hGCClipRgn, &box );
911 if (X11DRV_SetupGCForBrush( dc ))
912 TSXFillRectangle( display, physDev->drawable, physDev->gc,
914 box.right-box.left, box.bottom-box.top );
916 /* Restore the visible region */
918 RestoreVisRgn16( hdc );
922 /**********************************************************************
926 X11DRV_Polyline( DC *dc, const POINT* pt, INT count )
931 X11DRV_PDEVICE *physDev = (X11DRV_PDEVICE *)dc->physDev;
933 if((oldwidth = physDev->pen.width) == 0) physDev->pen.width = 1;
935 points = (XPoint *) xmalloc (sizeof (XPoint) * (count));
936 for (i = 0; i < count; i++)
938 points[i].x = dc->w.DCOrgX + XLPTODP( dc, pt[i].x );
939 points[i].y = dc->w.DCOrgY + YLPTODP( dc, pt[i].y );
942 if (X11DRV_SetupGCForPen ( dc ))
943 TSXDrawLines( display, physDev->drawable, physDev->gc,
944 points, count, CoordModeOrigin );
947 physDev->pen.width = oldwidth;
952 /**********************************************************************
956 X11DRV_Polygon( DC *dc, const POINT* pt, INT count )
960 X11DRV_PDEVICE *physDev = (X11DRV_PDEVICE *)dc->physDev;
962 points = (XPoint *) xmalloc (sizeof (XPoint) * (count+1));
963 for (i = 0; i < count; i++)
965 points[i].x = dc->w.DCOrgX + XLPTODP( dc, pt[i].x );
966 points[i].y = dc->w.DCOrgY + YLPTODP( dc, pt[i].y );
968 points[count] = points[0];
970 if (X11DRV_SetupGCForBrush( dc ))
971 TSXFillPolygon( display, physDev->drawable, physDev->gc,
972 points, count+1, Complex, CoordModeOrigin);
974 if (X11DRV_SetupGCForPen ( dc ))
975 TSXDrawLines( display, physDev->drawable, physDev->gc,
976 points, count+1, CoordModeOrigin );
983 /**********************************************************************
987 X11DRV_PolyPolygon( DC *dc, const POINT* pt, const INT* counts, UINT polygons)
990 X11DRV_PDEVICE *physDev = (X11DRV_PDEVICE *)dc->physDev;
992 /* FIXME: The points should be converted to device coords before */
993 /* creating the region. */
995 hrgn = CreatePolyPolygonRgn( pt, counts, polygons, dc->w.polyFillMode );
996 X11DRV_PaintRgn( dc, hrgn );
997 DeleteObject( hrgn );
999 /* Draw the outline of the polygons */
1001 if (X11DRV_SetupGCForPen ( dc ))
1006 for (i = 0; i < polygons; i++) if (counts[i] > max) max = counts[i];
1007 points = (XPoint *) xmalloc( sizeof(XPoint) * (max+1) );
1009 for (i = 0; i < polygons; i++)
1011 for (j = 0; j < counts[i]; j++)
1013 points[j].x = dc->w.DCOrgX + XLPTODP( dc, pt->x );
1014 points[j].y = dc->w.DCOrgY + YLPTODP( dc, pt->y );
1017 points[j] = points[0];
1018 TSXDrawLines( display, physDev->drawable, physDev->gc,
1019 points, j + 1, CoordModeOrigin );
1027 /**********************************************************************
1028 * X11DRV_PolyPolyline
1031 X11DRV_PolyPolyline( DC *dc, const POINT* pt, const DWORD* counts, DWORD polylines )
1033 X11DRV_PDEVICE *physDev = (X11DRV_PDEVICE *)dc->physDev;
1034 if (X11DRV_SetupGCForPen ( dc ))
1039 for (i = 0; i < polylines; i++) if (counts[i] > max) max = counts[i];
1040 points = (XPoint *) xmalloc( sizeof(XPoint) * (max+1) );
1042 for (i = 0; i < polylines; i++)
1044 for (j = 0; j < counts[i]; j++)
1046 points[j].x = dc->w.DCOrgX + XLPTODP( dc, pt->x );
1047 points[j].y = dc->w.DCOrgY + YLPTODP( dc, pt->y );
1050 points[j] = points[0];
1051 TSXDrawLines( display, physDev->drawable, physDev->gc,
1052 points, j + 1, CoordModeOrigin );
1060 /**********************************************************************
1061 * X11DRV_InternalFloodFill
1063 * Internal helper function for flood fill.
1064 * (xorg,yorg) is the origin of the X image relative to the drawable.
1065 * (x,y) is relative to the origin of the X image.
1067 static void X11DRV_InternalFloodFill(XImage *image, DC *dc,
1070 Pixel pixel, WORD fillType )
1072 X11DRV_PDEVICE *physDev = (X11DRV_PDEVICE *)dc->physDev;
1075 #define TO_FLOOD(x,y) ((fillType == FLOODFILLBORDER) ? \
1076 (XGetPixel(image,x,y) != pixel) : \
1077 (XGetPixel(image,x,y) == pixel))
1079 if (!TO_FLOOD(x,y)) return;
1081 /* Find left and right boundaries */
1084 while ((left > 0) && TO_FLOOD( left-1, y )) left--;
1085 while ((right < image->width) && TO_FLOOD( right, y )) right++;
1086 XFillRectangle( display, physDev->drawable, physDev->gc,
1087 xOrg + left, yOrg + y, right-left, 1 );
1089 /* Set the pixels of this line so we don't fill it again */
1091 for (x = left; x < right; x++)
1093 if (fillType == FLOODFILLBORDER) XPutPixel( image, x, y, pixel );
1094 else XPutPixel( image, x, y, ~pixel );
1097 /* Fill the line above */
1104 while ((x < right) && !TO_FLOOD(x,y)) x++;
1105 if (x >= right) break;
1106 while ((x < right) && TO_FLOOD(x,y)) x++;
1107 X11DRV_InternalFloodFill(image, dc, x-1, y,
1108 xOrg, yOrg, pixel, fillType );
1112 /* Fill the line below */
1114 if ((y += 2) < image->height)
1119 while ((x < right) && !TO_FLOOD(x,y)) x++;
1120 if (x >= right) break;
1121 while ((x < right) && TO_FLOOD(x,y)) x++;
1122 X11DRV_InternalFloodFill(image, dc, x-1, y,
1123 xOrg, yOrg, pixel, fillType );
1130 /**********************************************************************
1131 * X11DRV_DoFloodFill
1133 * Main flood-fill routine.
1135 * The Xlib critical section must be entered before calling this function.
1138 struct FloodFill_params
1147 static BOOL X11DRV_DoFloodFill( const struct FloodFill_params *params )
1151 DC *dc = params->dc;
1152 X11DRV_PDEVICE *physDev = (X11DRV_PDEVICE *)dc->physDev;
1154 if (GetRgnBox( dc->w.hGCClipRgn, &rect ) == ERROR) return FALSE;
1156 if (!(image = XGetImage( display, physDev->drawable,
1159 rect.right - rect.left,
1160 rect.bottom - rect.top,
1161 AllPlanes, ZPixmap ))) return FALSE;
1163 if (X11DRV_SetupGCForBrush( dc ))
1165 /* ROP mode is always GXcopy for flood-fill */
1166 XSetFunction( display, physDev->gc, GXcopy );
1167 X11DRV_InternalFloodFill(image, dc,
1168 XLPTODP(dc,params->x) + dc->w.DCOrgX - rect.left,
1169 YLPTODP(dc,params->y) + dc->w.DCOrgY - rect.top,
1172 COLOR_ToPhysical( dc, params->color ),
1176 XDestroyImage( image );
1181 /**********************************************************************
1182 * X11DRV_ExtFloodFill
1185 X11DRV_ExtFloodFill( DC *dc, INT x, INT y, COLORREF color,
1189 struct FloodFill_params params = { dc, x, y, color, fillType };
1191 TRACE(graphics, "X11DRV_ExtFloodFill %d,%d %06lx %d\n",
1192 x, y, color, fillType );
1194 if (!PtVisible( dc->hSelf, x, y )) return FALSE;
1195 EnterCriticalSection( &X11DRV_CritSection );
1196 result = CALL_LARGE_STACK( X11DRV_DoFloodFill, ¶ms );
1197 LeaveCriticalSection( &X11DRV_CritSection );
1201 /******************************************************************
1203 * *Very* simple bezier drawing code,
1205 * It uses a recursive algorithm to divide the curve in a series
1206 * of straight line segements. Not ideal but for me sufficient.
1207 * If you are in need for something better look for some incremental
1210 * 7 July 1998 Rein Klazes
1214 * some macro definitions for bezier drawing
1216 * to avoid trucation errors the coordinates are
1217 * shifted upwards. When used in drawing they are
1218 * shifted down again, including correct rounding
1219 * and avoiding floating point arithmatic
1220 * 4 bits should allow 27 bits coordinates which I saw
1221 * somewere in the win32 doc's
1225 #define BEZIERSHIFTBITS 4
1226 #define BEZIERSHIFTUP(x) ((x)<<BEZIERSHIFTBITS)
1227 #define BEZIERPIXEL BEZIERSHIFTUP(1)
1228 #define BEZIERSHIFTDOWN(x) (((x)+(1<<(BEZIERSHIFTBITS-1)))>>BEZIERSHIFTBITS)
1229 /* maximum depth of recursion */
1230 #define BEZIERMAXDEPTH 8
1232 /* size of array to store points on */
1233 /* enough for one curve */
1234 #define BEZMAXPOINTS (150)
1236 /* calculate Bezier average, in this case the middle
1237 * correctly rounded...
1240 #define BEZIERMIDDLE(Mid, P1, P2) \
1241 (Mid).x=((P1).x+(P2).x + 1)/2;\
1242 (Mid).y=((P1).y+(P2).y + 1)/2;
1244 /**********************************************************
1245 * BezierCheck helper function to check
1246 * that recursion can be terminated
1247 * Points[0] and Points[3] are begin and endpoint
1248 * Points[1] and Points[2] are control points
1249 * level is the recursion depth
1250 * returns true if the recusion can be terminated
1252 static BOOL BezierCheck( int level, POINT *Points)
1255 dx=Points[3].x-Points[0].x;
1256 dy=Points[3].y-Points[0].y;
1257 if(ABS(dy)<=ABS(dx)){/* shallow line */
1258 /* check that control points are between begin and end */
1259 if(Points[1].x < Points[0].x){
1260 if(Points[1].x < Points[3].x)
1263 if(Points[1].x > Points[3].x)
1265 if(Points[2].x < Points[0].x){
1266 if(Points[2].x < Points[3].x)
1269 if(Points[2].x > Points[3].x)
1271 dx=BEZIERSHIFTDOWN(dx);
1272 if(!dx) return TRUE;
1273 if(abs(Points[1].y-Points[0].y-(dy/dx)*
1274 BEZIERSHIFTDOWN(Points[1].x-Points[0].x)) > BEZIERPIXEL ||
1275 abs(Points[2].y-Points[0].y-(dy/dx)*
1276 BEZIERSHIFTDOWN(Points[2].x-Points[0].x)) > BEZIERPIXEL )
1280 }else{ /* steep line */
1281 /* check that control points are between begin and end */
1282 if(Points[1].y < Points[0].y){
1283 if(Points[1].y < Points[3].y)
1286 if(Points[1].y > Points[3].y)
1288 if(Points[2].y < Points[0].y){
1289 if(Points[2].y < Points[3].y)
1292 if(Points[2].y > Points[3].y)
1294 dy=BEZIERSHIFTDOWN(dy);
1295 if(!dy) return TRUE;
1296 if(abs(Points[1].x-Points[0].x-(dx/dy)*
1297 BEZIERSHIFTDOWN(Points[1].y-Points[0].y)) > BEZIERPIXEL ||
1298 abs(Points[2].x-Points[0].x-(dx/dy)*
1299 BEZIERSHIFTDOWN(Points[2].y-Points[0].y)) > BEZIERPIXEL )
1306 /***********************************************************************
1308 * Draw a -what microsoft calls- bezier curve
1309 * The routine recursively devides the curve
1310 * in two parts until a straight line can be drawn
1312 * level recusion depth counted backwards
1314 * Points array of begin(0), end(3) and control points(1 and 2)
1315 * XPoints array with points calculated sofar
1316 * *pIx nr points calculated sofar
1319 static void X11DRV_Bezier(int level, DC * dc, POINT *Points,
1320 XPoint* xpoints, unsigned int* pIx)
1322 X11DRV_PDEVICE *physDev = (X11DRV_PDEVICE *)dc->physDev;
1324 if(*pIx == BEZMAXPOINTS){
1325 TSXDrawLines( display, physDev->drawable, physDev->gc,
1326 xpoints, *pIx, CoordModeOrigin );
1329 if(!level || BezierCheck(level, Points)) {
1331 xpoints[*pIx].x= dc->w.DCOrgX + BEZIERSHIFTDOWN(Points[0].x);
1332 xpoints[*pIx].y= dc->w.DCOrgY + BEZIERSHIFTDOWN(Points[0].y);
1335 xpoints[*pIx].x= dc->w.DCOrgX + BEZIERSHIFTDOWN(Points[3].x);
1336 xpoints[*pIx].y= dc->w.DCOrgY + BEZIERSHIFTDOWN(Points[3].y);
1339 POINT Points2[4]; /* for the second recursive call */
1340 Points2[3]=Points[3];
1341 BEZIERMIDDLE(Points2[2], Points[2], Points[3]);
1342 BEZIERMIDDLE(Points2[0], Points[1], Points[2]);
1343 BEZIERMIDDLE(Points2[1],Points2[0],Points2[2]);
1345 BEZIERMIDDLE(Points[1], Points[0], Points[1]);
1346 BEZIERMIDDLE(Points[2], Points[1], Points2[0]);
1347 BEZIERMIDDLE(Points[3], Points[2], Points2[1]);
1349 Points2[0]=Points[3];
1351 /* do the two halves */
1352 X11DRV_Bezier(level-1, dc, Points, xpoints, pIx);
1353 X11DRV_Bezier(level-1, dc, Points2, xpoints, pIx);
1357 /***********************************************************************
1359 * Implement functionality for PolyBezier and PolyBezierTo
1361 * [i] dc pointer to device context
1362 * [i] start, first point in curve
1363 * [i] BezierPoints , array of point filled with rest of the points
1364 * [i] count, number of points in BezierPoints, must be a
1368 X11DRV_PolyBezier(DC *dc, POINT start, const POINT* BezierPoints, DWORD count)
1374 X11DRV_PDEVICE *physDev = (X11DRV_PDEVICE *)dc->physDev;
1376 TRACE(graphics, "dc=%p count=%ld %ld,%ld - %ld,%ld - %ld,%ld - %ld,%ld\n",
1379 (Points+0)->x, (Points+0)->y,
1380 (Points+1)->x, (Points+1)->y,
1381 (Points+2)->x, (Points+2)->y);
1382 if(!count || count % 3){/* paranoid */
1383 WARN(graphics," bad value for count : %ld\n", count);
1386 xpoints=(XPoint*) xmalloc( sizeof(XPoint)*BEZMAXPOINTS);
1387 Points[3].x=BEZIERSHIFTUP(XLPTODP(dc,start.x));
1388 Points[3].y=BEZIERSHIFTUP(YLPTODP(dc,start.y));
1390 Points[0]=Points[3];
1392 Points[i].x= BEZIERSHIFTUP(XLPTODP(dc,BezierPoints->x));
1393 Points[i].y= BEZIERSHIFTUP(YLPTODP(dc,BezierPoints->y));
1396 X11DRV_Bezier(BEZIERMAXDEPTH , dc, Points, xpoints, &ix );
1399 if( ix) TSXDrawLines( display, physDev->drawable, physDev->gc,
1400 xpoints, ix, CoordModeOrigin );
1405 /**********************************************************************
1409 X11DRV_SetBkColor( DC *dc, COLORREF color )
1411 X11DRV_PDEVICE *physDev = (X11DRV_PDEVICE *)dc->physDev;
1414 oldColor = dc->w.backgroundColor;
1415 dc->w.backgroundColor = color;
1417 physDev->backgroundPixel = COLOR_ToPhysical( dc, color );
1422 /**********************************************************************
1423 * X11DRV_SetTextColor
1426 X11DRV_SetTextColor( DC *dc, COLORREF color )
1428 X11DRV_PDEVICE *physDev = (X11DRV_PDEVICE *)dc->physDev;
1431 oldColor = dc->w.textColor;
1432 dc->w.textColor = color;
1434 physDev->textPixel = COLOR_ToPhysical( dc, color );
1439 #endif /* !defined(X_DISPLAY_MISSING) */