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 )
78 X11DRV_PDEVICE *physDev = (X11DRV_PDEVICE *)dc->physDev;
80 if (physDev->brush.style == BS_NULL) return FALSE;
81 if (physDev->brush.pixel == -1)
83 /* Special case used for monochrome pattern brushes.
84 * We need to swap foreground and background because
85 * Windows does it the wrong way...
87 val.foreground = physDev->backgroundPixel;
88 val.background = physDev->textPixel;
92 val.foreground = physDev->brush.pixel;
93 val.background = physDev->backgroundPixel;
95 if (fMapColors && COLOR_PixelToPalette)
97 val.foreground = COLOR_PixelToPalette[val.foreground];
98 val.background = COLOR_PixelToPalette[val.background];
101 if (dc->w.flags & DC_DIRTY) CLIPPING_UpdateGCRegion(dc);
103 val.function = X11DRV_XROPfunction[dc->w.ROPmode-1];
105 ** Let's replace GXinvert by GXxor with (black xor white)
106 ** This solves the selection color and leak problems in excel
107 ** FIXME : Let's do that only if we work with X-pixels, not with Win-pixels
109 if (val.function == GXinvert)
111 val.foreground = BlackPixelOfScreen(screen) ^ WhitePixelOfScreen(screen);
112 val.function = GXxor;
114 val.fill_style = physDev->brush.fillStyle;
115 switch(val.fill_style)
118 case FillOpaqueStippled:
119 if (dc->w.backgroundMode==OPAQUE) val.fill_style = FillOpaqueStippled;
120 val.stipple = physDev->brush.pixmap;
125 if (fMapColors && COLOR_PixelToPalette)
129 EnterCriticalSection( &X11DRV_CritSection );
130 pixmap = XCreatePixmap( display, rootWindow, 8, 8, screenDepth );
131 image = XGetImage( display, physDev->brush.pixmap, 0, 0, 8, 8,
132 AllPlanes, ZPixmap );
133 for (y = 0; y < 8; y++)
134 for (x = 0; x < 8; x++)
135 XPutPixel( image, x, y,
136 COLOR_PixelToPalette[XGetPixel( image, x, y)] );
137 XPutImage( display, pixmap, gc, image, 0, 0, 0, 0, 8, 8 );
138 XDestroyImage( image );
139 LeaveCriticalSection( &X11DRV_CritSection );
142 else val.tile = physDev->brush.pixmap;
150 val.ts_x_origin = dc->w.DCOrgX + dc->w.brushOrgX;
151 val.ts_y_origin = dc->w.DCOrgY + dc->w.brushOrgY;
152 val.fill_rule = (dc->w.polyFillMode==WINDING) ? WindingRule : EvenOddRule;
153 TSXChangeGC( display, gc,
154 GCFunction | GCForeground | GCBackground | GCFillStyle |
155 GCFillRule | GCTileStipXOrigin | GCTileStipYOrigin | mask,
157 if (pixmap) TSXFreePixmap( display, pixmap );
162 /***********************************************************************
163 * X11DRV_SetupGCForBrush
165 * Setup physDev->gc for drawing operations using current brush.
166 * Return FALSE if brush is BS_NULL, TRUE otherwise.
168 BOOL32 X11DRV_SetupGCForBrush( DC * dc )
170 X11DRV_PDEVICE *physDev = (X11DRV_PDEVICE *)dc->physDev;
171 return X11DRV_SetupGCForPatBlt( dc, physDev->gc, FALSE );
175 /***********************************************************************
176 * X11DRV_SetupGCForPen
178 * Setup physDev->gc for drawing operations using current pen.
179 * Return FALSE if pen is PS_NULL, TRUE otherwise.
181 BOOL32 X11DRV_SetupGCForPen( DC * dc )
184 X11DRV_PDEVICE *physDev = (X11DRV_PDEVICE *)dc->physDev;
186 if (physDev->pen.style == PS_NULL) return FALSE;
188 if (dc->w.flags & DC_DIRTY) CLIPPING_UpdateGCRegion(dc);
190 switch (dc->w.ROPmode)
193 val.foreground = BlackPixelOfScreen( screen );
194 val.function = GXcopy;
197 val.foreground = WhitePixelOfScreen( screen );
198 val.function = GXcopy;
201 val.foreground = physDev->pen.pixel;
202 /* It is very unlikely someone wants to XOR with 0 */
203 /* This fixes the rubber-drawings in paintbrush */
204 if (val.foreground == 0)
205 val.foreground = BlackPixelOfScreen( screen )
206 ^ WhitePixelOfScreen( screen );
207 val.function = GXxor;
210 val.foreground = physDev->pen.pixel;
211 val.function = X11DRV_XROPfunction[dc->w.ROPmode-1];
213 val.background = physDev->backgroundPixel;
214 val.fill_style = FillSolid;
215 if ((physDev->pen.style!=PS_SOLID) && (physDev->pen.style!=PS_INSIDEFRAME))
217 TSXSetDashes( display, physDev->gc, 0, physDev->pen.dashes,
218 physDev->pen.dash_len );
219 val.line_style = (dc->w.backgroundMode == OPAQUE) ?
220 LineDoubleDash : LineOnOffDash;
222 else val.line_style = LineSolid;
223 val.line_width = physDev->pen.width;
224 if (val.line_width <= 1) {
225 val.cap_style = CapNotLast;
227 switch (physDev->pen.endcap)
229 case PS_ENDCAP_SQUARE:
230 val.cap_style = CapProjecting;
233 val.cap_style = CapButt;
235 case PS_ENDCAP_ROUND:
237 val.cap_style = CapRound;
240 switch (physDev->pen.linejoin)
243 val.join_style = JoinBevel;
246 val.join_style = JoinMiter;
250 val.join_style = JoinRound;
252 TSXChangeGC( display, physDev->gc,
253 GCFunction | GCForeground | GCBackground | GCLineWidth |
254 GCLineStyle | GCCapStyle | GCJoinStyle | GCFillStyle, &val );
259 /***********************************************************************
260 * X11DRV_SetupGCForText
262 * Setup physDev->gc for text drawing operations.
263 * Return FALSE if the font is null, TRUE otherwise.
265 BOOL32 X11DRV_SetupGCForText( DC * dc )
267 X11DRV_PDEVICE *physDev = (X11DRV_PDEVICE *)dc->physDev;
268 XFontStruct* xfs = XFONT_GetFontStruct( physDev->font );
274 if (dc->w.flags & DC_DIRTY) CLIPPING_UpdateGCRegion(dc);
276 val.function = GXcopy; /* Text is always GXcopy */
277 val.foreground = physDev->textPixel;
278 val.background = physDev->backgroundPixel;
279 val.fill_style = FillSolid;
282 TSXChangeGC( display, physDev->gc,
283 GCFunction | GCForeground | GCBackground | GCFillStyle |
287 WARN(dc, "Physical font failure\n" );
292 /**********************************************************************
296 X11DRV_MoveToEx(DC *dc,INT32 x,INT32 y,LPPOINT32 pt) {
299 pt->x = dc->w.CursPosX;
300 pt->y = dc->w.CursPosY;
307 /***********************************************************************
311 X11DRV_LineTo( DC *dc, INT32 x, INT32 y )
313 X11DRV_PDEVICE *physDev = (X11DRV_PDEVICE *)dc->physDev;
315 if (X11DRV_SetupGCForPen( dc ))
316 TSXDrawLine(display, physDev->drawable, physDev->gc,
317 dc->w.DCOrgX + XLPTODP( dc, dc->w.CursPosX ),
318 dc->w.DCOrgY + YLPTODP( dc, dc->w.CursPosY ),
319 dc->w.DCOrgX + XLPTODP( dc, x ),
320 dc->w.DCOrgY + YLPTODP( dc, y ) );
328 /***********************************************************************
331 * Helper functions for Arc(), Chord() and Pie().
332 * 'lines' is the number of lines to draw: 0 for Arc, 1 for Chord, 2 for Pie.
336 X11DRV_DrawArc( DC *dc, INT32 left, INT32 top, INT32 right,
337 INT32 bottom, INT32 xstart, INT32 ystart,
338 INT32 xend, INT32 yend, INT32 lines )
340 INT32 xcenter, ycenter, istart_angle, idiff_angle;
341 INT32 width, oldwidth, oldendcap;
342 double start_angle, end_angle;
344 X11DRV_PDEVICE *physDev = (X11DRV_PDEVICE *)dc->physDev;
346 left = XLPTODP( dc, left );
347 top = YLPTODP( dc, top );
348 right = XLPTODP( dc, right );
349 bottom = YLPTODP( dc, bottom );
350 xstart = XLPTODP( dc, xstart );
351 ystart = YLPTODP( dc, ystart );
352 xend = XLPTODP( dc, xend );
353 yend = YLPTODP( dc, yend );
355 if (right < left) { INT32 tmp = right; right = left; left = tmp; }
356 if (bottom < top) { INT32 tmp = bottom; bottom = top; top = tmp; }
357 if ((left == right) || (top == bottom)
358 ||(lines && ((right-left==1)||(bottom-top==1)))) return TRUE;
360 oldwidth = width = physDev->pen.width;
361 oldendcap = physDev->pen.endcap;
362 if (!width) width = 1;
363 if(physDev->pen.style == PS_NULL) width = 0;
365 if ((physDev->pen.style == PS_INSIDEFRAME))
367 if (2*width > (right-left)) width=(right-left + 1)/2;
368 if (2*width > (bottom-top)) width=(bottom-top + 1)/2;
370 right -= (width - 1) / 2;
372 bottom -= (width - 1) / 2;
374 if(width == 0) width = 1; /* more accurate */
375 physDev->pen.width = width;
376 physDev->pen.endcap = PS_ENDCAP_SQUARE;
378 xcenter = (right + left) / 2;
379 ycenter = (bottom + top) / 2;
380 start_angle = atan2( (double)(ycenter-ystart)*(right-left),
381 (double)(xstart-xcenter)*(bottom-top) );
382 end_angle = atan2( (double)(ycenter-yend)*(right-left),
383 (double)(xend-xcenter)*(bottom-top) );
384 if ((xstart==xend)&&(ystart==yend))
385 { /* A lazy program delivers xstart=xend=ystart=yend=0) */
389 else /* notorious cases */
390 if ((start_angle == PI)&&( end_angle <0))
393 if ((end_angle == PI)&&( start_angle <0))
395 istart_angle = (INT32)(start_angle * 180 * 64 / PI + 0.5);
396 idiff_angle = (INT32)((end_angle - start_angle) * 180 * 64 / PI + 0.5);
397 if (idiff_angle <= 0) idiff_angle += 360 * 64;
399 /* Fill arc with brush if Chord() or Pie() */
401 if ((lines > 0) && X11DRV_SetupGCForBrush( dc )) {
402 TSXSetArcMode( display, physDev->gc,
403 (lines==1) ? ArcChord : ArcPieSlice);
404 TSXFillArc( display, physDev->drawable, physDev->gc,
405 dc->w.DCOrgX + left, dc->w.DCOrgY + top,
406 right-left-1, bottom-top-1, istart_angle, idiff_angle );
409 /* Draw arc and lines */
411 if (X11DRV_SetupGCForPen( dc )){
412 TSXDrawArc( display, physDev->drawable, physDev->gc,
413 dc->w.DCOrgX + left, dc->w.DCOrgY + top,
414 right-left-1, bottom-top-1, istart_angle, idiff_angle );
416 /* use the truncated values */
417 start_angle=(double)istart_angle*PI/64./180.;
418 end_angle=(double)(istart_angle+idiff_angle)*PI/64./180.;
419 /* calculate the endpoints and round correctly */
420 points[0].x = (int) floor(dc->w.DCOrgX + (right+left)/2.0 +
421 cos(start_angle) * (right-left-width*2+2) / 2. + 0.5);
422 points[0].y = (int) floor(dc->w.DCOrgY + (top+bottom)/2.0 -
423 sin(start_angle) * (bottom-top-width*2+2) / 2. + 0.5);
424 points[1].x = (int) floor(dc->w.DCOrgX + (right+left)/2.0 +
425 cos(end_angle) * (right-left-width*2+2) / 2. + 0.5);
426 points[1].y = (int) floor(dc->w.DCOrgY + (top+bottom)/2.0 -
427 sin(end_angle) * (bottom-top-width*2+2) / 2. + 0.5);
429 /* OK this stuff is optimized for Xfree86
430 * which is probably the most used server by
431 * wine users. Other X servers will not
432 * display correctly. (eXceed for instance)
433 * so if you feel you must change make sure that
434 * you either use Xfree86 or seperate your changes
435 * from these (compile switch or whatever)
439 points[3] = points[1];
440 points[1].x = dc->w.DCOrgX + xcenter;
441 points[1].y = dc->w.DCOrgY + ycenter;
442 points[2] = points[1];
443 dx1=points[1].x-points[0].x;
444 dy1=points[1].y-points[0].y;
445 if(((top-bottom) | -2) == -2)
446 if(dy1>0) points[1].y--;
448 if (((-dx1)*64)<=ABS(dy1)*37) points[0].x--;
449 if(((-dx1*9))<(dy1*16)) points[0].y--;
450 if( dy1<0 && ((dx1*9)) < (dy1*16)) points[0].y--;
452 if(dy1 < 0) points[0].y--;
453 if(((right-left) | -2) == -2) points[1].x--;
455 dx1=points[3].x-points[2].x;
456 dy1=points[3].y-points[2].y;
457 if(((top-bottom) | -2 ) == -2)
458 if(dy1 < 0) points[2].y--;
460 if( dy1>0) points[3].y--;
461 if(((right-left) | -2) == -2 ) points[2].x--;
464 if( dx1 * 64 < dy1 * -37 ) points[3].x--;
468 TSXDrawLines( display, physDev->drawable, physDev->gc,
469 points, lines+1, CoordModeOrigin );
472 physDev->pen.width = oldwidth;
473 physDev->pen.endcap = oldendcap;
478 /***********************************************************************
482 X11DRV_Arc( DC *dc, INT32 left, INT32 top, INT32 right, INT32 bottom,
483 INT32 xstart, INT32 ystart, INT32 xend, INT32 yend )
485 return X11DRV_DrawArc( dc, left, top, right, bottom,
486 xstart, ystart, xend, yend, 0 );
490 /***********************************************************************
494 X11DRV_Pie( DC *dc, INT32 left, INT32 top, INT32 right, INT32 bottom,
495 INT32 xstart, INT32 ystart, INT32 xend, INT32 yend )
497 return X11DRV_DrawArc( dc, left, top, right, bottom,
498 xstart, ystart, xend, yend, 2 );
501 /***********************************************************************
505 X11DRV_Chord( DC *dc, INT32 left, INT32 top, INT32 right, INT32 bottom,
506 INT32 xstart, INT32 ystart, INT32 xend, INT32 yend )
508 return X11DRV_DrawArc( dc, left, top, right, bottom,
509 xstart, ystart, xend, yend, 1 );
513 /***********************************************************************
517 X11DRV_Ellipse( DC *dc, INT32 left, INT32 top, INT32 right, INT32 bottom )
519 INT32 width, oldwidth;
520 X11DRV_PDEVICE *physDev = (X11DRV_PDEVICE *)dc->physDev;
522 left = XLPTODP( dc, left );
523 top = YLPTODP( dc, top );
524 right = XLPTODP( dc, right );
525 bottom = YLPTODP( dc, bottom );
526 if ((left == right) || (top == bottom)) return TRUE;
528 if (right < left) { INT32 tmp = right; right = left; left = tmp; }
529 if (bottom < top) { INT32 tmp = bottom; bottom = top; top = tmp; }
531 oldwidth = width = physDev->pen.width;
532 if (!width) width = 1;
533 if(physDev->pen.style == PS_NULL) width = 0;
535 if ((physDev->pen.style == PS_INSIDEFRAME))
537 if (2*width > (right-left)) width=(right-left + 1)/2;
538 if (2*width > (bottom-top)) width=(bottom-top + 1)/2;
540 right -= (width - 1) / 2;
542 bottom -= (width - 1) / 2;
544 if(width == 0) width = 1; /* more accurate */
545 physDev->pen.width = width;
547 if (X11DRV_SetupGCForBrush( dc ))
548 TSXFillArc( display, physDev->drawable, physDev->gc,
549 dc->w.DCOrgX + left, dc->w.DCOrgY + top,
550 right-left-1, bottom-top-1, 0, 360*64 );
551 if (X11DRV_SetupGCForPen( dc ))
552 TSXDrawArc( display, physDev->drawable, physDev->gc,
553 dc->w.DCOrgX + left, dc->w.DCOrgY + top,
554 right-left-1, bottom-top-1, 0, 360*64 );
555 physDev->pen.width = oldwidth;
560 /***********************************************************************
564 X11DRV_Rectangle(DC *dc, INT32 left, INT32 top, INT32 right, INT32 bottom)
566 INT32 width, oldwidth, oldjoinstyle;
567 X11DRV_PDEVICE *physDev = (X11DRV_PDEVICE *)dc->physDev;
569 TRACE(graphics, "(%d %d %d %d)\n",
570 left, top, right, bottom);
572 left = XLPTODP( dc, left );
573 top = YLPTODP( dc, top );
574 right = XLPTODP( dc, right );
575 bottom = YLPTODP( dc, bottom );
577 if ((left == right) || (top == bottom)) return TRUE;
579 if (right < left) { INT32 tmp = right; right = left; left = tmp; }
580 if (bottom < top) { INT32 tmp = bottom; bottom = top; top = tmp; }
582 oldwidth = width = physDev->pen.width;
583 if (!width) width = 1;
584 if(physDev->pen.style == PS_NULL) width = 0;
586 if ((physDev->pen.style == PS_INSIDEFRAME))
588 if (2*width > (right-left)) width=(right-left + 1)/2;
589 if (2*width > (bottom-top)) width=(bottom-top + 1)/2;
591 right -= (width - 1) / 2;
593 bottom -= (width - 1) / 2;
595 if(width == 1) width = 0;
596 physDev->pen.width = width;
597 oldjoinstyle = physDev->pen.linejoin;
598 if(physDev->pen.type != PS_GEOMETRIC)
599 physDev->pen.linejoin = PS_JOIN_MITER;
601 if ((right > left + width) && (bottom > top + width))
603 if (X11DRV_SetupGCForBrush( dc ))
604 TSXFillRectangle( display, physDev->drawable, physDev->gc,
605 dc->w.DCOrgX + left + (width + 1) / 2,
606 dc->w.DCOrgY + top + (width + 1) / 2,
607 right-left-width-1, bottom-top-width-1);
609 if (X11DRV_SetupGCForPen( dc ))
610 TSXDrawRectangle( display, physDev->drawable, physDev->gc,
611 dc->w.DCOrgX + left, dc->w.DCOrgY + top,
612 right-left-1, bottom-top-1 );
614 physDev->pen.width = oldwidth;
615 physDev->pen.linejoin = oldjoinstyle;
619 /***********************************************************************
623 X11DRV_RoundRect( DC *dc, INT32 left, INT32 top, INT32 right,
624 INT32 bottom, INT32 ell_width, INT32 ell_height )
626 INT32 width, oldwidth, oldendcap;
627 X11DRV_PDEVICE *physDev = (X11DRV_PDEVICE *)dc->physDev;
629 TRACE(graphics, "(%d %d %d %d %d %d\n",
630 left, top, right, bottom, ell_width, ell_height);
632 left = XLPTODP( dc, left );
633 top = YLPTODP( dc, top );
634 right = XLPTODP( dc, right );
635 bottom = YLPTODP( dc, bottom );
637 if ((left == right) || (top == bottom))
640 /* Make sure ell_width and ell_height are >= 1 otherwise XDrawArc gets
641 called with width/height < 0 */
642 ell_width = MAX(abs( ell_width * dc->vportExtX / dc->wndExtX ), 1);
643 ell_height = MAX(abs( ell_height * dc->vportExtY / dc->wndExtY ), 1);
645 /* Fix the coordinates */
647 if (right < left) { INT32 tmp = right; right = left; left = tmp; }
648 if (bottom < top) { INT32 tmp = bottom; bottom = top; top = tmp; }
650 oldwidth = width = physDev->pen.width;
651 oldendcap = physDev->pen.endcap;
652 if (!width) width = 1;
653 if(physDev->pen.style == PS_NULL) width = 0;
655 if ((physDev->pen.style == PS_INSIDEFRAME))
657 if (2*width > (right-left)) width=(right-left + 1)/2;
658 if (2*width > (bottom-top)) width=(bottom-top + 1)/2;
660 right -= (width - 1) / 2;
662 bottom -= (width - 1) / 2;
664 if(width == 0) width = 1;
665 physDev->pen.width = width;
666 physDev->pen.endcap = PS_ENDCAP_SQUARE;
668 if (X11DRV_SetupGCForBrush( dc ))
670 if (ell_width > (right-left) )
671 if (ell_height > (bottom-top) )
672 TSXFillArc( display, physDev->drawable, physDev->gc,
673 dc->w.DCOrgX + left, dc->w.DCOrgY + top,
674 right - left - 1, bottom - top - 1,
677 TSXFillArc( display, physDev->drawable, physDev->gc,
678 dc->w.DCOrgX + left, dc->w.DCOrgY + top,
679 right - left - 1, ell_height, 0, 180 * 64 );
680 TSXFillArc( display, physDev->drawable, physDev->gc,
682 dc->w.DCOrgY + bottom - ell_height - 1,
683 right - left - 1, ell_height, 180 * 64,
686 else if (ell_height > (bottom-top) ){
687 TSXFillArc( display, physDev->drawable, physDev->gc,
688 dc->w.DCOrgX + left, dc->w.DCOrgY + top,
689 ell_width, bottom - top - 1, 90 * 64, 180 * 64 );
690 TSXFillArc( display, physDev->drawable, physDev->gc,
691 dc->w.DCOrgX + right - ell_width -1, dc->w.DCOrgY + top,
692 ell_width, bottom - top - 1, 270 * 64, 180 * 64 );
694 TSXFillArc( display, physDev->drawable, physDev->gc,
695 dc->w.DCOrgX + left, dc->w.DCOrgY + top,
696 ell_width, ell_height, 90 * 64, 90 * 64 );
697 TSXFillArc( display, physDev->drawable, physDev->gc,
699 dc->w.DCOrgY + bottom - ell_height - 1,
700 ell_width, ell_height, 180 * 64, 90 * 64 );
701 TSXFillArc( display, physDev->drawable, physDev->gc,
702 dc->w.DCOrgX + right - ell_width - 1,
703 dc->w.DCOrgY + bottom - ell_height - 1,
704 ell_width, ell_height, 270 * 64, 90 * 64 );
705 TSXFillArc( display, physDev->drawable, physDev->gc,
706 dc->w.DCOrgX + right - ell_width - 1,
708 ell_width, ell_height, 0, 90 * 64 );
710 if (ell_width < right - left)
712 TSXFillRectangle( display, physDev->drawable, physDev->gc,
713 dc->w.DCOrgX + left + (ell_width + 1) / 2,
714 dc->w.DCOrgY + top + 1,
715 right - left - ell_width - 1,
716 (ell_height + 1) / 2 - 1);
717 TSXFillRectangle( display, physDev->drawable, physDev->gc,
718 dc->w.DCOrgX + left + (ell_width + 1) / 2,
719 dc->w.DCOrgY + bottom - (ell_height) / 2 - 1,
720 right - left - ell_width - 1,
723 if (ell_height < bottom - top)
725 TSXFillRectangle( display, physDev->drawable, physDev->gc,
726 dc->w.DCOrgX + left + 1,
727 dc->w.DCOrgY + top + (ell_height + 1) / 2,
729 bottom - top - ell_height - 1);
732 /* FIXME: this could be done with on X call
733 * more efficient and probably more correct
734 * on any X server: XDrawArcs will draw
735 * straight horizontal and vertical lines
736 * if width or height are zero.
738 * BTW this stuff is optimized for an Xfree86 server
739 * read the comments inside the X11DRV_DrawArc function
741 if (X11DRV_SetupGCForPen(dc)) {
742 if (ell_width > (right-left) )
743 if (ell_height > (bottom-top) )
744 TSXDrawArc( display, physDev->drawable, physDev->gc,
745 dc->w.DCOrgX + left, dc->w.DCOrgY + top,
746 right - left - 1, bottom -top - 1, 0 , 360 * 64 );
748 TSXDrawArc( display, physDev->drawable, physDev->gc,
749 dc->w.DCOrgX + left, dc->w.DCOrgY + top,
750 right - left - 1, ell_height - 1, 0 , 180 * 64 );
751 TSXDrawArc( display, physDev->drawable, physDev->gc,
753 dc->w.DCOrgY + bottom - ell_height,
754 right - left - 1, ell_height - 1, 180 * 64 , 180 * 64 );
756 else if (ell_height > (bottom-top) ){
757 TSXDrawArc( display, physDev->drawable, physDev->gc,
758 dc->w.DCOrgX + left, dc->w.DCOrgY + top,
759 ell_width - 1 , bottom - top - 1, 90 * 64 , 180 * 64 );
760 TSXDrawArc( display, physDev->drawable, physDev->gc,
761 dc->w.DCOrgX + right - ell_width,
763 ell_width - 1 , bottom - top - 1, 270 * 64 , 180 * 64 );
765 TSXDrawArc( display, physDev->drawable, physDev->gc,
766 dc->w.DCOrgX + left, dc->w.DCOrgY + top,
767 ell_width - 1, ell_height - 1, 90 * 64, 90 * 64 );
768 TSXDrawArc( display, physDev->drawable, physDev->gc,
769 dc->w.DCOrgX + left, dc->w.DCOrgY + bottom - ell_height,
770 ell_width - 1, ell_height - 1, 180 * 64, 90 * 64 );
771 TSXDrawArc( display, physDev->drawable, physDev->gc,
772 dc->w.DCOrgX + right - ell_width,
773 dc->w.DCOrgY + bottom - ell_height,
774 ell_width - 1, ell_height - 1, 270 * 64, 90 * 64 );
775 TSXDrawArc( display, physDev->drawable, physDev->gc,
776 dc->w.DCOrgX + right - ell_width, dc->w.DCOrgY + top,
777 ell_width - 1, ell_height - 1, 0, 90 * 64 );
779 if (ell_width < right - left)
781 TSXDrawLine( display, physDev->drawable, physDev->gc,
782 dc->w.DCOrgX + left + ell_width / 2,
784 dc->w.DCOrgX + right - (ell_width+1) / 2,
786 TSXDrawLine( display, physDev->drawable, physDev->gc,
787 dc->w.DCOrgX + left + ell_width / 2 ,
788 dc->w.DCOrgY + bottom - 1,
789 dc->w.DCOrgX + right - (ell_width+1)/ 2,
790 dc->w.DCOrgY + bottom - 1);
792 if (ell_height < bottom - top)
794 TSXDrawLine( display, physDev->drawable, physDev->gc,
795 dc->w.DCOrgX + right - 1,
796 dc->w.DCOrgY + top + ell_height / 2,
797 dc->w.DCOrgX + right - 1,
798 dc->w.DCOrgY + bottom - (ell_height+1) / 2);
799 TSXDrawLine( display, physDev->drawable, physDev->gc,
801 dc->w.DCOrgY + top + ell_height / 2,
803 dc->w.DCOrgY + bottom - (ell_height+1) / 2);
806 physDev->pen.width = oldwidth;
807 physDev->pen.endcap = oldendcap;
812 /***********************************************************************
816 X11DRV_SetPixel( DC *dc, INT32 x, INT32 y, COLORREF color )
819 X11DRV_PDEVICE *physDev = (X11DRV_PDEVICE *)dc->physDev;
821 x = dc->w.DCOrgX + XLPTODP( dc, x );
822 y = dc->w.DCOrgY + YLPTODP( dc, y );
823 pixel = COLOR_ToPhysical( dc, color );
825 TSXSetForeground( display, physDev->gc, pixel );
826 TSXSetFunction( display, physDev->gc, GXcopy );
827 TSXDrawPoint( display, physDev->drawable, physDev->gc, x, y );
829 /* inefficient but simple... */
831 return COLOR_ToLogical(pixel);
835 /***********************************************************************
839 X11DRV_GetPixel( DC *dc, INT32 x, INT32 y )
841 static Pixmap pixmap = 0;
844 X11DRV_PDEVICE *physDev = (X11DRV_PDEVICE *)dc->physDev;
846 x = dc->w.DCOrgX + XLPTODP( dc, x );
847 y = dc->w.DCOrgY + YLPTODP( dc, y );
848 EnterCriticalSection( &X11DRV_CritSection );
849 if (dc->w.flags & DC_MEMORY)
851 image = XGetImage( display, physDev->drawable, x, y, 1, 1,
852 AllPlanes, ZPixmap );
856 /* If we are reading from the screen, use a temporary copy */
857 /* to avoid a BadMatch error */
858 if (!pixmap) pixmap = XCreatePixmap( display, rootWindow,
859 1, 1, dc->w.bitsPerPixel );
860 XCopyArea( display, physDev->drawable, pixmap, BITMAP_colorGC,
862 image = XGetImage( display, pixmap, 0, 0, 1, 1, AllPlanes, ZPixmap );
864 pixel = XGetPixel( image, 0, 0 );
865 XDestroyImage( image );
866 LeaveCriticalSection( &X11DRV_CritSection );
868 return COLOR_ToLogical(pixel);
872 /***********************************************************************
876 X11DRV_PaintRgn( DC *dc, HRGN32 hrgn )
879 HRGN32 tmpVisRgn, prevVisRgn;
880 HDC32 hdc = dc->hSelf; /* FIXME: should not mix dc/hdc this way */
881 X11DRV_PDEVICE *physDev = (X11DRV_PDEVICE *)dc->physDev;
883 if (!(tmpVisRgn = CreateRectRgn32( 0, 0, 0, 0 ))) return FALSE;
885 /* Transform region into device co-ords */
886 if ( !REGION_LPTODP( hdc, tmpVisRgn, hrgn )
887 || OffsetRgn32( tmpVisRgn, dc->w.DCOrgX, dc->w.DCOrgY ) == ERROR) {
888 DeleteObject32( tmpVisRgn );
892 /* Modify visible region */
893 if (!(prevVisRgn = SaveVisRgn( hdc ))) {
894 DeleteObject32( tmpVisRgn );
897 CombineRgn32( tmpVisRgn, prevVisRgn, tmpVisRgn, RGN_AND );
898 SelectVisRgn( hdc, tmpVisRgn );
899 DeleteObject32( tmpVisRgn );
901 /* Fill the region */
903 GetRgnBox32( dc->w.hGCClipRgn, &box );
904 if (X11DRV_SetupGCForBrush( dc ))
905 TSXFillRectangle( display, physDev->drawable, physDev->gc,
907 box.right-box.left, box.bottom-box.top );
909 /* Restore the visible region */
911 RestoreVisRgn( hdc );
915 /**********************************************************************
919 X11DRV_Polyline( DC *dc, const POINT32* pt, INT32 count )
924 X11DRV_PDEVICE *physDev = (X11DRV_PDEVICE *)dc->physDev;
926 if((oldwidth = physDev->pen.width) == 0) physDev->pen.width = 1;
928 points = (XPoint *) xmalloc (sizeof (XPoint) * (count));
929 for (i = 0; i < count; i++)
931 points[i].x = dc->w.DCOrgX + XLPTODP( dc, pt[i].x );
932 points[i].y = dc->w.DCOrgY + YLPTODP( dc, pt[i].y );
935 if (X11DRV_SetupGCForPen ( dc ))
936 TSXDrawLines( display, physDev->drawable, physDev->gc,
937 points, count, CoordModeOrigin );
940 physDev->pen.width = oldwidth;
945 /**********************************************************************
949 X11DRV_Polygon( DC *dc, const POINT32* pt, INT32 count )
953 X11DRV_PDEVICE *physDev = (X11DRV_PDEVICE *)dc->physDev;
955 points = (XPoint *) xmalloc (sizeof (XPoint) * (count+1));
956 for (i = 0; i < count; i++)
958 points[i].x = dc->w.DCOrgX + XLPTODP( dc, pt[i].x );
959 points[i].y = dc->w.DCOrgY + YLPTODP( dc, pt[i].y );
961 points[count] = points[0];
963 if (X11DRV_SetupGCForBrush( dc ))
964 TSXFillPolygon( display, physDev->drawable, physDev->gc,
965 points, count+1, Complex, CoordModeOrigin);
967 if (X11DRV_SetupGCForPen ( dc ))
968 TSXDrawLines( display, physDev->drawable, physDev->gc,
969 points, count+1, CoordModeOrigin );
976 /**********************************************************************
980 X11DRV_PolyPolygon( DC *dc, const POINT32* pt, const INT32* counts, UINT32 polygons)
983 X11DRV_PDEVICE *physDev = (X11DRV_PDEVICE *)dc->physDev;
985 /* FIXME: The points should be converted to device coords before */
986 /* creating the region. */
988 hrgn = CreatePolyPolygonRgn32( pt, counts, polygons, dc->w.polyFillMode );
989 X11DRV_PaintRgn( dc, hrgn );
990 DeleteObject32( hrgn );
992 /* Draw the outline of the polygons */
994 if (X11DRV_SetupGCForPen ( dc ))
999 for (i = 0; i < polygons; i++) if (counts[i] > max) max = counts[i];
1000 points = (XPoint *) xmalloc( sizeof(XPoint) * (max+1) );
1002 for (i = 0; i < polygons; i++)
1004 for (j = 0; j < counts[i]; j++)
1006 points[j].x = dc->w.DCOrgX + XLPTODP( dc, pt->x );
1007 points[j].y = dc->w.DCOrgY + YLPTODP( dc, pt->y );
1010 points[j] = points[0];
1011 TSXDrawLines( display, physDev->drawable, physDev->gc,
1012 points, j + 1, CoordModeOrigin );
1020 /**********************************************************************
1021 * X11DRV_PolyPolyline
1024 X11DRV_PolyPolyline( DC *dc, const POINT32* pt, const DWORD* counts, DWORD polylines )
1026 X11DRV_PDEVICE *physDev = (X11DRV_PDEVICE *)dc->physDev;
1027 if (X11DRV_SetupGCForPen ( dc ))
1032 for (i = 0; i < polylines; i++) if (counts[i] > max) max = counts[i];
1033 points = (XPoint *) xmalloc( sizeof(XPoint) * (max+1) );
1035 for (i = 0; i < polylines; i++)
1037 for (j = 0; j < counts[i]; j++)
1039 points[j].x = dc->w.DCOrgX + XLPTODP( dc, pt->x );
1040 points[j].y = dc->w.DCOrgY + YLPTODP( dc, pt->y );
1043 points[j] = points[0];
1044 TSXDrawLines( display, physDev->drawable, physDev->gc,
1045 points, j + 1, CoordModeOrigin );
1053 /**********************************************************************
1054 * X11DRV_InternalFloodFill
1056 * Internal helper function for flood fill.
1057 * (xorg,yorg) is the origin of the X image relative to the drawable.
1058 * (x,y) is relative to the origin of the X image.
1060 static void X11DRV_InternalFloodFill(XImage *image, DC *dc,
1063 Pixel pixel, WORD fillType )
1065 X11DRV_PDEVICE *physDev = (X11DRV_PDEVICE *)dc->physDev;
1068 #define TO_FLOOD(x,y) ((fillType == FLOODFILLBORDER) ? \
1069 (XGetPixel(image,x,y) != pixel) : \
1070 (XGetPixel(image,x,y) == pixel))
1072 if (!TO_FLOOD(x,y)) return;
1074 /* Find left and right boundaries */
1077 while ((left > 0) && TO_FLOOD( left-1, y )) left--;
1078 while ((right < image->width) && TO_FLOOD( right, y )) right++;
1079 XFillRectangle( display, physDev->drawable, physDev->gc,
1080 xOrg + left, yOrg + y, right-left, 1 );
1082 /* Set the pixels of this line so we don't fill it again */
1084 for (x = left; x < right; x++)
1086 if (fillType == FLOODFILLBORDER) XPutPixel( image, x, y, pixel );
1087 else XPutPixel( image, x, y, ~pixel );
1090 /* Fill the line above */
1097 while ((x < right) && !TO_FLOOD(x,y)) x++;
1098 if (x >= right) break;
1099 while ((x < right) && TO_FLOOD(x,y)) x++;
1100 X11DRV_InternalFloodFill(image, dc, x-1, y,
1101 xOrg, yOrg, pixel, fillType );
1105 /* Fill the line below */
1107 if ((y += 2) < image->height)
1112 while ((x < right) && !TO_FLOOD(x,y)) x++;
1113 if (x >= right) break;
1114 while ((x < right) && TO_FLOOD(x,y)) x++;
1115 X11DRV_InternalFloodFill(image, dc, x-1, y,
1116 xOrg, yOrg, pixel, fillType );
1123 /**********************************************************************
1124 * X11DRV_DoFloodFill
1126 * Main flood-fill routine.
1128 * The Xlib critical section must be entered before calling this function.
1131 struct FloodFill_params
1140 static BOOL32 X11DRV_DoFloodFill( const struct FloodFill_params *params )
1144 DC *dc = params->dc;
1145 X11DRV_PDEVICE *physDev = (X11DRV_PDEVICE *)dc->physDev;
1147 if (GetRgnBox32( dc->w.hGCClipRgn, &rect ) == ERROR) return FALSE;
1149 if (!(image = XGetImage( display, physDev->drawable,
1152 rect.right - rect.left,
1153 rect.bottom - rect.top,
1154 AllPlanes, ZPixmap ))) return FALSE;
1156 if (X11DRV_SetupGCForBrush( dc ))
1158 /* ROP mode is always GXcopy for flood-fill */
1159 XSetFunction( display, physDev->gc, GXcopy );
1160 X11DRV_InternalFloodFill(image, dc,
1161 XLPTODP(dc,params->x) + dc->w.DCOrgX - rect.left,
1162 YLPTODP(dc,params->y) + dc->w.DCOrgY - rect.top,
1165 COLOR_ToPhysical( dc, params->color ),
1169 XDestroyImage( image );
1174 /**********************************************************************
1175 * X11DRV_ExtFloodFill
1178 X11DRV_ExtFloodFill( DC *dc, INT32 x, INT32 y, COLORREF color,
1182 struct FloodFill_params params = { dc, x, y, color, fillType };
1184 TRACE(graphics, "X11DRV_ExtFloodFill %d,%d %06lx %d\n",
1185 x, y, color, fillType );
1187 if (!PtVisible32( dc->hSelf, x, y )) return FALSE;
1188 EnterCriticalSection( &X11DRV_CritSection );
1189 result = CALL_LARGE_STACK( X11DRV_DoFloodFill, ¶ms );
1190 LeaveCriticalSection( &X11DRV_CritSection );
1194 /******************************************************************
1196 * *Very* simple bezier drawing code,
1198 * It uses a recursive algorithm to divide the curve in a series
1199 * of straight line segements. Not ideal but for me sufficient.
1200 * If you are in need for something better look for some incremental
1203 * 7 July 1998 Rein Klazes
1207 * some macro definitions for bezier drawing
1209 * to avoid trucation errors the coordinates are
1210 * shifted upwards. When used in drawing they are
1211 * shifted down again, including correct rounding
1212 * and avoiding floating point arithmatic
1213 * 4 bits should allow 27 bits coordinates which I saw
1214 * somewere in the win32 doc's
1218 #define BEZIERSHIFTBITS 4
1219 #define BEZIERSHIFTUP(x) ((x)<<BEZIERSHIFTBITS)
1220 #define BEZIERPIXEL BEZIERSHIFTUP(1)
1221 #define BEZIERSHIFTDOWN(x) (((x)+(1<<(BEZIERSHIFTBITS-1)))>>BEZIERSHIFTBITS)
1222 /* maximum depth of recursion */
1223 #define BEZIERMAXDEPTH 8
1225 /* size of array to store points on */
1226 /* enough for one curve */
1227 #define BEZMAXPOINTS (150)
1229 /* calculate Bezier average, in this case the middle
1230 * correctly rounded...
1233 #define BEZIERMIDDLE(Mid, P1, P2) \
1234 (Mid).x=((P1).x+(P2).x + 1)/2;\
1235 (Mid).y=((P1).y+(P2).y + 1)/2;
1237 /**********************************************************
1238 * BezierCheck helper function to check
1239 * that recursion can be terminated
1240 * Points[0] and Points[3] are begin and endpoint
1241 * Points[1] and Points[2] are control points
1242 * level is the recursion depth
1243 * returns true if the recusion can be terminated
1245 static BOOL32 BezierCheck( int level, POINT32 *Points)
1248 dx=Points[3].x-Points[0].x;
1249 dy=Points[3].y-Points[0].y;
1250 if(ABS(dy)<=ABS(dx)){/* shallow line */
1251 /* check that control points are between begin and end */
1252 if(Points[1].x < Points[0].x){
1253 if(Points[1].x < Points[3].x)
1256 if(Points[1].x > Points[3].x)
1258 if(Points[2].x < Points[0].x){
1259 if(Points[2].x < Points[3].x)
1262 if(Points[2].x > Points[3].x)
1264 dx=BEZIERSHIFTDOWN(dx);
1265 if(!dx) return TRUE;
1266 if(abs(Points[1].y-Points[0].y-(dy/dx)*
1267 BEZIERSHIFTDOWN(Points[1].x-Points[0].x)) > BEZIERPIXEL ||
1268 abs(Points[2].y-Points[0].y-(dy/dx)*
1269 BEZIERSHIFTDOWN(Points[2].x-Points[0].x)) > BEZIERPIXEL )
1273 }else{ /* steep line */
1274 /* check that control points are between begin and end */
1275 if(Points[1].y < Points[0].y){
1276 if(Points[1].y < Points[3].y)
1279 if(Points[1].y > Points[3].y)
1281 if(Points[2].y < Points[0].y){
1282 if(Points[2].y < Points[3].y)
1285 if(Points[2].y > Points[3].y)
1287 dy=BEZIERSHIFTDOWN(dy);
1288 if(!dy) return TRUE;
1289 if(abs(Points[1].x-Points[0].x-(dx/dy)*
1290 BEZIERSHIFTDOWN(Points[1].y-Points[0].y)) > BEZIERPIXEL ||
1291 abs(Points[2].x-Points[0].x-(dx/dy)*
1292 BEZIERSHIFTDOWN(Points[2].y-Points[0].y)) > BEZIERPIXEL )
1299 /***********************************************************************
1301 * Draw a -what microsoft calls- bezier curve
1302 * The routine recursively devides the curve
1303 * in two parts until a straight line can be drawn
1305 * level recusion depth counted backwards
1307 * Points array of begin(0), end(3) and control points(1 and 2)
1308 * XPoints array with points calculated sofar
1309 * *pIx nr points calculated sofar
1312 static void X11DRV_Bezier(int level, DC * dc, POINT32 *Points,
1313 XPoint* xpoints, unsigned int* pIx)
1315 X11DRV_PDEVICE *physDev = (X11DRV_PDEVICE *)dc->physDev;
1317 if(*pIx == BEZMAXPOINTS){
1318 TSXDrawLines( display, physDev->drawable, physDev->gc,
1319 xpoints, *pIx, CoordModeOrigin );
1322 if(!level || BezierCheck(level, Points)) {
1324 xpoints[*pIx].x= dc->w.DCOrgX + BEZIERSHIFTDOWN(Points[0].x);
1325 xpoints[*pIx].y= dc->w.DCOrgY + BEZIERSHIFTDOWN(Points[0].y);
1328 xpoints[*pIx].x= dc->w.DCOrgX + BEZIERSHIFTDOWN(Points[3].x);
1329 xpoints[*pIx].y= dc->w.DCOrgY + BEZIERSHIFTDOWN(Points[3].y);
1332 POINT32 Points2[4]; /* for the second recursive call */
1333 Points2[3]=Points[3];
1334 BEZIERMIDDLE(Points2[2], Points[2], Points[3]);
1335 BEZIERMIDDLE(Points2[0], Points[1], Points[2]);
1336 BEZIERMIDDLE(Points2[1],Points2[0],Points2[2]);
1338 BEZIERMIDDLE(Points[1], Points[0], Points[1]);
1339 BEZIERMIDDLE(Points[2], Points[1], Points2[0]);
1340 BEZIERMIDDLE(Points[3], Points[2], Points2[1]);
1342 Points2[0]=Points[3];
1344 /* do the two halves */
1345 X11DRV_Bezier(level-1, dc, Points, xpoints, pIx);
1346 X11DRV_Bezier(level-1, dc, Points2, xpoints, pIx);
1350 /***********************************************************************
1352 * Implement functionality for PolyBezier and PolyBezierTo
1354 * [i] dc pointer to device context
1355 * [i] start, first point in curve
1356 * [i] BezierPoints , array of point filled with rest of the points
1357 * [i] count, number of points in BezierPoints, must be a
1361 X11DRV_PolyBezier(DC *dc, POINT32 start, const POINT32* BezierPoints, DWORD count)
1367 X11DRV_PDEVICE *physDev = (X11DRV_PDEVICE *)dc->physDev;
1369 TRACE(graphics, "dc=%04x count=%ld %d,%d - %d,%d - %d,%d -%d,%d \n",
1372 (Points+0)->x, (Points+0)->y,
1373 (Points+1)->x, (Points+1)->y,
1374 (Points+2)->x, (Points+2)->y);
1375 if(!count || count % 3){/* paranoid */
1376 WARN(graphics," bad value for count : %ld\n", count);
1379 xpoints=(XPoint*) xmalloc( sizeof(XPoint)*BEZMAXPOINTS);
1380 Points[3].x=BEZIERSHIFTUP(XLPTODP(dc,start.x));
1381 Points[3].y=BEZIERSHIFTUP(YLPTODP(dc,start.y));
1383 Points[0]=Points[3];
1385 Points[i].x= BEZIERSHIFTUP(XLPTODP(dc,BezierPoints->x));
1386 Points[i].y= BEZIERSHIFTUP(YLPTODP(dc,BezierPoints->y));
1389 X11DRV_Bezier(BEZIERMAXDEPTH , dc, Points, xpoints, &ix );
1392 if( ix) TSXDrawLines( display, physDev->drawable, physDev->gc,
1393 xpoints, ix, CoordModeOrigin );
1398 /**********************************************************************
1402 X11DRV_SetBkColor( DC *dc, COLORREF color )
1404 X11DRV_PDEVICE *physDev = (X11DRV_PDEVICE *)dc->physDev;
1407 oldColor = dc->w.backgroundColor;
1408 dc->w.backgroundColor = color;
1410 physDev->backgroundPixel = COLOR_ToPhysical( dc, color );
1415 /**********************************************************************
1416 * X11DRV_SetTextColor
1419 X11DRV_SetTextColor( DC *dc, COLORREF color )
1421 X11DRV_PDEVICE *physDev = (X11DRV_PDEVICE *)dc->physDev;
1424 oldColor = dc->w.textColor;
1425 dc->w.textColor = color;
1427 physDev->textPixel = COLOR_ToPhysical( dc, color );