Release 960928
[wine/multimedia.git] / windows / graphics.c
blobaca1f6c9994084e08e9728d9f3a2823716eaa478
1 /*
2 * GDI graphics operations
4 * Copyright 1993, 1994 Alexandre Julliard
5 */
7 #include <math.h>
8 #include <stdlib.h>
9 #include <X11/Xlib.h>
10 #include <X11/Xutil.h>
11 #include <X11/Intrinsic.h>
12 #ifndef PI
13 #define PI M_PI
14 #endif
15 #include "graphics.h"
16 #include "dc.h"
17 #include "bitmap.h"
18 #include "callback.h"
19 #include "metafile.h"
20 #include "syscolor.h"
21 #include "stddebug.h"
22 #include "palette.h"
23 #include "color.h"
24 #include "region.h"
25 #include "debug.h"
26 #include "xmalloc.h"
28 /***********************************************************************
29 * LineTo (GDI.19)
31 BOOL LineTo( HDC hdc, short x, short y )
33 DC * dc = (DC *) GDI_GetObjPtr( hdc, DC_MAGIC );
34 if (!dc)
36 dc = (DC *)GDI_GetObjPtr(hdc, METAFILE_DC_MAGIC);
37 if (!dc) return FALSE;
38 MF_MetaParam2(dc, META_LINETO, x, y);
39 return TRUE;
42 if (DC_SetupGCForPen( dc ))
43 XDrawLine(display, dc->u.x.drawable, dc->u.x.gc,
44 dc->w.DCOrgX + XLPTODP( dc, dc->w.CursPosX ),
45 dc->w.DCOrgY + YLPTODP( dc, dc->w.CursPosY ),
46 dc->w.DCOrgX + XLPTODP( dc, x ),
47 dc->w.DCOrgY + YLPTODP( dc, y ) );
48 dc->w.CursPosX = x;
49 dc->w.CursPosY = y;
50 return TRUE;
54 /***********************************************************************
55 * MoveTo (GDI.20)
57 DWORD MoveTo( HDC hdc, short x, short y )
59 short oldx, oldy;
60 DC * dc = (DC *) GDI_GetObjPtr( hdc, DC_MAGIC );
61 if (!dc)
63 dc = (DC *)GDI_GetObjPtr(hdc, METAFILE_DC_MAGIC);
64 if (!dc) return FALSE;
65 MF_MetaParam2(dc, META_MOVETO, x, y);
66 return 0;
69 oldx = dc->w.CursPosX;
70 oldy = dc->w.CursPosY;
71 dc->w.CursPosX = x;
72 dc->w.CursPosY = y;
73 return oldx | (oldy << 16);
77 /***********************************************************************
78 * MoveToEx16 (GDI.483)
80 BOOL16 MoveToEx16( HDC16 hdc, INT16 x, INT16 y, LPPOINT16 pt )
82 DC * dc = (DC *) GDI_GetObjPtr( hdc, DC_MAGIC );
83 if (!dc) return FALSE;
84 if (pt)
86 pt->x = dc->w.CursPosX;
87 pt->y = dc->w.CursPosY;
89 dc->w.CursPosX = x;
90 dc->w.CursPosY = y;
91 return TRUE;
95 /***********************************************************************
96 * MoveToEx32 (GDI32.254)
98 BOOL32 MoveToEx32( HDC32 hdc, INT32 x, INT32 y, LPPOINT32 pt )
100 POINT16 pt16;
101 if (!MoveToEx16( (HDC16)hdc, (INT16)x, (INT16)y, &pt16 )) return FALSE;
102 if (pt) CONV_POINT16TO32( &pt16, pt );
103 return TRUE;
107 /***********************************************************************
108 * GRAPH_DrawArc
110 * Helper functions for Arc(), Chord() and Pie().
111 * 'lines' is the number of lines to draw: 0 for Arc, 1 for Chord, 2 for Pie.
113 static BOOL GRAPH_DrawArc( HDC hdc, int left, int top, int right, int bottom,
114 int xstart, int ystart, int xend, int yend, int lines )
116 int xcenter, ycenter, istart_angle, idiff_angle, tmp;
117 double start_angle, end_angle;
118 XPoint points[3];
119 DC * dc = (DC *) GDI_GetObjPtr( hdc, DC_MAGIC );
120 if (!dc)
122 dc = (DC *)GDI_GetObjPtr(hdc, METAFILE_DC_MAGIC);
123 if (!dc) return FALSE;
124 switch (lines)
126 case 0:
127 MF_MetaParam8(dc, META_ARC, left, top, right, bottom,
128 xstart, ystart, xend, yend);
129 break;
131 case 1:
132 MF_MetaParam8(dc, META_CHORD, left, top, right, bottom,
133 xstart, ystart, xend, yend);
134 break;
136 case 2:
137 MF_MetaParam8(dc, META_PIE, left, top, right, bottom,
138 xstart, ystart, xend, yend);
139 break;
141 return 0;
144 left = XLPTODP( dc, left );
145 top = YLPTODP( dc, top );
146 right = XLPTODP( dc, right );
147 bottom = YLPTODP( dc, bottom );
148 xstart = XLPTODP( dc, xstart );
149 ystart = YLPTODP( dc, ystart );
150 xend = XLPTODP( dc, xend );
151 yend = YLPTODP( dc, yend );
152 if ((left == right) || (top == bottom)) return FALSE;
154 xcenter = (right + left) / 2;
155 ycenter = (bottom + top) / 2;
156 start_angle = atan2( (double)(ycenter-ystart)*(right-left),
157 (double)(xstart-xcenter)*(bottom-top) );
158 end_angle = atan2( (double)(ycenter-yend)*(right-left),
159 (double)(xend-xcenter)*(bottom-top) );
160 istart_angle = (int)(start_angle * 180 * 64 / PI);
161 idiff_angle = (int)((end_angle - start_angle) * 180 * 64 / PI );
162 if (idiff_angle <= 0) idiff_angle += 360 * 64;
163 if (left > right) { tmp=left; left=right; right=tmp; }
164 if (top > bottom) { tmp=top; top=bottom; bottom=tmp; }
166 /* Fill arc with brush if Chord() or Pie() */
168 if ((lines > 0) && DC_SetupGCForBrush( dc ))
170 XSetArcMode( display, dc->u.x.gc, (lines==1) ? ArcChord : ArcPieSlice);
171 XFillArc( display, dc->u.x.drawable, dc->u.x.gc,
172 dc->w.DCOrgX + left, dc->w.DCOrgY + top,
173 right-left-1, bottom-top-1, istart_angle, idiff_angle );
176 /* Draw arc and lines */
178 if (!DC_SetupGCForPen( dc )) return TRUE;
179 XDrawArc( display, dc->u.x.drawable, dc->u.x.gc,
180 dc->w.DCOrgX + left, dc->w.DCOrgY + top,
181 right-left-1, bottom-top-1, istart_angle, idiff_angle );
182 if (!lines) return TRUE;
184 points[0].x = dc->w.DCOrgX + xcenter + (int)(cos(start_angle) * (right-left) / 2);
185 points[0].y = dc->w.DCOrgY + ycenter - (int)(sin(start_angle) * (bottom-top) / 2);
186 points[1].x = dc->w.DCOrgX + xcenter + (int)(cos(end_angle) * (right-left) / 2);
187 points[1].y = dc->w.DCOrgY + ycenter - (int)(sin(end_angle) * (bottom-top) / 2);
188 if (lines == 2)
190 points[2] = points[1];
191 points[1].x = dc->w.DCOrgX + xcenter;
192 points[1].y = dc->w.DCOrgY + ycenter;
194 XDrawLines( display, dc->u.x.drawable, dc->u.x.gc,
195 points, lines+1, CoordModeOrigin );
196 return TRUE;
200 /***********************************************************************
201 * Arc (GDI.23)
203 BOOL Arc( HDC hdc, INT left, INT top, INT right, INT bottom,
204 INT xstart, INT ystart, INT xend, INT yend )
206 return GRAPH_DrawArc( hdc, left, top, right, bottom,
207 xstart, ystart, xend, yend, 0 );
211 /***********************************************************************
212 * Pie (GDI.26)
214 BOOL Pie( HDC hdc, INT left, INT top, INT right, INT bottom,
215 INT xstart, INT ystart, INT xend, INT yend )
217 return GRAPH_DrawArc( hdc, left, top, right, bottom,
218 xstart, ystart, xend, yend, 2 );
222 /***********************************************************************
223 * Chord (GDI.348)
225 BOOL Chord( HDC hdc, INT left, INT top, INT right, INT bottom,
226 INT xstart, INT ystart, INT xend, INT yend )
228 return GRAPH_DrawArc( hdc, left, top, right, bottom,
229 xstart, ystart, xend, yend, 1 );
233 /***********************************************************************
234 * Ellipse (GDI.24)
236 BOOL Ellipse( HDC hdc, INT left, INT top, INT right, INT bottom )
238 DC * dc = (DC *) GDI_GetObjPtr( hdc, DC_MAGIC );
239 if (!dc)
241 dc = (DC *)GDI_GetObjPtr(hdc, METAFILE_DC_MAGIC);
242 if (!dc) return FALSE;
243 MF_MetaParam4(dc, META_ELLIPSE, left, top, right, bottom);
244 return 0;
247 left = XLPTODP( dc, left );
248 top = YLPTODP( dc, top );
249 right = XLPTODP( dc, right );
250 bottom = YLPTODP( dc, bottom );
251 if ((left == right) || (top == bottom)) return FALSE;
253 if (right < left) { INT tmp = right; right = left; left = tmp; }
254 if (bottom < top) { INT tmp = bottom; bottom = top; top = tmp; }
256 if ((dc->u.x.pen.style == PS_INSIDEFRAME) &&
257 (dc->u.x.pen.width < right-left-1) &&
258 (dc->u.x.pen.width < bottom-top-1))
260 left += dc->u.x.pen.width / 2;
261 right -= (dc->u.x.pen.width + 1) / 2;
262 top += dc->u.x.pen.width / 2;
263 bottom -= (dc->u.x.pen.width + 1) / 2;
266 if (DC_SetupGCForBrush( dc ))
267 XFillArc( display, dc->u.x.drawable, dc->u.x.gc,
268 dc->w.DCOrgX + left, dc->w.DCOrgY + top,
269 right-left-1, bottom-top-1, 0, 360*64 );
270 if (DC_SetupGCForPen( dc ))
271 XDrawArc( display, dc->u.x.drawable, dc->u.x.gc,
272 dc->w.DCOrgX + left, dc->w.DCOrgY + top,
273 right-left-1, bottom-top-1, 0, 360*64 );
274 return TRUE;
278 /***********************************************************************
279 * Rectangle (GDI.27)
281 BOOL Rectangle( HDC hdc, INT left, INT top, INT right, INT bottom )
283 INT32 width;
284 DC * dc = (DC *) GDI_GetObjPtr( hdc, DC_MAGIC );
285 if (!dc)
287 dc = (DC *)GDI_GetObjPtr(hdc, METAFILE_DC_MAGIC);
288 if (!dc) return FALSE;
289 MF_MetaParam4(dc, META_RECTANGLE, left, top, right, bottom);
290 return TRUE;
292 left = XLPTODP( dc, left );
293 top = YLPTODP( dc, top );
294 right = XLPTODP( dc, right );
295 bottom = YLPTODP( dc, bottom );
297 if (right < left) { INT tmp = right; right = left; left = tmp; }
298 if (bottom < top) { INT tmp = bottom; bottom = top; top = tmp; }
300 if ((left == right) || (top == bottom))
302 if (DC_SetupGCForPen( dc ))
303 XDrawLine(display, dc->u.x.drawable, dc->u.x.gc,
304 dc->w.DCOrgX + left,
305 dc->w.DCOrgY + top,
306 dc->w.DCOrgX + right,
307 dc->w.DCOrgY + bottom);
308 return TRUE;
310 width = dc->u.x.pen.width;
311 if (!width) width = 1;
312 if(dc->u.x.pen.style == PS_NULL) width = 0;
314 if ((dc->u.x.pen.style == PS_INSIDEFRAME) &&
315 (width < right-left) && (width < bottom-top))
317 left += width / 2;
318 right -= (width + 1) / 2;
319 top += width / 2;
320 bottom -= (width + 1) / 2;
323 if (DC_SetupGCForBrush( dc ))
324 XFillRectangle( display, dc->u.x.drawable, dc->u.x.gc,
325 dc->w.DCOrgX + left + (width + 1) / 2,
326 dc->w.DCOrgY + top + (width + 1) / 2,
327 right-left-width-1, bottom-top-width-1);
328 if (DC_SetupGCForPen( dc ))
329 XDrawRectangle( display, dc->u.x.drawable, dc->u.x.gc,
330 dc->w.DCOrgX + left, dc->w.DCOrgY + top,
331 right-left-1, bottom-top-1 );
332 return TRUE;
336 /***********************************************************************
337 * RoundRect (GDI.28)
339 BOOL RoundRect( HDC hDC, INT left, INT top, INT right, INT bottom,
340 INT ell_width, INT ell_height )
342 DC * dc = (DC *) GDI_GetObjPtr(hDC, DC_MAGIC);
343 if (!dc)
345 dc = (DC *)GDI_GetObjPtr(hDC, METAFILE_DC_MAGIC);
346 if (!dc) return FALSE;
347 MF_MetaParam6(dc, META_ROUNDRECT, left, top, right, bottom,
348 ell_width, ell_height);
349 return TRUE;
351 dprintf_graphics(stddeb, "RoundRect(%d %d %d %d %d %d\n",
352 left, top, right, bottom, ell_width, ell_height);
354 left = XLPTODP( dc, left );
355 top = YLPTODP( dc, top );
356 right = XLPTODP( dc, right );
357 bottom = YLPTODP( dc, bottom );
358 ell_width = abs( ell_width * dc->w.VportExtX / dc->w.WndExtX );
359 ell_height = abs( ell_height * dc->w.VportExtY / dc->w.WndExtY );
361 /* Fix the coordinates */
363 if (right < left) { INT tmp = right; right = left; left = tmp; }
364 if (bottom < top) { INT tmp = bottom; bottom = top; top = tmp; }
365 if (ell_width > right - left) ell_width = right - left;
366 if (ell_height > bottom - top) ell_height = bottom - top;
368 if (DC_SetupGCForBrush( dc ))
370 if (ell_width && ell_height)
372 XFillArc( display, dc->u.x.drawable, dc->u.x.gc,
373 dc->w.DCOrgX + left, dc->w.DCOrgY + top,
374 ell_width, ell_height, 90 * 64, 90 * 64 );
375 XFillArc( display, dc->u.x.drawable, dc->u.x.gc,
376 dc->w.DCOrgX + left, dc->w.DCOrgY + bottom - ell_height,
377 ell_width, ell_height, 180 * 64, 90 * 64 );
378 XFillArc( display, dc->u.x.drawable, dc->u.x.gc,
379 dc->w.DCOrgX + right - ell_width,
380 dc->w.DCOrgY + bottom - ell_height,
381 ell_width, ell_height, 270 * 64, 90 * 64 );
382 XFillArc( display, dc->u.x.drawable, dc->u.x.gc,
383 dc->w.DCOrgX + right - ell_width, dc->w.DCOrgY + top,
384 ell_width, ell_height, 0, 90 * 64 );
386 if (ell_width < right - left)
388 XFillRectangle( display, dc->u.x.drawable, dc->u.x.gc,
389 dc->w.DCOrgX + left + ell_width / 2,
390 dc->w.DCOrgY + top,
391 right - left - ell_width, ell_height / 2 );
392 XFillRectangle( display, dc->u.x.drawable, dc->u.x.gc,
393 dc->w.DCOrgX + left + ell_width / 2,
394 dc->w.DCOrgY + bottom - (ell_height+1) / 2,
395 right - left - ell_width, (ell_height+1) / 2 );
397 if (ell_height < bottom - top)
399 XFillRectangle( display, dc->u.x.drawable, dc->u.x.gc,
400 dc->w.DCOrgX + left,
401 dc->w.DCOrgY + top + ell_height / 2,
402 right - left, bottom - top - ell_height );
405 if (DC_SetupGCForPen(dc))
407 if (ell_width && ell_height)
409 XDrawArc( display, dc->u.x.drawable, dc->u.x.gc,
410 dc->w.DCOrgX + left, dc->w.DCOrgY + top,
411 ell_width, ell_height, 90 * 64, 90 * 64 );
412 XDrawArc( display, dc->u.x.drawable, dc->u.x.gc,
413 dc->w.DCOrgX + left, dc->w.DCOrgY + bottom - ell_height,
414 ell_width, ell_height, 180 * 64, 90 * 64 );
415 XDrawArc( display, dc->u.x.drawable, dc->u.x.gc,
416 dc->w.DCOrgX + right - ell_width,
417 dc->w.DCOrgY + bottom - ell_height,
418 ell_width, ell_height, 270 * 64, 90 * 64 );
419 XDrawArc( display, dc->u.x.drawable, dc->u.x.gc,
420 dc->w.DCOrgX + right - ell_width, dc->w.DCOrgY + top,
421 ell_width, ell_height, 0, 90 * 64 );
423 if (ell_width < right - left)
425 XDrawLine( display, dc->u.x.drawable, dc->u.x.gc,
426 dc->w.DCOrgX + left + ell_width / 2,
427 dc->w.DCOrgY + top,
428 dc->w.DCOrgX + right - ell_width / 2,
429 dc->w.DCOrgY + top );
430 XDrawLine( display, dc->u.x.drawable, dc->u.x.gc,
431 dc->w.DCOrgX + left + ell_width / 2,
432 dc->w.DCOrgY + bottom,
433 dc->w.DCOrgX + right - ell_width / 2,
434 dc->w.DCOrgY + bottom );
436 if (ell_height < bottom - top)
438 XDrawLine( display, dc->u.x.drawable, dc->u.x.gc,
439 dc->w.DCOrgX + right,
440 dc->w.DCOrgY + top + ell_height / 2,
441 dc->w.DCOrgX + right,
442 dc->w.DCOrgY + bottom - ell_height / 2 );
443 XDrawLine( display, dc->u.x.drawable, dc->u.x.gc,
444 dc->w.DCOrgX + left,
445 dc->w.DCOrgY + top + ell_height / 2,
446 dc->w.DCOrgX + left,
447 dc->w.DCOrgY + bottom - ell_height / 2 );
450 return TRUE;
454 /***********************************************************************
455 * FillRect16 (USER.81)
457 INT16 FillRect16( HDC16 hdc, const RECT16 *rect, HBRUSH16 hbrush )
459 HBRUSH prevBrush;
461 /* coordinates are logical so we cannot fast-check rectangle
462 * - do it in PatBlt() after LPtoDP().
465 if (!(prevBrush = SelectObject( hdc, hbrush ))) return 0;
466 PatBlt( hdc, rect->left, rect->top,
467 rect->right - rect->left, rect->bottom - rect->top, PATCOPY );
468 SelectObject( hdc, prevBrush );
469 return 1;
473 /***********************************************************************
474 * FillRect32 (USER32.196)
476 INT32 FillRect32( HDC32 hdc, const RECT32 *rect, HBRUSH32 hbrush )
478 HBRUSH prevBrush;
480 if (!(prevBrush = SelectObject( hdc, (HBRUSH16)hbrush ))) return 0;
481 PatBlt( hdc, rect->left, rect->top,
482 rect->right - rect->left, rect->bottom - rect->top, PATCOPY );
483 SelectObject( hdc, prevBrush );
484 return 1;
488 /***********************************************************************
489 * InvertRect16 (USER.82)
491 void InvertRect16( HDC16 hdc, const RECT16 *rect )
493 PatBlt( hdc, rect->left, rect->top,
494 rect->right - rect->left, rect->bottom - rect->top, DSTINVERT );
498 /***********************************************************************
499 * InvertRect32 (USER32.329)
501 void InvertRect32( HDC32 hdc, const RECT32 *rect )
503 PatBlt( hdc, rect->left, rect->top,
504 rect->right - rect->left, rect->bottom - rect->top, DSTINVERT );
508 /***********************************************************************
509 * FrameRect16 (USER.83)
511 INT16 FrameRect16( HDC16 hdc, const RECT16 *rect, HBRUSH16 hbrush )
513 HBRUSH prevBrush;
514 int left, top, right, bottom;
516 DC * dc = (DC *) GDI_GetObjPtr( hdc, DC_MAGIC );
517 if (!dc) return FALSE;
519 left = XLPTODP( dc, rect->left );
520 top = YLPTODP( dc, rect->top );
521 right = XLPTODP( dc, rect->right );
522 bottom = YLPTODP( dc, rect->bottom );
524 if ( (right <= left) || (bottom <= top) ) return 0;
525 if (!(prevBrush = SelectObject( hdc, hbrush ))) return 0;
527 if (DC_SetupGCForBrush( dc ))
529 PatBlt( hdc, rect->left, rect->top, 1,
530 rect->bottom - rect->top, PATCOPY );
531 PatBlt( hdc, rect->right - 1, rect->top, 1,
532 rect->bottom - rect->top, PATCOPY );
533 PatBlt( hdc, rect->left, rect->top,
534 rect->right - rect->left, 1, PATCOPY );
535 PatBlt( hdc, rect->left, rect->bottom - 1,
536 rect->right - rect->left, 1, PATCOPY );
538 SelectObject( hdc, prevBrush );
539 return 1;
543 /***********************************************************************
544 * FrameRect32 (USER32.202)
546 INT32 FrameRect32( HDC32 hdc, const RECT32 *rect, HBRUSH32 hbrush )
548 RECT16 rect16;
549 CONV_RECT32TO16( rect, &rect16 );
550 return FrameRect16( (HDC16)hdc, &rect16, (HBRUSH16)hbrush );
554 /***********************************************************************
555 * SetPixel (GDI.31)
557 COLORREF SetPixel( HDC hdc, short x, short y, COLORREF color )
559 Pixel pixel;
561 DC * dc = (DC *) GDI_GetObjPtr( hdc, DC_MAGIC );
562 if (!dc)
564 dc = (DC *)GDI_GetObjPtr(hdc, METAFILE_DC_MAGIC);
565 if (!dc) return 0;
566 MF_MetaParam4(dc, META_SETPIXEL, x, y, HIWORD(color), LOWORD(color));
567 return 1;
570 x = dc->w.DCOrgX + XLPTODP( dc, x );
571 y = dc->w.DCOrgY + YLPTODP( dc, y );
572 pixel = COLOR_ToPhysical( dc, color );
574 XSetForeground( display, dc->u.x.gc, pixel );
575 XSetFunction( display, dc->u.x.gc, GXcopy );
576 XDrawPoint( display, dc->u.x.drawable, dc->u.x.gc, x, y );
578 /* inefficient but simple... */
580 return COLOR_ToLogical(pixel);
584 /***********************************************************************
585 * GetPixel (GDI.83)
587 COLORREF GetPixel( HDC hdc, short x, short y )
589 static Pixmap pixmap = 0;
590 XImage * image;
591 int pixel;
593 DC * dc = (DC *) GDI_GetObjPtr( hdc, DC_MAGIC );
594 if (!dc) return 0;
596 #ifdef SOLITAIRE_SPEED_HACK
597 return 0;
598 #endif
600 if (!PtVisible( hdc, x, y )) return 0;
602 x = dc->w.DCOrgX + XLPTODP( dc, x );
603 y = dc->w.DCOrgY + YLPTODP( dc, y );
604 if (dc->w.flags & DC_MEMORY)
606 image = XGetImage( display, dc->u.x.drawable, x, y, 1, 1,
607 AllPlanes, ZPixmap );
609 else
611 /* If we are reading from the screen, use a temporary copy */
612 /* to avoid a BadMatch error */
613 if (!pixmap) pixmap = XCreatePixmap( display, rootWindow,
614 1, 1, dc->w.bitsPerPixel );
615 XCopyArea( display, dc->u.x.drawable, pixmap, BITMAP_colorGC,
616 x, y, 1, 1, 0, 0 );
617 image = XGetImage( display, pixmap, 0, 0, 1, 1, AllPlanes, ZPixmap );
619 pixel = XGetPixel( image, 0, 0 );
620 XDestroyImage( image );
622 return COLOR_ToLogical(pixel);
626 /***********************************************************************
627 * PaintRgn (GDI.43)
629 BOOL PaintRgn( HDC hdc, HRGN hrgn )
631 RECT16 box;
632 HRGN tmpVisRgn, prevVisRgn;
633 DC * dc = (DC *) GDI_GetObjPtr( hdc, DC_MAGIC );
634 if (!dc) return FALSE;
636 /* Modify visible region */
638 if (!(prevVisRgn = SaveVisRgn( hdc ))) return FALSE;
639 if (!(tmpVisRgn = CreateRectRgn( 0, 0, 0, 0 )))
641 RestoreVisRgn( hdc );
642 return FALSE;
644 CombineRgn( tmpVisRgn, prevVisRgn, hrgn, RGN_AND );
645 SelectVisRgn( hdc, tmpVisRgn );
646 DeleteObject( tmpVisRgn );
648 /* Fill the region */
650 GetRgnBox16( dc->w.hGCClipRgn, &box );
651 if (DC_SetupGCForBrush( dc ))
652 XFillRectangle( display, dc->u.x.drawable, dc->u.x.gc,
653 dc->w.DCOrgX + box.left, dc->w.DCOrgY + box.top,
654 box.right-box.left, box.bottom-box.top );
656 /* Restore the visible region */
658 RestoreVisRgn( hdc );
659 return TRUE;
663 /***********************************************************************
664 * FillRgn (GDI.40)
666 BOOL FillRgn( HDC hdc, HRGN hrgn, HBRUSH hbrush )
668 BOOL retval;
669 HBRUSH prevBrush = SelectObject( hdc, hbrush );
670 if (!prevBrush) return FALSE;
671 retval = PaintRgn( hdc, hrgn );
672 SelectObject( hdc, prevBrush );
673 return retval;
676 /***********************************************************************
677 * FrameRgn (GDI.41)
679 BOOL FrameRgn( HDC hdc, HRGN hrgn, HBRUSH hbrush, int nWidth, int nHeight )
681 HRGN tmp = CreateRectRgn( 0, 0, 0, 0 );
682 if(!REGION_FrameRgn( tmp, hrgn, nWidth, nHeight )) return 0;
683 FillRgn( hdc, tmp, hbrush );
684 DeleteObject( tmp );
685 return 1;
688 /***********************************************************************
689 * InvertRgn (GDI.42)
691 BOOL InvertRgn( HDC hdc, HRGN hrgn )
693 HBRUSH prevBrush = SelectObject( hdc, GetStockObject(BLACK_BRUSH) );
694 WORD prevROP = SetROP2( hdc, R2_NOT );
695 BOOL retval = PaintRgn( hdc, hrgn );
696 SelectObject( hdc, prevBrush );
697 SetROP2( hdc, prevROP );
698 return retval;
702 /***********************************************************************
703 * DrawFocusRect16 (USER.466)
705 void DrawFocusRect16( HDC16 hdc, const RECT16* rc )
707 HPEN16 hOldPen;
708 int oldDrawMode, oldBkMode;
709 int left, top, right, bottom;
710 DC * dc = (DC *) GDI_GetObjPtr( hdc, DC_MAGIC );
711 if (!dc) return;
713 left = XLPTODP( dc, rc->left );
714 top = YLPTODP( dc, rc->top );
715 right = XLPTODP( dc, rc->right );
716 bottom = YLPTODP( dc, rc->bottom );
718 hOldPen = (HPEN16)SelectObject(hdc, sysColorObjects.hpenWindowText );
719 oldDrawMode = SetROP2(hdc, R2_XORPEN);
720 oldBkMode = SetBkMode(hdc, TRANSPARENT);
722 /* Hack: make sure the XORPEN operation has an effect */
723 dc->u.x.pen.pixel = (1 << screenDepth) - 1;
725 if (DC_SetupGCForPen( dc ))
726 XDrawRectangle( display, dc->u.x.drawable, dc->u.x.gc,
727 dc->w.DCOrgX + left, dc->w.DCOrgY + top,
728 right-left-1, bottom-top-1 );
730 SetBkMode(hdc, oldBkMode);
731 SetROP2(hdc, oldDrawMode);
732 SelectObject(hdc, (HANDLE)hOldPen);
736 /***********************************************************************
737 * DrawFocusRect32 (USER32.155)
739 void DrawFocusRect32( HDC32 hdc, const RECT32* rect )
741 RECT16 rect16;
742 CONV_RECT32TO16( rect, &rect16 );
743 return DrawFocusRect16( (HDC16)hdc, &rect16 );
747 /**********************************************************************
748 * GRAPH_DrawBitmap
750 * Short-cut function to blit a bitmap into a device.
751 * Faster than CreateCompatibleDC() + SelectBitmap() + BitBlt() + DeleteDC().
753 BOOL32 GRAPH_DrawBitmap( HDC32 hdc, HBITMAP32 hbitmap, int xdest, int ydest,
754 int xsrc, int ysrc, int width, int height )
756 BITMAPOBJ *bmp;
757 DC *dc;
759 if (!(dc = (DC *) GDI_GetObjPtr( hdc, DC_MAGIC ))) return FALSE;
760 if (!(bmp = (BITMAPOBJ *) GDI_GetObjPtr( hbitmap, BITMAP_MAGIC )))
761 return FALSE;
762 XSetFunction( display, dc->u.x.gc, GXcopy );
763 if (bmp->bitmap.bmBitsPixel == 1)
765 XSetForeground( display, dc->u.x.gc, dc->w.backgroundPixel );
766 XSetBackground( display, dc->u.x.gc, dc->w.textPixel );
767 XCopyPlane( display, bmp->pixmap, dc->u.x.drawable, dc->u.x.gc,
768 xsrc, ysrc, width, height,
769 dc->w.DCOrgX + xdest, dc->w.DCOrgY + ydest, 1 );
770 return TRUE;
772 else if (bmp->bitmap.bmBitsPixel == dc->w.bitsPerPixel)
774 XCopyArea( display, bmp->pixmap, dc->u.x.drawable, dc->u.x.gc,
775 xsrc, ysrc, width, height,
776 dc->w.DCOrgX + xdest, dc->w.DCOrgY + ydest );
777 return TRUE;
779 else return FALSE;
783 /**********************************************************************
784 * GRAPH_DrawReliefRect (Not a MSWin Call)
786 void GRAPH_DrawReliefRect( HDC32 hdc, const RECT32 *rect, INT32 highlight_size,
787 INT32 shadow_size, BOOL32 pressed )
789 HBRUSH hbrushOld;
790 int i;
792 hbrushOld = SelectObject( hdc, pressed ? sysColorObjects.hbrushBtnShadow :
793 sysColorObjects.hbrushBtnHighlight );
794 for (i = 0; i < highlight_size; i++)
796 PatBlt( hdc, rect->left + i, rect->top,
797 1, rect->bottom - rect->top - i, PATCOPY );
798 PatBlt( hdc, rect->left, rect->top + i,
799 rect->right - rect->left - i, 1, PATCOPY );
802 SelectObject( hdc, pressed ? sysColorObjects.hbrushBtnHighlight :
803 sysColorObjects.hbrushBtnShadow );
804 for (i = 0; i < shadow_size; i++)
806 PatBlt( hdc, rect->right - i - 1, rect->top + i,
807 1, rect->bottom - rect->top - i, PATCOPY );
808 PatBlt( hdc, rect->left + i, rect->bottom - i - 1,
809 rect->right - rect->left - i, 1, PATCOPY );
812 SelectObject( hdc, hbrushOld );
816 /**********************************************************************
817 * Polyline16 (GDI.37)
819 BOOL16 Polyline16( HDC16 hdc, LPPOINT16 pt, INT16 count )
821 register int i;
822 DC * dc = (DC *) GDI_GetObjPtr( hdc, DC_MAGIC );
823 if (!dc)
825 dc = (DC *)GDI_GetObjPtr(hdc, METAFILE_DC_MAGIC);
826 if (!dc) return FALSE;
827 MF_MetaPoly(dc, META_POLYLINE, pt, count);
828 return TRUE;
831 if (DC_SetupGCForPen( dc ))
832 for (i = 0; i < count-1; i ++)
833 XDrawLine (display, dc->u.x.drawable, dc->u.x.gc,
834 dc->w.DCOrgX + XLPTODP(dc, pt [i].x),
835 dc->w.DCOrgY + YLPTODP(dc, pt [i].y),
836 dc->w.DCOrgX + XLPTODP(dc, pt [i+1].x),
837 dc->w.DCOrgY + YLPTODP(dc, pt [i+1].y));
838 return TRUE;
842 /**********************************************************************
843 * Polygon16 (GDI.36)
845 BOOL16 Polygon16( HDC16 hdc, LPPOINT16 pt, INT16 count )
847 register int i;
848 DC * dc = (DC *) GDI_GetObjPtr( hdc, DC_MAGIC );
849 XPoint *points = (XPoint *) xmalloc (sizeof (XPoint) * (count+1));
851 if (!dc)
853 dc = (DC *)GDI_GetObjPtr(hdc, METAFILE_DC_MAGIC);
854 if (!dc) return FALSE;
855 MF_MetaPoly(dc, META_POLYGON, pt, count);
856 return TRUE;
859 for (i = 0; i < count; i++)
861 points[i].x = dc->w.DCOrgX + XLPTODP( dc, pt[i].x );
862 points[i].y = dc->w.DCOrgY + YLPTODP( dc, pt[i].y );
864 points[count] = points[0];
866 if (DC_SetupGCForBrush( dc ))
867 XFillPolygon( display, dc->u.x.drawable, dc->u.x.gc,
868 points, count+1, Complex, CoordModeOrigin);
870 if (DC_SetupGCForPen ( dc ))
871 XDrawLines( display, dc->u.x.drawable, dc->u.x.gc,
872 points, count+1, CoordModeOrigin );
874 free( points );
875 return TRUE;
879 /**********************************************************************
880 * PolyPolygon16 (GDI.450)
882 BOOL16 PolyPolygon16( HDC16 hdc, LPPOINT16 pt, LPINT16 counts, UINT16 polygons)
884 HRGN hrgn;
885 DC * dc = (DC *) GDI_GetObjPtr( hdc, DC_MAGIC );
887 if (!dc)
889 dc = (DC *)GDI_GetObjPtr(hdc, METAFILE_DC_MAGIC);
890 if (!dc) return FALSE;
891 /* MF_MetaPoly(dc, META_POLYGON, pt, count); */
892 return TRUE;
894 /* FIXME: The points should be converted to device coords before */
895 /* creating the region. But as CreatePolyPolygonRgn is not */
896 /* really correct either, it doesn't matter much... */
897 /* At least the outline will be correct :-) */
898 hrgn = CreatePolyPolygonRgn16( pt, counts, polygons, dc->w.polyFillMode );
899 PaintRgn( hdc, hrgn );
900 DeleteObject( hrgn );
902 /* Draw the outline of the polygons */
904 if (DC_SetupGCForPen ( dc ))
906 int i, j, max = 0;
907 XPoint *points;
909 for (i = 0; i < polygons; i++) if (counts[i] > max) max = counts[i];
910 points = (XPoint *) xmalloc( sizeof(XPoint) * (max+1) );
912 for (i = 0; i < polygons; i++)
914 for (j = 0; j < counts[i]; j++)
916 points[j].x = dc->w.DCOrgX + XLPTODP( dc, pt->x );
917 points[j].y = dc->w.DCOrgY + YLPTODP( dc, pt->y );
918 pt++;
920 points[j] = points[0];
921 XDrawLines( display, dc->u.x.drawable, dc->u.x.gc,
922 points, j + 1, CoordModeOrigin );
924 free( points );
926 return TRUE;
930 /**********************************************************************
931 * GRAPH_InternalFloodFill
933 * Internal helper function for flood fill.
934 * (xorg,yorg) is the origin of the X image relative to the drawable.
935 * (x,y) is relative to the origin of the X image.
937 static void GRAPH_InternalFloodFill( XImage *image, DC *dc,
938 int x, int y,
939 int xOrg, int yOrg,
940 Pixel pixel, WORD fillType )
942 int left, right;
944 #define TO_FLOOD(x,y) ((fillType == FLOODFILLBORDER) ? \
945 (XGetPixel(image,x,y) != pixel) : \
946 (XGetPixel(image,x,y) == pixel))
948 if (!TO_FLOOD(x,y)) return;
950 /* Find left and right boundaries */
952 left = right = x;
953 while ((left > 0) && TO_FLOOD( left-1, y )) left--;
954 while ((right < image->width) && TO_FLOOD( right, y )) right++;
955 XFillRectangle( display, dc->u.x.drawable, dc->u.x.gc,
956 xOrg + left, yOrg + y, right-left, 1 );
958 /* Set the pixels of this line so we don't fill it again */
960 for (x = left; x < right; x++)
962 if (fillType == FLOODFILLBORDER) XPutPixel( image, x, y, pixel );
963 else XPutPixel( image, x, y, ~pixel );
966 /* Fill the line above */
968 if (--y >= 0)
970 x = left;
971 while (x < right)
973 while ((x < right) && !TO_FLOOD(x,y)) x++;
974 if (x >= right) break;
975 while ((x < right) && TO_FLOOD(x,y)) x++;
976 GRAPH_InternalFloodFill( image, dc, x-1, y,
977 xOrg, yOrg, pixel, fillType );
981 /* Fill the line below */
983 if ((y += 2) < image->height)
985 x = left;
986 while (x < right)
988 while ((x < right) && !TO_FLOOD(x,y)) x++;
989 if (x >= right) break;
990 while ((x < right) && TO_FLOOD(x,y)) x++;
991 GRAPH_InternalFloodFill( image, dc, x-1, y,
992 xOrg, yOrg, pixel, fillType );
995 #undef TO_FLOOD
999 /**********************************************************************
1000 * GRAPH_DoFloodFill
1002 * Main flood-fill routine.
1004 static BOOL16 GRAPH_DoFloodFill( DC *dc, RECT16 *rect, INT32 x, INT32 y,
1005 COLORREF color, UINT32 fillType )
1007 XImage *image;
1009 if (!(image = XGetImage( display, dc->u.x.drawable,
1010 dc->w.DCOrgX + rect->left,
1011 dc->w.DCOrgY + rect->top,
1012 rect->right - rect->left,
1013 rect->bottom - rect->top,
1014 AllPlanes, ZPixmap ))) return FALSE;
1016 if (DC_SetupGCForBrush( dc ))
1018 /* ROP mode is always GXcopy for flood-fill */
1019 XSetFunction( display, dc->u.x.gc, GXcopy );
1020 GRAPH_InternalFloodFill( image, dc,
1021 XLPTODP(dc,x) - rect->left,
1022 YLPTODP(dc,y) - rect->top,
1023 dc->w.DCOrgX + rect->left,
1024 dc->w.DCOrgY + rect->top,
1025 COLOR_ToPhysical( dc, color ), fillType );
1028 XDestroyImage( image );
1029 return TRUE;
1033 /**********************************************************************
1034 * ExtFloodFill (GDI.372) (GDI32.96)
1036 BOOL16 ExtFloodFill( HDC32 hdc, INT32 x, INT32 y, COLORREF color,
1037 UINT32 fillType )
1039 RECT16 rect;
1040 DC *dc;
1042 dprintf_graphics( stddeb, "ExtFloodFill %04x %d,%d %06lx %d\n",
1043 hdc, x, y, color, fillType );
1044 dc = (DC *) GDI_GetObjPtr(hdc, DC_MAGIC);
1045 if (!dc)
1047 dc = (DC *)GDI_GetObjPtr(hdc, METAFILE_DC_MAGIC);
1048 if (!dc) return FALSE;
1049 MF_MetaParam4(dc, META_FLOODFILL, x, y, HIWORD(color),
1050 LOWORD(color));
1051 return TRUE;
1054 if (!PtVisible( hdc, x, y )) return FALSE;
1055 if (GetRgnBox16( dc->w.hGCClipRgn, &rect ) == ERROR) return FALSE;
1057 return CallTo32_LargeStack( (int(*)())GRAPH_DoFloodFill, 6,
1058 dc, &rect, x, y, color, fillType );
1062 /**********************************************************************
1063 * FloodFill (GDI.25) (GDI32.104)
1065 BOOL16 FloodFill( HDC32 hdc, INT32 x, INT32 y, COLORREF color )
1067 return ExtFloodFill( hdc, x, y, color, FLOODFILLBORDER );
1071 /**********************************************************************
1072 * DrawEdge16 (USER.659)
1074 BOOL16 DrawEdge16( HDC16 hdc, LPRECT16 rc, UINT16 edge, UINT16 flags )
1076 RECT32 rect32;
1077 BOOL32 ret;
1079 CONV_RECT16TO32( rc, &rect32 );
1080 ret = DrawEdge32( hdc, &rect32, edge, flags );
1081 CONV_RECT32TO16( &rect32, rc );
1082 return ret;
1086 /**********************************************************************
1087 * DrawEdge32 (USER32.154)
1089 BOOL32 DrawEdge32( HDC32 hdc, LPRECT32 rc, UINT32 edge, UINT32 flags )
1091 HBRUSH hbrushOld;
1093 if (flags >= BF_DIAGONAL)
1094 fprintf( stderr, "DrawEdge: unsupported flags %04x\n", flags );
1096 dprintf_graphics( stddeb, "DrawEdge: %04x %d,%d-%d,%d %04x %04x\n",
1097 hdc, rc->left, rc->top, rc->right, rc->bottom,
1098 edge, flags );
1100 /* First do all the raised edges */
1102 SelectObject( hdc, sysColorObjects.hbrushBtnHighlight );
1103 if (edge & BDR_RAISEDOUTER)
1105 if (flags & BF_LEFT) PatBlt( hdc, rc->left, rc->top,
1106 1, rc->bottom - rc->top - 1, PATCOPY );
1107 if (flags & BF_TOP) PatBlt( hdc, rc->left, rc->top,
1108 rc->right - rc->left - 1, 1, PATCOPY );
1110 if (edge & BDR_SUNKENOUTER)
1112 if (flags & BF_RIGHT) PatBlt( hdc, rc->right - 1, rc->top,
1113 1, rc->bottom - rc->top, PATCOPY );
1114 if (flags & BF_BOTTOM) PatBlt( hdc, rc->left, rc->bottom - 1,
1115 rc->right - rc->left, 1, PATCOPY );
1117 if (edge & BDR_RAISEDINNER)
1119 if (flags & BF_LEFT) PatBlt( hdc, rc->left + 1, rc->top + 1,
1120 1, rc->bottom - rc->top - 2, PATCOPY );
1121 if (flags & BF_TOP) PatBlt( hdc, rc->left + 1, rc->top + 1,
1122 rc->right - rc->left - 2, 1, PATCOPY );
1124 if (edge & BDR_SUNKENINNER)
1126 if (flags & BF_RIGHT) PatBlt( hdc, rc->right - 2, rc->top + 1,
1127 1, rc->bottom - rc->top - 2, PATCOPY );
1128 if (flags & BF_BOTTOM) PatBlt( hdc, rc->left + 1, rc->bottom - 2,
1129 rc->right - rc->left - 2, 1, PATCOPY );
1132 /* Then do all the sunken edges */
1134 hbrushOld = SelectObject( hdc, sysColorObjects.hbrushBtnShadow );
1135 if (edge & BDR_SUNKENOUTER)
1137 if (flags & BF_LEFT) PatBlt( hdc, rc->left, rc->top,
1138 1, rc->bottom - rc->top - 1, PATCOPY );
1139 if (flags & BF_TOP) PatBlt( hdc, rc->left, rc->top,
1140 rc->right - rc->left - 1, 1, PATCOPY );
1142 if (edge & BDR_RAISEDOUTER)
1144 if (flags & BF_RIGHT) PatBlt( hdc, rc->right - 1, rc->top,
1145 1, rc->bottom - rc->top, PATCOPY );
1146 if (flags & BF_BOTTOM) PatBlt( hdc, rc->left, rc->bottom - 1,
1147 rc->right - rc->left, 1, PATCOPY );
1149 if (edge & BDR_SUNKENINNER)
1151 if (flags & BF_LEFT) PatBlt( hdc, rc->left + 1, rc->top + 1,
1152 1, rc->bottom - rc->top - 2, PATCOPY );
1153 if (flags & BF_TOP) PatBlt( hdc, rc->left + 1, rc->top + 1,
1154 rc->right - rc->left - 2, 1, PATCOPY );
1156 if (edge & BDR_RAISEDINNER)
1158 if (flags & BF_RIGHT) PatBlt( hdc, rc->right - 2, rc->top + 1,
1159 1, rc->bottom - rc->top - 2, PATCOPY );
1160 if (flags & BF_BOTTOM) PatBlt( hdc, rc->left + 1, rc->bottom - 2,
1161 rc->right - rc->left - 2, 1, PATCOPY );
1164 SelectObject( hdc, hbrushOld );
1165 return TRUE;
1169 /**********************************************************************
1170 * DrawFrameControl16 (USER.656)
1172 BOOL16 DrawFrameControl16( HDC16 hdc, LPRECT16 rc, UINT16 edge, UINT16 flags )
1174 fprintf( stdnimp,"DrawFrameControl16(%x,%p,%d,%x), empty stub!\n",
1175 hdc,rc,edge,flags );
1176 return TRUE;
1180 /**********************************************************************
1181 * DrawFrameControl32 (USER32.157)
1183 BOOL32 DrawFrameControl32( HDC32 hdc, LPRECT32 rc, UINT32 edge, UINT32 flags )
1185 fprintf( stdnimp,"DrawFrameControl32(%x,%p,%d,%x), empty stub!\n",
1186 hdc,rc,edge,flags );
1187 return TRUE;