2 * X11 graphics driver graphics functions
4 * Copyright 1993,1994 Alexandre Julliard
9 * FIXME: none of these functions obey the GM_ADVANCED
20 #include <X11/Intrinsic.h>
41 #define ABS(x) ((x)<0?(-(x)):(x))
42 /**********************************************************************
46 X11DRV_MoveToEx(DC *dc,INT32 x,INT32 y,LPPOINT32 pt) {
49 pt->x = dc->w.CursPosX;
50 pt->y = dc->w.CursPosY;
57 /***********************************************************************
61 X11DRV_LineTo( DC *dc, INT32 x, INT32 y )
63 if (DC_SetupGCForPen( dc ))
64 TSXDrawLine(display, dc->u.x.drawable, dc->u.x.gc,
65 dc->w.DCOrgX + XLPTODP( dc, dc->w.CursPosX ),
66 dc->w.DCOrgY + YLPTODP( dc, dc->w.CursPosY ),
67 dc->w.DCOrgX + XLPTODP( dc, x ),
68 dc->w.DCOrgY + YLPTODP( dc, y ) );
76 /***********************************************************************
79 * Helper functions for Arc(), Chord() and Pie().
80 * 'lines' is the number of lines to draw: 0 for Arc, 1 for Chord, 2 for Pie.
84 X11DRV_DrawArc( DC *dc, INT32 left, INT32 top, INT32 right,
85 INT32 bottom, INT32 xstart, INT32 ystart,
86 INT32 xend, INT32 yend, INT32 lines )
88 INT32 xcenter, ycenter, istart_angle, idiff_angle;
89 INT32 width, oldwidth, oldendcap;
90 double start_angle, end_angle;
93 left = XLPTODP( dc, left );
94 top = YLPTODP( dc, top );
95 right = XLPTODP( dc, right );
96 bottom = YLPTODP( dc, bottom );
97 xstart = XLPTODP( dc, xstart );
98 ystart = YLPTODP( dc, ystart );
99 xend = XLPTODP( dc, xend );
100 yend = YLPTODP( dc, yend );
102 if (right < left) { INT32 tmp = right; right = left; left = tmp; }
103 if (bottom < top) { INT32 tmp = bottom; bottom = top; top = tmp; }
104 if ((left == right) || (top == bottom)
105 ||(lines && ((right-left==1)||(bottom-top==1)))) return TRUE;
107 oldwidth = width = dc->u.x.pen.width;
108 oldendcap= dc->u.x.pen.endcap;
109 if (!width) width = 1;
110 if(dc->u.x.pen.style == PS_NULL) width = 0;
112 if ((dc->u.x.pen.style == PS_INSIDEFRAME))
114 if (2*width > (right-left)) width=(right-left + 1)/2;
115 if (2*width > (bottom-top)) width=(bottom-top + 1)/2;
117 right -= (width - 1) / 2;
119 bottom -= (width - 1) / 2;
121 if(width == 0) width=1; /* more accurate */
122 dc->u.x.pen.width=width;
123 dc->u.x.pen.endcap=PS_ENDCAP_SQUARE;
125 xcenter = (right + left) / 2;
126 ycenter = (bottom + top) / 2;
127 start_angle = atan2( (double)(ycenter-ystart)*(right-left),
128 (double)(xstart-xcenter)*(bottom-top) );
129 end_angle = atan2( (double)(ycenter-yend)*(right-left),
130 (double)(xend-xcenter)*(bottom-top) );
131 if ((xstart==xend)&&(ystart==yend))
132 { /* A lazy program delivers xstart=xend=ystart=yend=0) */
136 else /* notorious cases */
137 if ((start_angle == PI)&&( end_angle <0))
140 if ((end_angle == PI)&&( start_angle <0))
142 istart_angle = (INT32)(start_angle * 180 * 64 / PI + 0.5);
143 idiff_angle = (INT32)((end_angle - start_angle) * 180 * 64 / PI + 0.5);
144 if (idiff_angle <= 0) idiff_angle += 360 * 64;
146 /* Fill arc with brush if Chord() or Pie() */
148 if ((lines > 0) && DC_SetupGCForBrush( dc )) {
149 TSXSetArcMode( display, dc->u.x.gc, (lines==1) ? ArcChord : ArcPieSlice);
150 TSXFillArc( display, dc->u.x.drawable, dc->u.x.gc,
151 dc->w.DCOrgX + left, dc->w.DCOrgY + top,
152 right-left-1, bottom-top-1, istart_angle, idiff_angle );
155 /* Draw arc and lines */
157 if (DC_SetupGCForPen( dc )){
158 TSXDrawArc( display, dc->u.x.drawable, dc->u.x.gc,
159 dc->w.DCOrgX + left, dc->w.DCOrgY + top,
160 right-left-1, bottom-top-1, istart_angle, idiff_angle );
162 /* use the truncated values */
163 start_angle=(double)istart_angle*PI/64./180.;
164 end_angle=(double)(istart_angle+idiff_angle)*PI/64./180.;
165 /* calculate the endpoints and round correctly */
166 points[0].x = (int) floor(dc->w.DCOrgX + (right+left)/2.0 +
167 cos(start_angle) * (right-left-width*2+2) / 2. + 0.5);
168 points[0].y = (int) floor(dc->w.DCOrgY + (top+bottom)/2.0 -
169 sin(start_angle) * (bottom-top-width*2+2) / 2. + 0.5);
170 points[1].x = (int) floor(dc->w.DCOrgX + (right+left)/2.0 +
171 cos(end_angle) * (right-left-width*2+2) / 2. + 0.5);
172 points[1].y = (int) floor(dc->w.DCOrgY + (top+bottom)/2.0 -
173 sin(end_angle) * (bottom-top-width*2+2) / 2. + 0.5);
175 /* OK this stuff is optimized for Xfree86
176 * which is probably the most used server by
177 * wine users. Other X servers will not
178 * display correctly. (eXceed for instance)
179 * so if you feel you must change make sure that
180 * you either use Xfree86 or seperate your changes
181 * from these (compile switch or whatever)
185 points[3] = points[1];
186 points[1].x = dc->w.DCOrgX + xcenter;
187 points[1].y = dc->w.DCOrgY + ycenter;
188 points[2] = points[1];
189 dx1=points[1].x-points[0].x;
190 dy1=points[1].y-points[0].y;
191 if(((top-bottom) | -2) == -2)
192 if(dy1>0) points[1].y--;
194 if (((-dx1)*64)<=ABS(dy1)*37) points[0].x--;
195 if(((-dx1*9))<(dy1*16)) points[0].y--;
196 if( dy1<0 && ((dx1*9)) < (dy1*16)) points[0].y--;
198 if(dy1 < 0) points[0].y--;
199 if(((right-left) | -2) == -2) points[1].x--;
201 dx1=points[3].x-points[2].x;
202 dy1=points[3].y-points[2].y;
203 if(((top-bottom) | -2 ) == -2)
204 if(dy1 < 0) points[2].y--;
206 if( dy1>0) points[3].y--;
207 if(((right-left) | -2) == -2 ) points[2].x--;
210 if( dx1 * 64 < dy1 * -37 ) points[3].x--;
214 TSXDrawLines( display, dc->u.x.drawable, dc->u.x.gc,
215 points, lines+1, CoordModeOrigin );
218 dc->u.x.pen.width=oldwidth;
219 dc->u.x.pen.endcap=oldendcap;
224 /***********************************************************************
228 X11DRV_Arc( DC *dc, INT32 left, INT32 top, INT32 right, INT32 bottom,
229 INT32 xstart, INT32 ystart, INT32 xend, INT32 yend )
231 return X11DRV_DrawArc( dc, left, top, right, bottom,
232 xstart, ystart, xend, yend, 0 );
236 /***********************************************************************
240 X11DRV_Pie( DC *dc, INT32 left, INT32 top, INT32 right, INT32 bottom,
241 INT32 xstart, INT32 ystart, INT32 xend, INT32 yend )
243 return X11DRV_DrawArc( dc, left, top, right, bottom,
244 xstart, ystart, xend, yend, 2 );
247 /***********************************************************************
251 X11DRV_Chord( DC *dc, INT32 left, INT32 top, INT32 right, INT32 bottom,
252 INT32 xstart, INT32 ystart, INT32 xend, INT32 yend )
254 return X11DRV_DrawArc( dc, left, top, right, bottom,
255 xstart, ystart, xend, yend, 1 );
259 /***********************************************************************
263 X11DRV_Ellipse( DC *dc, INT32 left, INT32 top, INT32 right, INT32 bottom )
265 INT32 width, oldwidth;
266 left = XLPTODP( dc, left );
267 top = YLPTODP( dc, top );
268 right = XLPTODP( dc, right );
269 bottom = YLPTODP( dc, bottom );
270 if ((left == right) || (top == bottom)) return TRUE;
272 if (right < left) { INT32 tmp = right; right = left; left = tmp; }
273 if (bottom < top) { INT32 tmp = bottom; bottom = top; top = tmp; }
275 oldwidth = width = dc->u.x.pen.width;
276 if (!width) width = 1;
277 if(dc->u.x.pen.style == PS_NULL) width = 0;
279 if ((dc->u.x.pen.style == PS_INSIDEFRAME))
281 if (2*width > (right-left)) width=(right-left + 1)/2;
282 if (2*width > (bottom-top)) width=(bottom-top + 1)/2;
284 right -= (width - 1) / 2;
286 bottom -= (width - 1) / 2;
288 if(width == 0) width=1; /* more accurate */
289 dc->u.x.pen.width=width;
291 if (DC_SetupGCForBrush( dc ))
292 TSXFillArc( display, dc->u.x.drawable, dc->u.x.gc,
293 dc->w.DCOrgX + left, dc->w.DCOrgY + top,
294 right-left-1, bottom-top-1, 0, 360*64 );
295 if (DC_SetupGCForPen( dc ))
296 TSXDrawArc( display, dc->u.x.drawable, dc->u.x.gc,
297 dc->w.DCOrgX + left, dc->w.DCOrgY + top,
298 right-left-1, bottom-top-1, 0, 360*64 );
299 dc->u.x.pen.width=oldwidth;
304 /***********************************************************************
308 X11DRV_Rectangle(DC *dc, INT32 left, INT32 top, INT32 right, INT32 bottom)
310 INT32 width, oldwidth, oldjoinstyle;
312 TRACE(graphics, "(%d %d %d %d)\n",
313 left, top, right, bottom);
315 left = XLPTODP( dc, left );
316 top = YLPTODP( dc, top );
317 right = XLPTODP( dc, right );
318 bottom = YLPTODP( dc, bottom );
320 if ((left == right) || (top == bottom)) return TRUE;
322 if (right < left) { INT32 tmp = right; right = left; left = tmp; }
323 if (bottom < top) { INT32 tmp = bottom; bottom = top; top = tmp; }
325 oldwidth = width = dc->u.x.pen.width;
326 if (!width) width = 1;
327 if(dc->u.x.pen.style == PS_NULL) width = 0;
329 if ((dc->u.x.pen.style == PS_INSIDEFRAME))
331 if (2*width > (right-left)) width=(right-left + 1)/2;
332 if (2*width > (bottom-top)) width=(bottom-top + 1)/2;
334 right -= (width - 1) / 2;
336 bottom -= (width - 1) / 2;
338 if(width == 1) width=0;
339 dc->u.x.pen.width=width;
340 oldjoinstyle=dc->u.x.pen.linejoin;
341 if(dc->u.x.pen.type!=PS_GEOMETRIC)
342 dc->u.x.pen.linejoin=PS_JOIN_MITER;
344 if ((right > left + width) && (bottom > top + width))
346 if (DC_SetupGCForBrush( dc ))
347 TSXFillRectangle( display, dc->u.x.drawable, dc->u.x.gc,
348 dc->w.DCOrgX + left + (width + 1) / 2,
349 dc->w.DCOrgY + top + (width + 1) / 2,
350 right-left-width-1, bottom-top-width-1);
352 if (DC_SetupGCForPen( dc ))
353 TSXDrawRectangle( display, dc->u.x.drawable, dc->u.x.gc,
354 dc->w.DCOrgX + left, dc->w.DCOrgY + top,
355 right-left-1, bottom-top-1 );
357 dc->u.x.pen.width=oldwidth;
358 dc->u.x.pen.linejoin=oldjoinstyle;
362 /***********************************************************************
366 X11DRV_RoundRect( DC *dc, INT32 left, INT32 top, INT32 right,
367 INT32 bottom, INT32 ell_width, INT32 ell_height )
369 INT32 width, oldwidth, oldendcap;
371 TRACE(graphics, "(%d %d %d %d %d %d\n",
372 left, top, right, bottom, ell_width, ell_height);
374 left = XLPTODP( dc, left );
375 top = YLPTODP( dc, top );
376 right = XLPTODP( dc, right );
377 bottom = YLPTODP( dc, bottom );
379 if ((left == right) || (top == bottom))
382 /* Make sure ell_width and ell_height are >= 1 otherwise XDrawArc gets
383 called with width/height < 0 */
384 ell_width = MAX(abs( ell_width * dc->vportExtX / dc->wndExtX ), 1);
385 ell_height = MAX(abs( ell_height * dc->vportExtY / dc->wndExtY ), 1);
387 /* Fix the coordinates */
389 if (right < left) { INT32 tmp = right; right = left; left = tmp; }
390 if (bottom < top) { INT32 tmp = bottom; bottom = top; top = tmp; }
392 oldwidth=width = dc->u.x.pen.width;
393 oldendcap = dc->u.x.pen.endcap;
394 if (!width) width = 1;
395 if(dc->u.x.pen.style == PS_NULL) width = 0;
397 if ((dc->u.x.pen.style == PS_INSIDEFRAME))
399 if (2*width > (right-left)) width=(right-left + 1)/2;
400 if (2*width > (bottom-top)) width=(bottom-top + 1)/2;
402 right -= (width - 1) / 2;
404 bottom -= (width - 1) / 2;
406 if(width == 0) width=1;
407 dc->u.x.pen.width=width;
408 dc->u.x.pen.endcap=PS_ENDCAP_SQUARE;
410 if (DC_SetupGCForBrush( dc ))
412 if (ell_width > (right-left) )
413 if (ell_height > (bottom-top) )
414 TSXFillArc( display, dc->u.x.drawable, dc->u.x.gc,
415 dc->w.DCOrgX + left, dc->w.DCOrgY + top,
416 right - left - 1, bottom - top - 1,
419 TSXFillArc( display, dc->u.x.drawable, dc->u.x.gc,
420 dc->w.DCOrgX + left, dc->w.DCOrgY + top,
421 right - left - 1, ell_height, 0, 180 * 64 );
422 TSXFillArc( display, dc->u.x.drawable, dc->u.x.gc,
424 dc->w.DCOrgY + bottom - ell_height - 1,
425 right - left - 1, ell_height, 180 * 64, 180 * 64 );
427 else if (ell_height > (bottom-top) ){
428 TSXFillArc( display, dc->u.x.drawable, dc->u.x.gc,
429 dc->w.DCOrgX + left, dc->w.DCOrgY + top,
430 ell_width, bottom - top - 1, 90 * 64, 180 * 64 );
431 TSXFillArc( display, dc->u.x.drawable, dc->u.x.gc,
432 dc->w.DCOrgX + right - ell_width -1, dc->w.DCOrgY + top,
433 ell_width, bottom - top - 1, 270 * 64, 180 * 64 );
435 TSXFillArc( display, dc->u.x.drawable, dc->u.x.gc,
436 dc->w.DCOrgX + left, dc->w.DCOrgY + top,
437 ell_width, ell_height, 90 * 64, 90 * 64 );
438 TSXFillArc( display, dc->u.x.drawable, dc->u.x.gc,
440 dc->w.DCOrgY + bottom - ell_height - 1,
441 ell_width, ell_height, 180 * 64, 90 * 64 );
442 TSXFillArc( display, dc->u.x.drawable, dc->u.x.gc,
443 dc->w.DCOrgX + right - ell_width - 1,
444 dc->w.DCOrgY + bottom - ell_height - 1,
445 ell_width, ell_height, 270 * 64, 90 * 64 );
446 TSXFillArc( display, dc->u.x.drawable, dc->u.x.gc,
447 dc->w.DCOrgX + right - ell_width - 1,
449 ell_width, ell_height, 0, 90 * 64 );
451 if (ell_width < right - left)
453 TSXFillRectangle( display, dc->u.x.drawable, dc->u.x.gc,
454 dc->w.DCOrgX + left + (ell_width + 1) / 2,
455 dc->w.DCOrgY + top + 1,
456 right - left - ell_width - 1,
457 (ell_height + 1) / 2 - 1);
458 TSXFillRectangle( display, dc->u.x.drawable, dc->u.x.gc,
459 dc->w.DCOrgX + left + (ell_width + 1) / 2,
460 dc->w.DCOrgY + bottom - (ell_height) / 2 - 1,
461 right - left - ell_width - 1,
464 if (ell_height < bottom - top)
466 TSXFillRectangle( display, dc->u.x.drawable, dc->u.x.gc,
467 dc->w.DCOrgX + left + 1,
468 dc->w.DCOrgY + top + (ell_height + 1) / 2,
470 bottom - top - ell_height - 1);
473 /* FIXME: this could be done with on X call
474 * more efficient and probably more correct
475 * on any X server: XDrawArcs will draw
476 * straight horizontal and vertical lines
477 * if width or height are zero.
479 * BTW this stuff is optimized for an Xfree86 server
480 * read the comments inside the X11DRV_DrawArc function
482 if (DC_SetupGCForPen(dc)) {
483 if (ell_width > (right-left) )
484 if (ell_height > (bottom-top) )
485 TSXDrawArc( display, dc->u.x.drawable, dc->u.x.gc,
486 dc->w.DCOrgX + left, dc->w.DCOrgY + top,
487 right - left - 1, bottom -top - 1, 0 , 360 * 64 );
489 TSXDrawArc( display, dc->u.x.drawable, dc->u.x.gc,
490 dc->w.DCOrgX + left, dc->w.DCOrgY + top,
491 right - left - 1, ell_height - 1, 0 , 180 * 64 );
492 TSXDrawArc( display, dc->u.x.drawable, dc->u.x.gc,
494 dc->w.DCOrgY + bottom - ell_height,
495 right - left - 1, ell_height - 1, 180 * 64 , 180 * 64 );
497 else if (ell_height > (bottom-top) ){
498 TSXDrawArc( display, dc->u.x.drawable, dc->u.x.gc,
499 dc->w.DCOrgX + left, dc->w.DCOrgY + top,
500 ell_width - 1 , bottom - top - 1, 90 * 64 , 180 * 64 );
501 TSXDrawArc( display, dc->u.x.drawable, dc->u.x.gc,
502 dc->w.DCOrgX + right - ell_width,
504 ell_width - 1 , bottom - top - 1, 270 * 64 , 180 * 64 );
506 TSXDrawArc( display, dc->u.x.drawable, dc->u.x.gc,
507 dc->w.DCOrgX + left, dc->w.DCOrgY + top,
508 ell_width - 1, ell_height - 1, 90 * 64, 90 * 64 );
509 TSXDrawArc( display, dc->u.x.drawable, dc->u.x.gc,
510 dc->w.DCOrgX + left, dc->w.DCOrgY + bottom - ell_height,
511 ell_width - 1, ell_height - 1, 180 * 64, 90 * 64 );
512 TSXDrawArc( display, dc->u.x.drawable, dc->u.x.gc,
513 dc->w.DCOrgX + right - ell_width,
514 dc->w.DCOrgY + bottom - ell_height,
515 ell_width - 1, ell_height - 1, 270 * 64, 90 * 64 );
516 TSXDrawArc( display, dc->u.x.drawable, dc->u.x.gc,
517 dc->w.DCOrgX + right - ell_width, dc->w.DCOrgY + top,
518 ell_width - 1, ell_height - 1, 0, 90 * 64 );
520 if (ell_width < right - left)
522 TSXDrawLine( display, dc->u.x.drawable, dc->u.x.gc,
523 dc->w.DCOrgX + left + ell_width / 2,
525 dc->w.DCOrgX + right - (ell_width+1) / 2,
527 TSXDrawLine( display, dc->u.x.drawable, dc->u.x.gc,
528 dc->w.DCOrgX + left + ell_width / 2 ,
529 dc->w.DCOrgY + bottom - 1,
530 dc->w.DCOrgX + right - (ell_width+1)/ 2,
531 dc->w.DCOrgY + bottom - 1);
533 if (ell_height < bottom - top)
535 TSXDrawLine( display, dc->u.x.drawable, dc->u.x.gc,
536 dc->w.DCOrgX + right - 1,
537 dc->w.DCOrgY + top + ell_height / 2,
538 dc->w.DCOrgX + right - 1,
539 dc->w.DCOrgY + bottom - (ell_height+1) / 2);
540 TSXDrawLine( display, dc->u.x.drawable, dc->u.x.gc,
542 dc->w.DCOrgY + top + ell_height / 2,
544 dc->w.DCOrgY + bottom - (ell_height+1) / 2);
547 dc->u.x.pen.width=oldwidth;
548 dc->u.x.pen.endcap=oldendcap;
553 /***********************************************************************
557 X11DRV_SetPixel( DC *dc, INT32 x, INT32 y, COLORREF color )
561 x = dc->w.DCOrgX + XLPTODP( dc, x );
562 y = dc->w.DCOrgY + YLPTODP( dc, y );
563 pixel = COLOR_ToPhysical( dc, color );
565 TSXSetForeground( display, dc->u.x.gc, pixel );
566 TSXSetFunction( display, dc->u.x.gc, GXcopy );
567 TSXDrawPoint( display, dc->u.x.drawable, dc->u.x.gc, x, y );
569 /* inefficient but simple... */
571 return COLOR_ToLogical(pixel);
575 /***********************************************************************
579 X11DRV_GetPixel( DC *dc, INT32 x, INT32 y )
581 static Pixmap pixmap = 0;
585 x = dc->w.DCOrgX + XLPTODP( dc, x );
586 y = dc->w.DCOrgY + YLPTODP( dc, y );
587 EnterCriticalSection( &X11DRV_CritSection );
588 if (dc->w.flags & DC_MEMORY)
590 image = XGetImage( display, dc->u.x.drawable, x, y, 1, 1,
591 AllPlanes, ZPixmap );
595 /* If we are reading from the screen, use a temporary copy */
596 /* to avoid a BadMatch error */
597 if (!pixmap) pixmap = XCreatePixmap( display, rootWindow,
598 1, 1, dc->w.bitsPerPixel );
599 XCopyArea( display, dc->u.x.drawable, pixmap, BITMAP_colorGC,
601 image = XGetImage( display, pixmap, 0, 0, 1, 1, AllPlanes, ZPixmap );
603 pixel = XGetPixel( image, 0, 0 );
604 XDestroyImage( image );
605 LeaveCriticalSection( &X11DRV_CritSection );
607 return COLOR_ToLogical(pixel);
611 /***********************************************************************
615 X11DRV_PaintRgn( DC *dc, HRGN32 hrgn )
618 HRGN32 tmpVisRgn, prevVisRgn;
619 HDC32 hdc = dc->hSelf; /* FIXME: should not mix dc/hdc this way */
621 if (!(tmpVisRgn = CreateRectRgn32( 0, 0, 0, 0 ))) return FALSE;
623 /* Transform region into device co-ords */
624 if ( !REGION_LPTODP( hdc, tmpVisRgn, hrgn )
625 || OffsetRgn32( tmpVisRgn, dc->w.DCOrgX, dc->w.DCOrgY ) == ERROR) {
626 DeleteObject32( tmpVisRgn );
630 /* Modify visible region */
631 if (!(prevVisRgn = SaveVisRgn( hdc ))) {
632 DeleteObject32( tmpVisRgn );
635 CombineRgn32( tmpVisRgn, prevVisRgn, tmpVisRgn, RGN_AND );
636 SelectVisRgn( hdc, tmpVisRgn );
637 DeleteObject32( tmpVisRgn );
639 /* Fill the region */
641 GetRgnBox32( dc->w.hGCClipRgn, &box );
642 if (DC_SetupGCForBrush( dc ))
643 TSXFillRectangle( display, dc->u.x.drawable, dc->u.x.gc,
645 box.right-box.left, box.bottom-box.top );
647 /* Restore the visible region */
649 RestoreVisRgn( hdc );
653 /**********************************************************************
657 X11DRV_Polyline( DC *dc, const POINT32* pt, INT32 count )
662 if((oldwidth=dc->u.x.pen.width)==0) dc->u.x.pen.width=1;
664 points = (XPoint *) xmalloc (sizeof (XPoint) * (count));
665 for (i = 0; i < count; i++)
667 points[i].x = dc->w.DCOrgX + XLPTODP( dc, pt[i].x );
668 points[i].y = dc->w.DCOrgY + YLPTODP( dc, pt[i].y );
671 if (DC_SetupGCForPen ( dc ))
672 TSXDrawLines( display, dc->u.x.drawable, dc->u.x.gc,
673 points, count, CoordModeOrigin );
676 dc->u.x.pen.width=oldwidth;
681 /**********************************************************************
685 X11DRV_Polygon( DC *dc, const POINT32* pt, INT32 count )
690 points = (XPoint *) xmalloc (sizeof (XPoint) * (count+1));
691 for (i = 0; i < count; i++)
693 points[i].x = dc->w.DCOrgX + XLPTODP( dc, pt[i].x );
694 points[i].y = dc->w.DCOrgY + YLPTODP( dc, pt[i].y );
696 points[count] = points[0];
698 if (DC_SetupGCForBrush( dc ))
699 TSXFillPolygon( display, dc->u.x.drawable, dc->u.x.gc,
700 points, count+1, Complex, CoordModeOrigin);
702 if (DC_SetupGCForPen ( dc ))
703 TSXDrawLines( display, dc->u.x.drawable, dc->u.x.gc,
704 points, count+1, CoordModeOrigin );
711 /**********************************************************************
715 X11DRV_PolyPolygon( DC *dc, const POINT32* pt, const INT32* counts, UINT32 polygons)
719 /* FIXME: The points should be converted to device coords before */
720 /* creating the region. But as CreatePolyPolygonRgn is not */
721 /* really correct either, it doesn't matter much... */
722 /* At least the outline will be correct :-) */
723 hrgn = CreatePolyPolygonRgn32( pt, counts, polygons, dc->w.polyFillMode );
724 X11DRV_PaintRgn( dc, hrgn );
725 DeleteObject32( hrgn );
727 /* Draw the outline of the polygons */
729 if (DC_SetupGCForPen ( dc ))
734 for (i = 0; i < polygons; i++) if (counts[i] > max) max = counts[i];
735 points = (XPoint *) xmalloc( sizeof(XPoint) * (max+1) );
737 for (i = 0; i < polygons; i++)
739 for (j = 0; j < counts[i]; j++)
741 points[j].x = dc->w.DCOrgX + XLPTODP( dc, pt->x );
742 points[j].y = dc->w.DCOrgY + YLPTODP( dc, pt->y );
745 points[j] = points[0];
746 TSXDrawLines( display, dc->u.x.drawable, dc->u.x.gc,
747 points, j + 1, CoordModeOrigin );
755 /**********************************************************************
756 * X11DRV_PolyPolyline
759 X11DRV_PolyPolyline( DC *dc, const POINT32* pt, const DWORD* counts, DWORD polylines )
761 if (DC_SetupGCForPen ( dc ))
766 for (i = 0; i < polylines; i++) if (counts[i] > max) max = counts[i];
767 points = (XPoint *) xmalloc( sizeof(XPoint) * (max+1) );
769 for (i = 0; i < polylines; i++)
771 for (j = 0; j < counts[i]; j++)
773 points[j].x = dc->w.DCOrgX + XLPTODP( dc, pt->x );
774 points[j].y = dc->w.DCOrgY + YLPTODP( dc, pt->y );
777 points[j] = points[0];
778 TSXDrawLines( display, dc->u.x.drawable, dc->u.x.gc,
779 points, j + 1, CoordModeOrigin );
787 /**********************************************************************
788 * X11DRV_InternalFloodFill
790 * Internal helper function for flood fill.
791 * (xorg,yorg) is the origin of the X image relative to the drawable.
792 * (x,y) is relative to the origin of the X image.
794 static void X11DRV_InternalFloodFill(XImage *image, DC *dc,
797 Pixel pixel, WORD fillType )
801 #define TO_FLOOD(x,y) ((fillType == FLOODFILLBORDER) ? \
802 (XGetPixel(image,x,y) != pixel) : \
803 (XGetPixel(image,x,y) == pixel))
805 if (!TO_FLOOD(x,y)) return;
807 /* Find left and right boundaries */
810 while ((left > 0) && TO_FLOOD( left-1, y )) left--;
811 while ((right < image->width) && TO_FLOOD( right, y )) right++;
812 XFillRectangle( display, dc->u.x.drawable, dc->u.x.gc,
813 xOrg + left, yOrg + y, right-left, 1 );
815 /* Set the pixels of this line so we don't fill it again */
817 for (x = left; x < right; x++)
819 if (fillType == FLOODFILLBORDER) XPutPixel( image, x, y, pixel );
820 else XPutPixel( image, x, y, ~pixel );
823 /* Fill the line above */
830 while ((x < right) && !TO_FLOOD(x,y)) x++;
831 if (x >= right) break;
832 while ((x < right) && TO_FLOOD(x,y)) x++;
833 X11DRV_InternalFloodFill(image, dc, x-1, y,
834 xOrg, yOrg, pixel, fillType );
838 /* Fill the line below */
840 if ((y += 2) < image->height)
845 while ((x < right) && !TO_FLOOD(x,y)) x++;
846 if (x >= right) break;
847 while ((x < right) && TO_FLOOD(x,y)) x++;
848 X11DRV_InternalFloodFill(image, dc, x-1, y,
849 xOrg, yOrg, pixel, fillType );
856 /**********************************************************************
859 * Main flood-fill routine.
861 * The Xlib critical section must be entered before calling this function.
864 struct FloodFill_params
873 static BOOL32 X11DRV_DoFloodFill( const struct FloodFill_params *params )
879 if (GetRgnBox32( dc->w.hGCClipRgn, &rect ) == ERROR) return FALSE;
881 if (!(image = XGetImage( display, dc->u.x.drawable,
884 rect.right - rect.left,
885 rect.bottom - rect.top,
886 AllPlanes, ZPixmap ))) return FALSE;
888 if (DC_SetupGCForBrush( dc ))
890 /* ROP mode is always GXcopy for flood-fill */
891 XSetFunction( display, dc->u.x.gc, GXcopy );
892 X11DRV_InternalFloodFill(image, dc,
893 XLPTODP(dc,params->x) + dc->w.DCOrgX - rect.left,
894 YLPTODP(dc,params->y) + dc->w.DCOrgY - rect.top,
897 COLOR_ToPhysical( dc, params->color ),
901 XDestroyImage( image );
906 /**********************************************************************
907 * X11DRV_ExtFloodFill
910 X11DRV_ExtFloodFill( DC *dc, INT32 x, INT32 y, COLORREF color,
914 struct FloodFill_params params = { dc, x, y, color, fillType };
916 TRACE(graphics, "X11DRV_ExtFloodFill %d,%d %06lx %d\n",
917 x, y, color, fillType );
919 if (!PtVisible32( dc->hSelf, x, y )) return FALSE;
920 EnterCriticalSection( &X11DRV_CritSection );
921 result = CALL_LARGE_STACK( X11DRV_DoFloodFill, ¶ms );
922 LeaveCriticalSection( &X11DRV_CritSection );
926 /******************************************************************
928 * *Very* simple bezier drawing code,
930 * It uses a recursive algorithm to divide the curve in a series
931 * of straight line segements. Not ideal but for me sufficient.
932 * If you are in need for something better look for some incremental
935 * 7 July 1998 Rein Klazes
939 * some macro definitions for bezier drawing
941 * to avoid trucation errors the coordinates are
942 * shifted upwards. When used in drawing they are
943 * shifted down again, including correct rounding
944 * and avoiding floating point arithmatic
945 * 4 bits should allow 27 bits coordinates which I saw
946 * somewere in the win32 doc's
950 #define BEZIERSHIFTBITS 4
951 #define BEZIERSHIFTUP(x) ((x)<<BEZIERSHIFTBITS)
952 #define BEZIERPIXEL BEZIERSHIFTUP(1)
953 #define BEZIERSHIFTDOWN(x) (((x)+(1<<(BEZIERSHIFTBITS-1)))>>BEZIERSHIFTBITS)
954 /* maximum depth of recursion */
955 #define BEZIERMAXDEPTH 8
957 /* size of array to store points on */
958 /* enough for one curve */
959 #define BEZMAXPOINTS (150)
961 /* calculate Bezier average, in this case the middle
962 * correctly rounded...
965 #define BEZIERMIDDLE(Mid, P1, P2) \
966 (Mid).x=((P1).x+(P2).x + 1)/2;\
967 (Mid).y=((P1).y+(P2).y + 1)/2;
969 /**********************************************************
970 * BezierCheck helper function to check
971 * that recursion can be terminated
972 * Points[0] and Points[3] are begin and endpoint
973 * Points[1] and Points[2] are control points
974 * level is the recursion depth
975 * returns true if the recusion can be terminated
977 static BOOL32 BezierCheck( int level, POINT32 *Points)
980 dx=Points[3].x-Points[0].x;
981 dy=Points[3].y-Points[0].y;
982 if(ABS(dy)<=ABS(dx)){/* shallow line */
983 /* check that control points are between begin and end */
984 if(Points[1].x < Points[0].x){
985 if(Points[1].x < Points[3].x)
988 if(Points[1].x > Points[3].x)
990 if(Points[2].x < Points[0].x){
991 if(Points[2].x < Points[3].x)
994 if(Points[2].x > Points[3].x)
996 dx=BEZIERSHIFTDOWN(dx);
998 if(abs(Points[1].y-Points[0].y-(dy/dx)*
999 BEZIERSHIFTDOWN(Points[1].x-Points[0].x)) > BEZIERPIXEL ||
1000 abs(Points[2].y-Points[0].y-(dy/dx)*
1001 BEZIERSHIFTDOWN(Points[2].x-Points[0].x)) > BEZIERPIXEL )
1005 }else{ /* steep line */
1006 /* check that control points are between begin and end */
1007 if(Points[1].y < Points[0].y){
1008 if(Points[1].y < Points[3].y)
1011 if(Points[1].y > Points[3].y)
1013 if(Points[2].y < Points[0].y){
1014 if(Points[2].y < Points[3].y)
1017 if(Points[2].y > Points[3].y)
1019 dy=BEZIERSHIFTDOWN(dy);
1020 if(!dy) return TRUE;
1021 if(abs(Points[1].x-Points[0].x-(dx/dy)*
1022 BEZIERSHIFTDOWN(Points[1].y-Points[0].y)) > BEZIERPIXEL ||
1023 abs(Points[2].x-Points[0].x-(dx/dy)*
1024 BEZIERSHIFTDOWN(Points[2].y-Points[0].y)) > BEZIERPIXEL )
1031 /***********************************************************************
1033 * Draw a -what microsoft calls- bezier curve
1034 * The routine recursively devides the curve
1035 * in two parts until a straight line can be drawn
1037 * level recusion depth counted backwards
1039 * Points array of begin(0), end(3) and control points(1 and 2)
1040 * XPoints array with points calculated sofar
1041 * *pIx nr points calculated sofar
1044 static void X11DRV_Bezier(int level, DC * dc, POINT32 *Points,
1045 XPoint* xpoints, unsigned int* pIx)
1047 if(*pIx == BEZMAXPOINTS){
1048 TSXDrawLines( display, dc->u.x.drawable, dc->u.x.gc,
1049 xpoints, *pIx, CoordModeOrigin );
1052 if(!level || BezierCheck(level, Points)) {
1054 xpoints[*pIx].x= dc->w.DCOrgX + BEZIERSHIFTDOWN(Points[0].x);
1055 xpoints[*pIx].y= dc->w.DCOrgY + BEZIERSHIFTDOWN(Points[0].y);
1058 xpoints[*pIx].x= dc->w.DCOrgX + BEZIERSHIFTDOWN(Points[3].x);
1059 xpoints[*pIx].y= dc->w.DCOrgY + BEZIERSHIFTDOWN(Points[3].y);
1062 POINT32 Points2[4]; /* for the second recursive call */
1063 Points2[3]=Points[3];
1064 BEZIERMIDDLE(Points2[2], Points[2], Points[3]);
1065 BEZIERMIDDLE(Points2[0], Points[1], Points[2]);
1066 BEZIERMIDDLE(Points2[1],Points2[0],Points2[2]);
1068 BEZIERMIDDLE(Points[1], Points[0], Points[1]);
1069 BEZIERMIDDLE(Points[2], Points[1], Points2[0]);
1070 BEZIERMIDDLE(Points[3], Points[2], Points2[1]);
1072 Points2[0]=Points[3];
1074 /* do the two halves */
1075 X11DRV_Bezier(level-1, dc, Points, xpoints, pIx);
1076 X11DRV_Bezier(level-1, dc, Points2, xpoints, pIx);
1080 /***********************************************************************
1082 * Implement functionality for PolyBezier and PolyBezierTo
1084 * [i] dc pointer to device context
1085 * [i] start, first point in curve
1086 * [i] BezierPoints , array of point filled with rest of the points
1087 * [i] count, number of points in BezierPoints, must be a
1091 X11DRV_PolyBezier(DC *dc, POINT32 start, const POINT32* BezierPoints, DWORD count)
1097 TRACE(graphics, "dc=%04x count=%ld %d,%d - %d,%d - %d,%d -%d,%d \n",
1100 (Points+0)->x, (Points+0)->y,
1101 (Points+1)->x, (Points+1)->y,
1102 (Points+2)->x, (Points+2)->y);
1103 if(!count || count % 3){/* paranoid */
1104 WARN(graphics," bad value for count : %ld\n", count);
1107 xpoints=(XPoint*) xmalloc( sizeof(XPoint)*BEZMAXPOINTS);
1108 Points[3].x=BEZIERSHIFTUP(XLPTODP(dc,start.x));
1109 Points[3].y=BEZIERSHIFTUP(YLPTODP(dc,start.y));
1111 Points[0]=Points[3];
1113 Points[i].x= BEZIERSHIFTUP(XLPTODP(dc,BezierPoints->x));
1114 Points[i].y= BEZIERSHIFTUP(YLPTODP(dc,BezierPoints->y));
1117 X11DRV_Bezier(BEZIERMAXDEPTH , dc, Points, xpoints, &ix );
1120 if( ix) TSXDrawLines( display, dc->u.x.drawable, dc->u.x.gc,
1121 xpoints, ix, CoordModeOrigin );
1126 /**********************************************************************
1130 X11DRV_SetBkColor( DC *dc, COLORREF color )
1132 X11DRV_PDEVICE *physDev = (X11DRV_PDEVICE *)dc->physDev;
1135 oldColor = dc->w.backgroundColor;
1136 dc->w.backgroundColor = color;
1138 physDev->backgroundPixel = COLOR_ToPhysical( dc, color );
1143 /**********************************************************************
1144 * X11DRV_SetTextColor
1147 X11DRV_SetTextColor( DC *dc, COLORREF color )
1149 X11DRV_PDEVICE *physDev = (X11DRV_PDEVICE *)dc->physDev;
1152 oldColor = dc->w.textColor;
1153 dc->w.textColor = color;
1155 physDev->textPixel = COLOR_ToPhysical( dc, color );