Release 960506
[wine] / windows / graphics.c
1 /*
2  * GDI graphics operations
3  *
4  * Copyright 1993, 1994 Alexandre Julliard
5  */
6
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 "dc.h"
16 #include "bitmap.h"
17 #include "callback.h"
18 #include "metafile.h"
19 #include "syscolor.h"
20 #include "stddebug.h"
21 #include "color.h"
22 #include "region.h"
23 #include "debug.h"
24 #include "xmalloc.h"
25
26 /***********************************************************************
27  *           LineTo    (GDI.19)
28  */
29 BOOL LineTo( HDC hdc, short x, short y )
30 {
31     DC * dc = (DC *) GDI_GetObjPtr( hdc, DC_MAGIC );
32     if (!dc) 
33     {
34         dc = (DC *)GDI_GetObjPtr(hdc, METAFILE_DC_MAGIC);
35         if (!dc) return FALSE;
36         MF_MetaParam2(dc, META_LINETO, x, y);
37         return TRUE;
38     }
39
40     if (DC_SetupGCForPen( dc ))
41         XDrawLine(display, dc->u.x.drawable, dc->u.x.gc, 
42                   dc->w.DCOrgX + XLPTODP( dc, dc->w.CursPosX ),
43                   dc->w.DCOrgY + YLPTODP( dc, dc->w.CursPosY ),
44                   dc->w.DCOrgX + XLPTODP( dc, x ),
45                   dc->w.DCOrgY + YLPTODP( dc, y ) );
46     dc->w.CursPosX = x;
47     dc->w.CursPosY = y;
48     return TRUE;
49 }
50
51
52 /***********************************************************************
53  *           MoveTo    (GDI.20)
54  */
55 DWORD MoveTo( HDC hdc, short x, short y )
56 {
57     short oldx, oldy;
58     DC * dc = (DC *) GDI_GetObjPtr( hdc, DC_MAGIC );
59     if (!dc) 
60     {
61         dc = (DC *)GDI_GetObjPtr(hdc, METAFILE_DC_MAGIC);
62         if (!dc) return FALSE;
63         MF_MetaParam2(dc, META_MOVETO, x, y);
64         return 0;
65     }
66
67     oldx = dc->w.CursPosX;
68     oldy = dc->w.CursPosY;
69     dc->w.CursPosX = x;
70     dc->w.CursPosY = y;
71     return oldx | (oldy << 16);
72 }
73
74
75 /***********************************************************************
76  *           MoveToEx    (GDI.483)
77  */
78 BOOL MoveToEx( HDC hdc, short x, short y, LPPOINT pt )
79 {
80     DC * dc = (DC *) GDI_GetObjPtr( hdc, DC_MAGIC );
81     if (!dc) return FALSE;
82     if (pt)
83     {
84         pt->x = dc->w.CursPosX;
85         pt->y = dc->w.CursPosY;
86     }
87     dc->w.CursPosX = x;
88     dc->w.CursPosY = y;
89     return TRUE;
90 }
91
92
93 /***********************************************************************
94  *           GRAPH_DrawArc
95  *
96  * Helper functions for Arc(), Chord() and Pie().
97  * 'lines' is the number of lines to draw: 0 for Arc, 1 for Chord, 2 for Pie.
98  */
99 static BOOL GRAPH_DrawArc( HDC hdc, int left, int top, int right, int bottom,
100                     int xstart, int ystart, int xend, int yend, int lines )
101 {
102     int xcenter, ycenter, istart_angle, idiff_angle, tmp;
103     double start_angle, end_angle;
104     XPoint points[3];
105     DC * dc = (DC *) GDI_GetObjPtr( hdc, DC_MAGIC );
106     if (!dc) 
107     {
108         dc = (DC *)GDI_GetObjPtr(hdc, METAFILE_DC_MAGIC);
109         if (!dc) return FALSE;
110         switch (lines)
111         {
112         case 0:
113             MF_MetaParam8(dc, META_ARC, left, top, right, bottom,
114                           xstart, ystart, xend, yend);
115             break;
116
117         case 1:
118             MF_MetaParam8(dc, META_CHORD, left, top, right, bottom,
119                           xstart, ystart, xend, yend);
120             break;
121
122         case 2:
123             MF_MetaParam8(dc, META_PIE, left, top, right, bottom,
124                           xstart, ystart, xend, yend);
125             break;
126         }
127         return 0;
128     }
129
130     left   = XLPTODP( dc, left );
131     top    = YLPTODP( dc, top );
132     right  = XLPTODP( dc, right );
133     bottom = YLPTODP( dc, bottom );
134     xstart = XLPTODP( dc, xstart );
135     ystart = YLPTODP( dc, ystart );
136     xend   = XLPTODP( dc, xend );
137     yend   = YLPTODP( dc, yend );
138     if ((left == right) || (top == bottom)) return FALSE;
139
140     xcenter = (right + left) / 2;
141     ycenter = (bottom + top) / 2;
142     start_angle = atan2( (double)(ycenter-ystart)*(right-left),
143                          (double)(xstart-xcenter)*(bottom-top) );
144     end_angle   = atan2( (double)(ycenter-yend)*(right-left),
145                          (double)(xend-xcenter)*(bottom-top) );
146     istart_angle = (int)(start_angle * 180 * 64 / PI);
147     idiff_angle  = (int)((end_angle - start_angle) * 180 * 64 / PI );
148     if (idiff_angle <= 0) idiff_angle += 360 * 64;
149     if (left > right) { tmp=left; left=right; right=tmp; }
150     if (top > bottom) { tmp=top; top=bottom; bottom=tmp; }
151
152       /* Fill arc with brush if Chord() or Pie() */
153
154     if ((lines > 0) && DC_SetupGCForBrush( dc ))
155     {
156         XSetArcMode( display, dc->u.x.gc, (lines==1) ? ArcChord : ArcPieSlice);
157         XFillArc( display, dc->u.x.drawable, dc->u.x.gc,
158                  dc->w.DCOrgX + left, dc->w.DCOrgY + top,
159                  right-left-1, bottom-top-1, istart_angle, idiff_angle );
160     }
161
162       /* Draw arc and lines */
163
164     if (!DC_SetupGCForPen( dc )) return TRUE;
165     XDrawArc( display, dc->u.x.drawable, dc->u.x.gc,
166               dc->w.DCOrgX + left, dc->w.DCOrgY + top,
167               right-left-1, bottom-top-1, istart_angle, idiff_angle );
168     if (!lines) return TRUE;
169
170     points[0].x = dc->w.DCOrgX + xcenter + (int)(cos(start_angle) * (right-left) / 2);
171     points[0].y = dc->w.DCOrgY + ycenter - (int)(sin(start_angle) * (bottom-top) / 2);
172     points[1].x = dc->w.DCOrgX + xcenter + (int)(cos(end_angle) * (right-left) / 2);
173     points[1].y = dc->w.DCOrgY + ycenter - (int)(sin(end_angle) * (bottom-top) / 2);
174     if (lines == 2)
175     {
176         points[2] = points[1];
177         points[1].x = dc->w.DCOrgX + xcenter;
178         points[1].y = dc->w.DCOrgY + ycenter;
179     }
180     XDrawLines( display, dc->u.x.drawable, dc->u.x.gc,
181                 points, lines+1, CoordModeOrigin );
182     return TRUE;
183 }
184
185
186 /***********************************************************************
187  *           Arc    (GDI.23)
188  */
189 BOOL Arc( HDC hdc, INT left, INT top, INT right, INT bottom,
190           INT xstart, INT ystart, INT xend, INT yend )
191 {
192     return GRAPH_DrawArc( hdc, left, top, right, bottom,
193                           xstart, ystart, xend, yend, 0 );
194 }
195
196
197 /***********************************************************************
198  *           Pie    (GDI.26)
199  */
200 BOOL Pie( HDC hdc, INT left, INT top, INT right, INT bottom,
201           INT xstart, INT ystart, INT xend, INT yend )
202 {
203     return GRAPH_DrawArc( hdc, left, top, right, bottom,
204                           xstart, ystart, xend, yend, 2 );
205 }
206
207
208 /***********************************************************************
209  *           Chord    (GDI.348)
210  */
211 BOOL Chord( HDC hdc, INT left, INT top, INT right, INT bottom,
212             INT xstart, INT ystart, INT xend, INT yend )
213 {
214     return GRAPH_DrawArc( hdc, left, top, right, bottom,
215                           xstart, ystart, xend, yend, 1 );
216 }
217
218
219 /***********************************************************************
220  *           Ellipse    (GDI.24)
221  */
222 BOOL Ellipse( HDC hdc, INT left, INT top, INT right, INT bottom )
223 {
224     DC * dc = (DC *) GDI_GetObjPtr( hdc, DC_MAGIC );
225     if (!dc) 
226     {
227         dc = (DC *)GDI_GetObjPtr(hdc, METAFILE_DC_MAGIC);
228         if (!dc) return FALSE;
229         MF_MetaParam4(dc, META_ELLIPSE, left, top, right, bottom);
230         return 0;
231     }
232
233     left   = XLPTODP( dc, left );
234     top    = YLPTODP( dc, top );
235     right  = XLPTODP( dc, right );
236     bottom = YLPTODP( dc, bottom );
237     if ((left == right) || (top == bottom)) return FALSE;
238
239     if (right < left) { INT tmp = right; right = left; left = tmp; }
240     if (bottom < top) { INT tmp = bottom; bottom = top; top = tmp; }
241     
242     if ((dc->u.x.pen.style == PS_INSIDEFRAME) &&
243         (dc->u.x.pen.width < right-left-1) &&
244         (dc->u.x.pen.width < bottom-top-1))
245     {
246         left   += dc->u.x.pen.width / 2;
247         right  -= (dc->u.x.pen.width + 1) / 2;
248         top    += dc->u.x.pen.width / 2;
249         bottom -= (dc->u.x.pen.width + 1) / 2;
250     }
251
252     if (DC_SetupGCForBrush( dc ))
253         XFillArc( display, dc->u.x.drawable, dc->u.x.gc,
254                   dc->w.DCOrgX + left, dc->w.DCOrgY + top,
255                   right-left-1, bottom-top-1, 0, 360*64 );
256     if (DC_SetupGCForPen( dc ))
257         XDrawArc( display, dc->u.x.drawable, dc->u.x.gc,
258                   dc->w.DCOrgX + left, dc->w.DCOrgY + top,
259                   right-left-1, bottom-top-1, 0, 360*64 );
260     return TRUE;
261 }
262
263
264 /***********************************************************************
265  *           Rectangle    (GDI.27)
266  */
267 BOOL Rectangle( HDC hdc, INT left, INT top, INT right, INT bottom )
268 {
269     DC * dc = (DC *) GDI_GetObjPtr( hdc, DC_MAGIC );
270     if (!dc) 
271     {
272         dc = (DC *)GDI_GetObjPtr(hdc, METAFILE_DC_MAGIC);
273         if (!dc) return FALSE;
274         MF_MetaParam4(dc, META_RECTANGLE, left, top, right, bottom);
275         return TRUE;
276     }
277     left   = XLPTODP( dc, left );
278     top    = YLPTODP( dc, top );
279     right  = XLPTODP( dc, right );
280     bottom = YLPTODP( dc, bottom );
281
282     if (right < left) { INT tmp = right; right = left; left = tmp; }
283     if (bottom < top) { INT tmp = bottom; bottom = top; top = tmp; }
284
285     if ((left == right) || (top == bottom))
286     {
287         if (DC_SetupGCForPen( dc ))
288             XDrawLine(display, dc->u.x.drawable, dc->u.x.gc, 
289                   dc->w.DCOrgX + left,
290                   dc->w.DCOrgY + top,
291                   dc->w.DCOrgX + right,
292                   dc->w.DCOrgY + bottom);
293         return TRUE;
294     }
295     
296     if ((dc->u.x.pen.style == PS_INSIDEFRAME) &&
297         (dc->u.x.pen.width < right-left) &&
298         (dc->u.x.pen.width < bottom-top))
299     {
300         left   += dc->u.x.pen.width / 2;
301         right  -= (dc->u.x.pen.width + 1) / 2;
302         top    += dc->u.x.pen.width / 2;
303         bottom -= (dc->u.x.pen.width + 1) / 2;
304     }
305
306     if (DC_SetupGCForBrush( dc ))
307         XFillRectangle( display, dc->u.x.drawable, dc->u.x.gc,
308                         dc->w.DCOrgX + left, dc->w.DCOrgY + top,
309                         right-left, bottom-top );
310     if (DC_SetupGCForPen( dc ))
311         XDrawRectangle( display, dc->u.x.drawable, dc->u.x.gc,
312                         dc->w.DCOrgX + left, dc->w.DCOrgY + top,
313                         right-left-1, bottom-top-1 );
314     return TRUE;
315 }
316
317
318 /***********************************************************************
319  *           RoundRect    (GDI.28)
320  */
321 BOOL RoundRect( HDC hDC, INT left, INT top, INT right, INT bottom,
322                 INT ell_width, INT ell_height )
323 {
324     DC * dc = (DC *) GDI_GetObjPtr(hDC, DC_MAGIC);
325     if (!dc) 
326     {
327         dc = (DC *)GDI_GetObjPtr(hDC, METAFILE_DC_MAGIC);
328         if (!dc) return FALSE;
329         MF_MetaParam6(dc, META_ROUNDRECT, left, top, right, bottom,
330                       ell_width, ell_height);
331         return TRUE;
332     }
333     dprintf_graphics(stddeb, "RoundRect(%d %d %d %d  %d %d\n", 
334         left, top, right, bottom, ell_width, ell_height);
335
336     left   = XLPTODP( dc, left );
337     top    = YLPTODP( dc, top );
338     right  = XLPTODP( dc, right );
339     bottom = YLPTODP( dc, bottom );
340     ell_width  = abs( ell_width * dc->w.VportExtX / dc->w.WndExtX );
341     ell_height = abs( ell_height * dc->w.VportExtY / dc->w.WndExtY );
342
343     /* Fix the coordinates */
344
345     if (right < left) { INT tmp = right; right = left; left = tmp; }
346     if (bottom < top) { INT tmp = bottom; bottom = top; top = tmp; }
347     if (ell_width > right - left) ell_width = right - left;
348     if (ell_height > bottom - top) ell_height = bottom - top;
349
350     if (DC_SetupGCForBrush( dc ))
351     {
352         if (ell_width && ell_height)
353         {
354             XFillArc( display, dc->u.x.drawable, dc->u.x.gc,
355                       dc->w.DCOrgX + left, dc->w.DCOrgY + top,
356                       ell_width, ell_height, 90 * 64, 90 * 64 );
357             XFillArc( display, dc->u.x.drawable, dc->u.x.gc,
358                       dc->w.DCOrgX + left, dc->w.DCOrgY + bottom - ell_height,
359                       ell_width, ell_height, 180 * 64, 90 * 64 );
360             XFillArc( display, dc->u.x.drawable, dc->u.x.gc,
361                       dc->w.DCOrgX + right - ell_width,
362                       dc->w.DCOrgY + bottom - ell_height,
363                       ell_width, ell_height, 270 * 64, 90 * 64 );
364             XFillArc( display, dc->u.x.drawable, dc->u.x.gc,
365                       dc->w.DCOrgX + right - ell_width, dc->w.DCOrgY + top,
366                       ell_width, ell_height, 0, 90 * 64 );
367         }
368         if (ell_width < right - left)
369         {
370             XFillRectangle( display, dc->u.x.drawable, dc->u.x.gc,
371                             dc->w.DCOrgX + left + ell_width / 2,
372                             dc->w.DCOrgY + top,
373                             right - left - ell_width, ell_height / 2 );
374             XFillRectangle( display, dc->u.x.drawable, dc->u.x.gc,
375                             dc->w.DCOrgX + left + ell_width / 2,
376                             dc->w.DCOrgY + bottom - (ell_height+1) / 2,
377                             right - left - ell_width, (ell_height+1) / 2 );
378         }
379         if  (ell_height < bottom - top)
380         {
381             XFillRectangle( display, dc->u.x.drawable, dc->u.x.gc,
382                             dc->w.DCOrgX + left,
383                             dc->w.DCOrgY + top + ell_height / 2,
384                             right - left, bottom - top - ell_height );
385         }
386     }
387     if (DC_SetupGCForPen(dc))
388     {
389         if (ell_width && ell_height)
390         {
391             XDrawArc( display, dc->u.x.drawable, dc->u.x.gc,
392                       dc->w.DCOrgX + left, dc->w.DCOrgY + top,
393                       ell_width, ell_height, 90 * 64, 90 * 64 );
394             XDrawArc( display, dc->u.x.drawable, dc->u.x.gc,
395                       dc->w.DCOrgX + left, dc->w.DCOrgY + bottom - ell_height,
396                       ell_width, ell_height, 180 * 64, 90 * 64 );
397             XDrawArc( display, dc->u.x.drawable, dc->u.x.gc,
398                       dc->w.DCOrgX + right - ell_width,
399                       dc->w.DCOrgY + bottom - ell_height,
400                       ell_width, ell_height, 270 * 64, 90 * 64 );
401             XDrawArc( display, dc->u.x.drawable, dc->u.x.gc,
402                       dc->w.DCOrgX + right - ell_width, dc->w.DCOrgY + top,
403                       ell_width, ell_height, 0, 90 * 64 );
404         }
405         if (ell_width < right - left)
406         {
407             XDrawLine( display, dc->u.x.drawable, dc->u.x.gc, 
408                        dc->w.DCOrgX + left + ell_width / 2,
409                        dc->w.DCOrgY + top,
410                        dc->w.DCOrgX + right - ell_width / 2,
411                        dc->w.DCOrgY + top );
412             XDrawLine( display, dc->u.x.drawable, dc->u.x.gc, 
413                        dc->w.DCOrgX + left + ell_width / 2,
414                        dc->w.DCOrgY + bottom,
415                        dc->w.DCOrgX + right - ell_width / 2,
416                        dc->w.DCOrgY + bottom );
417         }
418         if (ell_height < bottom - top)
419         {
420             XDrawLine( display, dc->u.x.drawable, dc->u.x.gc, 
421                        dc->w.DCOrgX + right,
422                        dc->w.DCOrgY + top + ell_height / 2,
423                        dc->w.DCOrgX + right,
424                        dc->w.DCOrgY + bottom - ell_height / 2 );
425             XDrawLine( display, dc->u.x.drawable, dc->u.x.gc, 
426                        dc->w.DCOrgX + left,
427                        dc->w.DCOrgY + top + ell_height / 2,
428                        dc->w.DCOrgX + left,
429                        dc->w.DCOrgY + bottom - ell_height / 2 );
430         }
431     }
432     return TRUE;
433 }
434
435
436 /***********************************************************************
437  *           FillRect    (USER.81)
438  */
439 int FillRect( HDC hdc, LPRECT rect, HBRUSH hbrush )
440 {
441     HBRUSH prevBrush;
442
443     if ((rect->right <= rect->left) || (rect->bottom <= rect->top)) return 0;
444     if (!(prevBrush = SelectObject( hdc, hbrush ))) return 0;
445     PatBlt( hdc, rect->left, rect->top,
446             rect->right - rect->left, rect->bottom - rect->top, PATCOPY );
447     SelectObject( hdc, prevBrush );
448     return 1;
449 }
450
451
452 /***********************************************************************
453  *           InvertRect    (USER.82)
454  */
455 void InvertRect( HDC hdc, LPRECT rect )
456 {
457     if ((rect->right <= rect->left) || (rect->bottom <= rect->top)) return;
458     PatBlt( hdc, rect->left, rect->top,
459             rect->right - rect->left, rect->bottom - rect->top, DSTINVERT );
460 }
461
462
463 /***********************************************************************
464  *           FrameRect    (USER.83)
465  */
466 int FrameRect( HDC hdc, LPRECT rect, HBRUSH hbrush )
467 {
468     HBRUSH prevBrush;
469     int left, top, right, bottom;
470
471     DC * dc = (DC *) GDI_GetObjPtr( hdc, DC_MAGIC );
472     if (!dc) return FALSE;
473
474     if ((rect->right <= rect->left) || (rect->bottom <= rect->top)) return 0;
475     if (!(prevBrush = SelectObject( hdc, hbrush ))) return 0;
476     
477     left   = XLPTODP( dc, rect->left );
478     top    = YLPTODP( dc, rect->top );
479     right  = XLPTODP( dc, rect->right );
480     bottom = YLPTODP( dc, rect->bottom );
481     
482     if (DC_SetupGCForBrush( dc ))
483     {
484         PatBlt( hdc, rect->left, rect->top, 1,
485             rect->bottom - rect->top, PATCOPY );
486         PatBlt( hdc, rect->right - 1, rect->top, 1,
487             rect->bottom - rect->top, PATCOPY );
488         PatBlt( hdc, rect->left, rect->top,
489             rect->right - rect->left, 1, PATCOPY );
490         PatBlt( hdc, rect->left, rect->bottom - 1,
491             rect->right - rect->left, 1, PATCOPY );
492         }    
493     SelectObject( hdc, prevBrush );
494     return 1;
495 }
496
497
498 /***********************************************************************
499  *           SetPixel    (GDI.31)
500  */
501 COLORREF SetPixel( HDC hdc, short x, short y, COLORREF color )
502 {
503     Pixel pixel;
504     PALETTEENTRY entry;
505     
506     DC * dc = (DC *) GDI_GetObjPtr( hdc, DC_MAGIC );
507     if (!dc) 
508     {
509         dc = (DC *)GDI_GetObjPtr(hdc, METAFILE_DC_MAGIC);
510         if (!dc) return 0;
511         MF_MetaParam4(dc, META_SETPIXEL, x, y, HIWORD(color), LOWORD(color)); 
512         return 1;
513     }
514
515     x = dc->w.DCOrgX + XLPTODP( dc, x );
516     y = dc->w.DCOrgY + YLPTODP( dc, y );
517     pixel = COLOR_ToPhysical( dc, color );
518     
519     XSetForeground( display, dc->u.x.gc, pixel );
520     XSetFunction( display, dc->u.x.gc, GXcopy );
521     XDrawPoint( display, dc->u.x.drawable, dc->u.x.gc, x, y );
522
523     if (screenDepth <= 8)
524     {
525         GetPaletteEntries( dc->w.hPalette, pixel, 1, &entry );
526         return RGB( entry.peRed, entry.peGreen, entry.peBlue );
527     }
528     else return (COLORREF)pixel;
529 }
530
531
532 /***********************************************************************
533  *           GetPixel    (GDI.83)
534  */
535 COLORREF GetPixel( HDC hdc, short x, short y )
536 {
537     PALETTEENTRY entry;
538     XImage * image;
539     WORD * mapping;
540     int pixel;
541
542     DC * dc = (DC *) GDI_GetObjPtr( hdc, DC_MAGIC );
543     if (!dc) return 0;
544
545 #ifdef SOLITAIRE_SPEED_HACK
546     return 0;
547 #endif
548
549     if (!PtVisible( hdc, x, y )) return 0;
550
551     x = dc->w.DCOrgX + XLPTODP( dc, x );
552     y = dc->w.DCOrgY + YLPTODP( dc, y );
553     image = XGetImage( display, dc->u.x.drawable, x, y,
554                        1, 1, AllPlanes, ZPixmap );
555     pixel = XGetPixel( image, 0, 0 );
556     XDestroyImage( image );
557     
558     if (screenDepth > 8) return pixel;
559     mapping = (WORD *) GDI_HEAP_LIN_ADDR( dc->u.x.pal.hRevMapping );
560     if (mapping) pixel = mapping[pixel];
561     GetPaletteEntries( dc->w.hPalette, pixel, 1, &entry );
562     return RGB( entry.peRed, entry.peGreen, entry.peBlue );
563 }
564
565
566 /***********************************************************************
567  *           PaintRgn    (GDI.43)
568  */
569 BOOL PaintRgn( HDC hdc, HRGN hrgn )
570 {
571     RECT box;
572     HRGN tmpVisRgn, prevVisRgn;
573     DC * dc = (DC *) GDI_GetObjPtr( hdc, DC_MAGIC );
574     if (!dc) return FALSE;
575
576       /* Modify visible region */
577
578     if (!(prevVisRgn = SaveVisRgn( hdc ))) return FALSE;
579     if (!(tmpVisRgn = CreateRectRgn( 0, 0, 0, 0 )))
580     {
581         RestoreVisRgn( hdc );
582         return FALSE;
583     }
584     CombineRgn( tmpVisRgn, prevVisRgn, hrgn, RGN_AND );
585     SelectVisRgn( hdc, tmpVisRgn );
586     DeleteObject( tmpVisRgn );
587
588       /* Fill the region */
589
590     GetRgnBox( dc->w.hGCClipRgn, &box );
591     if (DC_SetupGCForBrush( dc ))
592         XFillRectangle( display, dc->u.x.drawable, dc->u.x.gc,
593                         dc->w.DCOrgX + box.left, dc->w.DCOrgY + box.top,
594                         box.right-box.left, box.bottom-box.top );
595
596       /* Restore the visible region */
597
598     RestoreVisRgn( hdc );
599     return TRUE;
600 }
601
602
603 /***********************************************************************
604  *           FillRgn    (GDI.40)
605  */
606 BOOL FillRgn( HDC hdc, HRGN hrgn, HBRUSH hbrush )
607 {
608     BOOL retval;
609     HBRUSH prevBrush = SelectObject( hdc, hbrush );
610     if (!prevBrush) return FALSE;
611     retval = PaintRgn( hdc, hrgn );
612     SelectObject( hdc, prevBrush );
613     return retval;
614 }
615
616 /***********************************************************************
617  *           FrameRgn     (GDI.41)
618  */
619 BOOL FrameRgn( HDC hdc, HRGN hrgn, HBRUSH hbrush, int nWidth, int nHeight )
620 {
621     HRGN tmp = CreateRectRgn( 0, 0, 0, 0 );
622     if(!REGION_FrameRgn( tmp, hrgn, nWidth, nHeight )) return 0;
623     FillRgn( hdc, tmp, hbrush );
624     DeleteObject( tmp );
625     return 1;
626 }
627
628 /***********************************************************************
629  *           InvertRgn    (GDI.42)
630  */
631 BOOL InvertRgn( HDC hdc, HRGN hrgn )
632 {
633     HBRUSH prevBrush = SelectObject( hdc, GetStockObject(BLACK_BRUSH) );
634     WORD prevROP = SetROP2( hdc, R2_NOT );
635     BOOL retval = PaintRgn( hdc, hrgn );
636     SelectObject( hdc, prevBrush );
637     SetROP2( hdc, prevROP );
638     return retval;
639 }
640
641
642 /***********************************************************************
643  *           DrawFocusRect    (USER.466)
644  */
645 void DrawFocusRect( HDC hdc, const RECT* rc )
646 {
647     HPEN hOldPen;
648     int oldDrawMode, oldBkMode;
649     int left, top, right, bottom;
650     DC * dc = (DC *) GDI_GetObjPtr( hdc, DC_MAGIC );
651     if (!dc) return;
652
653     left   = XLPTODP( dc, rc->left );
654     top    = YLPTODP( dc, rc->top );
655     right  = XLPTODP( dc, rc->right );
656     bottom = YLPTODP( dc, rc->bottom );
657     
658     hOldPen = (HPEN)SelectObject(hdc, sysColorObjects.hpenWindowText );
659     oldDrawMode = SetROP2(hdc, R2_XORPEN);
660     oldBkMode = SetBkMode(hdc, TRANSPARENT);
661
662     /* Hack: make sure the XORPEN operation has an effect */
663     dc->u.x.pen.pixel = (1 << screenDepth) - 1;
664
665     if (DC_SetupGCForPen( dc ))
666         XDrawRectangle( display, dc->u.x.drawable, dc->u.x.gc,
667                         dc->w.DCOrgX + left, dc->w.DCOrgY + top,
668                         right-left-1, bottom-top-1 );
669
670     SetBkMode(hdc, oldBkMode);
671     SetROP2(hdc, oldDrawMode);
672     SelectObject(hdc, (HANDLE)hOldPen);
673 }
674
675
676 /**********************************************************************
677  *          GRAPH_DrawBitmap
678  *
679  * Short-cut function to blit a bitmap into a device.
680  * Faster than CreateCompatibleDC() + SelectBitmap() + BitBlt() + DeleteDC().
681  */
682 BOOL GRAPH_DrawBitmap( HDC hdc, HBITMAP hbitmap, int xdest, int ydest,
683                        int xsrc, int ysrc, int width, int height )
684 {
685     BITMAPOBJ *bmp;
686     DC *dc;
687     
688     if (!(dc = (DC *) GDI_GetObjPtr( hdc, DC_MAGIC ))) return FALSE;
689     if (!(bmp = (BITMAPOBJ *) GDI_GetObjPtr( hbitmap, BITMAP_MAGIC )))
690         return FALSE;
691     XSetFunction( display, dc->u.x.gc, GXcopy );
692     if (bmp->bitmap.bmBitsPixel == 1)
693     {
694         XSetForeground( display, dc->u.x.gc, dc->w.backgroundPixel );
695         XSetBackground( display, dc->u.x.gc, dc->w.textPixel );
696         XCopyPlane( display, bmp->pixmap, dc->u.x.drawable, dc->u.x.gc,
697                     xsrc, ysrc, width, height,
698                     dc->w.DCOrgX + xdest, dc->w.DCOrgY + ydest, 1 );
699         return TRUE;
700     }
701     else if (bmp->bitmap.bmBitsPixel == dc->w.bitsPerPixel)
702     {
703         XCopyArea( display, bmp->pixmap, dc->u.x.drawable, dc->u.x.gc,
704                    xsrc, ysrc, width, height,
705                    dc->w.DCOrgX + xdest, dc->w.DCOrgY + ydest );
706         return TRUE;
707     }
708     else return FALSE;
709 }
710
711
712 /**********************************************************************
713  *          GRAPH_DrawReliefRect  (Not a MSWin Call)
714  */
715 void GRAPH_DrawReliefRect( HDC hdc, RECT *rect, int highlight_size,
716                            int shadow_size, BOOL pressed )
717 {
718     HBRUSH hbrushOld;
719     int i;
720
721     hbrushOld = SelectObject( hdc, pressed ? sysColorObjects.hbrushBtnShadow :
722                                           sysColorObjects.hbrushBtnHighlight );
723     for (i = 0; i < highlight_size; i++)
724     {
725         PatBlt( hdc, rect->left + i, rect->top,
726                 1, rect->bottom - rect->top - i, PATCOPY );
727         PatBlt( hdc, rect->left, rect->top + i,
728                 rect->right - rect->left - i, 1, PATCOPY );
729     }
730
731     SelectObject( hdc, pressed ? sysColorObjects.hbrushBtnHighlight :
732                                  sysColorObjects.hbrushBtnShadow );
733     for (i = 0; i < shadow_size; i++)
734     {
735         PatBlt( hdc, rect->right - i - 1, rect->top + i,
736                 1, rect->bottom - rect->top - i, PATCOPY );
737         PatBlt( hdc, rect->left + i, rect->bottom - i - 1,
738                 rect->right - rect->left - i, 1, PATCOPY );
739     }
740
741     SelectObject( hdc, hbrushOld );
742 }
743
744
745 /**********************************************************************
746  *          Polyline  (GDI.37)
747  */
748 BOOL Polyline (HDC hdc, LPPOINT pt, int count)
749 {
750     register int i;
751     DC * dc = (DC *) GDI_GetObjPtr( hdc, DC_MAGIC );
752     if (!dc) 
753     {
754         dc = (DC *)GDI_GetObjPtr(hdc, METAFILE_DC_MAGIC);
755         if (!dc) return FALSE;
756         MF_MetaPoly(dc, META_POLYLINE, pt, count); 
757         return TRUE;
758     }
759
760     if (DC_SetupGCForPen( dc ))
761         for (i = 0; i < count-1; i ++)
762             XDrawLine (display, dc->u.x.drawable, dc->u.x.gc,  
763                        dc->w.DCOrgX + XLPTODP(dc, pt [i].x),
764                        dc->w.DCOrgY + YLPTODP(dc, pt [i].y),
765                        dc->w.DCOrgX + XLPTODP(dc, pt [i+1].x),
766                        dc->w.DCOrgY + YLPTODP(dc, pt [i+1].y));
767     return TRUE;
768 }
769
770
771 /**********************************************************************
772  *          Polygon  (GDI.36)
773  */
774 BOOL Polygon (HDC hdc, LPPOINT pt, int count)
775 {
776     register int i;
777     DC * dc = (DC *) GDI_GetObjPtr( hdc, DC_MAGIC );
778     XPoint *points = (XPoint *) xmalloc (sizeof (XPoint) * (count+1));
779
780     if (!dc) 
781     {
782         dc = (DC *)GDI_GetObjPtr(hdc, METAFILE_DC_MAGIC);
783         if (!dc) return FALSE;
784         MF_MetaPoly(dc, META_POLYGON, pt, count); 
785         return TRUE;
786     }
787
788     for (i = 0; i < count; i++)
789     {
790         points[i].x = dc->w.DCOrgX + XLPTODP( dc, pt[i].x );
791         points[i].y = dc->w.DCOrgY + YLPTODP( dc, pt[i].y );
792     }
793     points[count] = points[0];
794
795     if (DC_SetupGCForBrush( dc ))
796         XFillPolygon( display, dc->u.x.drawable, dc->u.x.gc,
797                      points, count+1, Complex, CoordModeOrigin);
798
799     if (DC_SetupGCForPen ( dc ))
800         XDrawLines( display, dc->u.x.drawable, dc->u.x.gc,
801                    points, count+1, CoordModeOrigin );
802
803     free( points );
804     return TRUE;
805 }
806
807
808 /**********************************************************************
809  *          PolyPolygon  (GDI.450)
810  */
811 BOOL PolyPolygon( HDC hdc, LPPOINT pt, LPINT16 counts, WORD polygons )
812 {
813     HRGN hrgn;
814     DC * dc = (DC *) GDI_GetObjPtr( hdc, DC_MAGIC );
815
816     if (!dc) 
817     {
818         dc = (DC *)GDI_GetObjPtr(hdc, METAFILE_DC_MAGIC);
819         if (!dc) return FALSE;
820         /* MF_MetaPoly(dc, META_POLYGON, pt, count); */
821         return TRUE;
822     }
823       /* FIXME: The points should be converted to device coords before */
824       /* creating the region. But as CreatePolyPolygonRgn is not */
825       /* really correct either, it doesn't matter much... */
826       /* At least the outline will be correct :-) */
827     hrgn = CreatePolyPolygonRgn( pt, counts, polygons, dc->w.polyFillMode );
828     PaintRgn( hdc, hrgn );
829     DeleteObject( hrgn );
830
831       /* Draw the outline of the polygons */
832
833     if (DC_SetupGCForPen ( dc ))
834     {
835         int i, j, max = 0;
836         XPoint *points;
837
838         for (i = 0; i < polygons; i++) if (counts[i] > max) max = counts[i];
839         points = (XPoint *) xmalloc( sizeof(XPoint) * (max+1) );
840
841         for (i = 0; i < polygons; i++)
842         {
843             for (j = 0; j < counts[i]; j++)
844             {
845                 points[j].x = dc->w.DCOrgX + XLPTODP( dc, pt->x );
846                 points[j].y = dc->w.DCOrgY + YLPTODP( dc, pt->y );
847                 pt++;
848             }
849             points[j] = points[0];
850             XDrawLines( display, dc->u.x.drawable, dc->u.x.gc,
851                         points, j + 1, CoordModeOrigin );
852         }
853         free( points );
854     }
855     return TRUE;
856 }
857
858
859 /**********************************************************************
860  *          GRAPH_InternalFloodFill
861  *
862  * Internal helper function for flood fill.
863  * (xorg,yorg) is the origin of the X image relative to the drawable.
864  * (x,y) is relative to the origin of the X image.
865  */
866 static void GRAPH_InternalFloodFill( XImage *image, DC *dc,
867                                      int x, int y,
868                                      int xOrg, int yOrg,
869                                      Pixel pixel, WORD fillType )
870 {
871     int left, right;
872
873 #define TO_FLOOD(x,y)  ((fillType == FLOODFILLBORDER) ? \
874                         (XGetPixel(image,x,y) != pixel) : \
875                         (XGetPixel(image,x,y) == pixel))
876
877     if (!TO_FLOOD(x,y)) return;
878
879       /* Find left and right boundaries */
880
881     left = right = x;
882     while ((left > 0) && TO_FLOOD( left-1, y )) left--;
883     while ((right < image->width) && TO_FLOOD( right, y )) right++;
884     XFillRectangle( display, dc->u.x.drawable, dc->u.x.gc,
885                     xOrg + left, yOrg + y, right-left, 1 );
886
887       /* Set the pixels of this line so we don't fill it again */
888
889     for (x = left; x < right; x++)
890     {
891         if (fillType == FLOODFILLBORDER) XPutPixel( image, x, y, pixel );
892         else XPutPixel( image, x, y, ~pixel );
893     }
894
895       /* Fill the line above */
896
897     if (--y >= 0)
898     {
899         x = left;
900         while (x < right)
901         {
902             while ((x < right) && !TO_FLOOD(x,y)) x++;
903             if (x >= right) break;
904             while ((x < right) && TO_FLOOD(x,y)) x++;
905             GRAPH_InternalFloodFill( image, dc, x-1, y,
906                                      xOrg, yOrg, pixel, fillType );
907         }
908     }
909
910       /* Fill the line below */
911
912     if ((y += 2) < image->height)
913     {
914         x = left;
915         while (x < right)
916         {
917             while ((x < right) && !TO_FLOOD(x,y)) x++;
918             if (x >= right) break;
919             while ((x < right) && TO_FLOOD(x,y)) x++;
920             GRAPH_InternalFloodFill( image, dc, x-1, y,
921                                      xOrg, yOrg, pixel, fillType );
922         }
923     }
924 #undef TO_FLOOD    
925 }
926
927
928 /**********************************************************************
929  *          GRAPH_DoFloodFill
930  *
931  * Main flood-fill routine.
932  */
933 static BOOL GRAPH_DoFloodFill( DC *dc, RECT *rect, INT x, INT y,
934                                COLORREF color, WORD fillType )
935 {
936     XImage *image;
937
938     if (!(image = XGetImage( display, dc->u.x.drawable,
939                              dc->w.DCOrgX + rect->left,
940                              dc->w.DCOrgY + rect->top,
941                              rect->right - rect->left,
942                              rect->bottom - rect->top,
943                              AllPlanes, ZPixmap ))) return FALSE;
944
945     if (DC_SetupGCForBrush( dc ))
946     {
947           /* ROP mode is always GXcopy for flood-fill */
948         XSetFunction( display, dc->u.x.gc, GXcopy );
949         GRAPH_InternalFloodFill( image, dc,
950                                  XLPTODP(dc,x) - rect->left,
951                                  YLPTODP(dc,y) - rect->top,
952                                  dc->w.DCOrgX + rect->left,
953                                  dc->w.DCOrgY + rect->top,
954                                  COLOR_ToPhysical( dc, color ), fillType );
955     }
956
957     XDestroyImage( image );
958     return TRUE;
959 }
960
961
962 /**********************************************************************
963  *          ExtFloodFill  (GDI.372)
964  */
965 BOOL ExtFloodFill( HDC hdc, INT x, INT y, COLORREF color, WORD fillType )
966 {
967     RECT rect;
968     DC *dc;
969
970     dprintf_graphics( stddeb, "ExtFloodFill %04x %d,%d %06lx %d\n",
971                       hdc, x, y, color, fillType );
972     dc = (DC *) GDI_GetObjPtr(hdc, DC_MAGIC);
973     if (!dc) 
974     {
975         dc = (DC *)GDI_GetObjPtr(hdc, METAFILE_DC_MAGIC);
976         if (!dc) return FALSE;
977         MF_MetaParam4(dc, META_FLOODFILL, x, y, HIWORD(color), 
978                       LOWORD(color)); 
979         return TRUE;
980     }
981
982     if (!PtVisible( hdc, x, y )) return FALSE;
983     if (GetRgnBox( dc->w.hGCClipRgn, &rect ) == ERROR) return FALSE;
984
985     return CallTo32_LargeStack( (int(*)())GRAPH_DoFloodFill, 6,
986                                 dc, &rect, x, y, color, fillType );
987 }
988
989
990 /**********************************************************************
991  *          FloodFill  (GDI.25)
992  */
993 BOOL FloodFill( HDC hdc, INT x, INT y, COLORREF color )
994 {
995     return ExtFloodFill( hdc, x, y, color, FLOODFILLBORDER );
996 }
997
998
999 /**********************************************************************
1000  *          DrawEdge  (USER.659)
1001  */
1002 BOOL DrawEdge(HDC hdc, LPRECT qrc, UINT edge, UINT flags)
1003 {
1004         fprintf(stdnimp,"DrawEdge(%x,%p,%d,%x), empty stub!\n",
1005                 hdc,qrc,edge,flags
1006         );
1007         return TRUE;
1008 }
1009
1010 /**********************************************************************
1011  *          DrawFrameControl  (USER.656)
1012  */
1013 BOOL DrawFrameControl(HDC hdc, LPRECT qrc, UINT edge, UINT flags)
1014 {
1015         fprintf(stdnimp,"DrawFrameControl(%x,%p,%d,%x), empty stub!\n",
1016                 hdc,qrc,edge,flags
1017         );
1018         return TRUE;
1019 }