Release 951212
[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, LPRECT 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     if (DC_SetupGCForPen( dc ))
663         XDrawRectangle( display, dc->u.x.drawable, dc->u.x.gc,
664                         dc->w.DCOrgX + left, dc->w.DCOrgY + top,
665                         right-left-1, bottom-top-1 );
666
667     SetBkMode(hdc, oldBkMode);
668     SetROP2(hdc, oldDrawMode);
669     SelectObject(hdc, (HANDLE)hOldPen);
670 }
671
672
673 /**********************************************************************
674  *          GRAPH_DrawBitmap
675  *
676  * Short-cut function to blit a bitmap into a device.
677  * Faster than CreateCompatibleDC() + SelectBitmap() + BitBlt() + DeleteDC().
678  */
679 BOOL GRAPH_DrawBitmap( HDC hdc, HBITMAP hbitmap, int xdest, int ydest,
680                        int xsrc, int ysrc, int width, int height )
681 {
682     BITMAPOBJ *bmp;
683     DC *dc;
684     
685     if (!(dc = (DC *) GDI_GetObjPtr( hdc, DC_MAGIC ))) return FALSE;
686     if (!(bmp = (BITMAPOBJ *) GDI_GetObjPtr( hbitmap, BITMAP_MAGIC )))
687         return FALSE;
688     XSetFunction( display, dc->u.x.gc, GXcopy );
689     if (bmp->bitmap.bmBitsPixel == 1)
690     {
691         XSetForeground( display, dc->u.x.gc, dc->w.backgroundPixel );
692         XSetBackground( display, dc->u.x.gc, dc->w.textPixel );
693         XCopyPlane( display, bmp->pixmap, dc->u.x.drawable, dc->u.x.gc,
694                     xsrc, ysrc, width, height,
695                     dc->w.DCOrgX + xdest, dc->w.DCOrgY + ydest, 1 );
696         return TRUE;
697     }
698     else if (bmp->bitmap.bmBitsPixel == dc->w.bitsPerPixel)
699     {
700         XCopyArea( display, bmp->pixmap, dc->u.x.drawable, dc->u.x.gc,
701                    xsrc, ysrc, width, height,
702                    dc->w.DCOrgX + xdest, dc->w.DCOrgY + ydest );
703         return TRUE;
704     }
705     else return FALSE;
706 }
707
708
709 /**********************************************************************
710  *          GRAPH_DrawReliefRect  (Not a MSWin Call)
711  */
712 void GRAPH_DrawReliefRect( HDC hdc, RECT *rect, int highlight_size,
713                            int shadow_size, BOOL pressed )
714 {
715     HBRUSH hbrushOld;
716     int i;
717
718     hbrushOld = SelectObject( hdc, pressed ? sysColorObjects.hbrushBtnShadow :
719                                           sysColorObjects.hbrushBtnHighlight );
720     for (i = 0; i < highlight_size; i++)
721     {
722         PatBlt( hdc, rect->left + i, rect->top,
723                 1, rect->bottom - rect->top - i, PATCOPY );
724         PatBlt( hdc, rect->left, rect->top + i,
725                 rect->right - rect->left - i, 1, PATCOPY );
726     }
727
728     SelectObject( hdc, pressed ? sysColorObjects.hbrushBtnHighlight :
729                                  sysColorObjects.hbrushBtnShadow );
730     for (i = 0; i < shadow_size; i++)
731     {
732         PatBlt( hdc, rect->right - i - 1, rect->top + i,
733                 1, rect->bottom - rect->top - i, PATCOPY );
734         PatBlt( hdc, rect->left + i, rect->bottom - i - 1,
735                 rect->right - rect->left - i, 1, PATCOPY );
736     }
737
738     SelectObject( hdc, hbrushOld );
739 }
740
741
742 /**********************************************************************
743  *          Polyline  (GDI.37)
744  */
745 BOOL Polyline (HDC hdc, LPPOINT pt, int count)
746 {
747     register int i;
748     DC * dc = (DC *) GDI_GetObjPtr( hdc, DC_MAGIC );
749     if (!dc) 
750     {
751         dc = (DC *)GDI_GetObjPtr(hdc, METAFILE_DC_MAGIC);
752         if (!dc) return FALSE;
753         MF_MetaPoly(dc, META_POLYLINE, pt, count); 
754         return TRUE;
755     }
756
757     if (DC_SetupGCForPen( dc ))
758         for (i = 0; i < count-1; i ++)
759             XDrawLine (display, dc->u.x.drawable, dc->u.x.gc,  
760                        dc->w.DCOrgX + XLPTODP(dc, pt [i].x),
761                        dc->w.DCOrgY + YLPTODP(dc, pt [i].y),
762                        dc->w.DCOrgX + XLPTODP(dc, pt [i+1].x),
763                        dc->w.DCOrgY + YLPTODP(dc, pt [i+1].y));
764     return TRUE;
765 }
766
767
768 /**********************************************************************
769  *          Polygon  (GDI.36)
770  */
771 BOOL Polygon (HDC hdc, LPPOINT pt, int count)
772 {
773     register int i;
774     DC * dc = (DC *) GDI_GetObjPtr( hdc, DC_MAGIC );
775     XPoint *points = (XPoint *) xmalloc (sizeof (XPoint) * (count+1));
776
777     if (!dc) 
778     {
779         dc = (DC *)GDI_GetObjPtr(hdc, METAFILE_DC_MAGIC);
780         if (!dc) return FALSE;
781         MF_MetaPoly(dc, META_POLYGON, pt, count); 
782         return TRUE;
783     }
784
785     for (i = 0; i < count; i++)
786     {
787         points[i].x = dc->w.DCOrgX + XLPTODP( dc, pt[i].x );
788         points[i].y = dc->w.DCOrgY + YLPTODP( dc, pt[i].y );
789     }
790     points[count] = points[0];
791
792     if (DC_SetupGCForBrush( dc ))
793         XFillPolygon( display, dc->u.x.drawable, dc->u.x.gc,
794                      points, count+1, Complex, CoordModeOrigin);
795
796     if (DC_SetupGCForPen ( dc ))
797         XDrawLines( display, dc->u.x.drawable, dc->u.x.gc,
798                    points, count+1, CoordModeOrigin );
799
800     free( points );
801     return TRUE;
802 }
803
804
805 /**********************************************************************
806  *          PolyPolygon  (GDI.450)
807  */
808 BOOL PolyPolygon( HDC hdc, LPPOINT pt, LPINT counts, WORD polygons )
809 {
810     HRGN hrgn;
811     DC * dc = (DC *) GDI_GetObjPtr( hdc, DC_MAGIC );
812
813     if (!dc) 
814     {
815         dc = (DC *)GDI_GetObjPtr(hdc, METAFILE_DC_MAGIC);
816         if (!dc) return FALSE;
817         /* MF_MetaPoly(dc, META_POLYGON, pt, count); */
818         return TRUE;
819     }
820       /* FIXME: The points should be converted to device coords before */
821       /* creating the region. But as CreatePolyPolygonRgn is not */
822       /* really correct either, it doesn't matter much... */
823       /* At least the outline will be correct :-) */
824     hrgn = CreatePolyPolygonRgn( pt, counts, polygons, dc->w.polyFillMode );
825     PaintRgn( hdc, hrgn );
826     DeleteObject( hrgn );
827
828       /* Draw the outline of the polygons */
829
830     if (DC_SetupGCForPen ( dc ))
831     {
832         int i, j, max = 0;
833         XPoint *points;
834
835         for (i = 0; i < polygons; i++) if (counts[i] > max) max = counts[i];
836         points = (XPoint *) xmalloc( sizeof(XPoint) * (max+1) );
837
838         for (i = 0; i < polygons; i++)
839         {
840             for (j = 0; j < counts[i]; j++)
841             {
842                 points[j].x = dc->w.DCOrgX + XLPTODP( dc, pt->x );
843                 points[j].y = dc->w.DCOrgY + YLPTODP( dc, pt->y );
844                 pt++;
845             }
846             points[j] = points[0];
847             XDrawLines( display, dc->u.x.drawable, dc->u.x.gc,
848                         points, j + 1, CoordModeOrigin );
849         }
850         free( points );
851     }
852     return TRUE;
853 }
854
855
856 /**********************************************************************
857  *          GRAPH_InternalFloodFill
858  *
859  * Internal helper function for flood fill.
860  * (xorg,yorg) is the origin of the X image relative to the drawable.
861  * (x,y) is relative to the origin of the X image.
862  */
863 static void GRAPH_InternalFloodFill( XImage *image, DC *dc,
864                                      int x, int y,
865                                      int xOrg, int yOrg,
866                                      Pixel pixel, WORD fillType )
867 {
868     int left, right;
869
870 #define TO_FLOOD(x,y)  ((fillType == FLOODFILLBORDER) ? \
871                         (XGetPixel(image,x,y) != pixel) : \
872                         (XGetPixel(image,x,y) == pixel))
873
874     if (!TO_FLOOD(x,y)) return;
875
876       /* Find left and right boundaries */
877
878     left = right = x;
879     while ((left > 0) && TO_FLOOD( left-1, y )) left--;
880     while ((right < image->width) && TO_FLOOD( right, y )) right++;
881     XFillRectangle( display, dc->u.x.drawable, dc->u.x.gc,
882                     xOrg + left, yOrg + y, right-left, 1 );
883
884       /* Set the pixels of this line so we don't fill it again */
885
886     for (x = left; x < right; x++)
887     {
888         if (fillType == FLOODFILLBORDER) XPutPixel( image, x, y, pixel );
889         else XPutPixel( image, x, y, ~pixel );
890     }
891
892       /* Fill the line above */
893
894     if (--y >= 0)
895     {
896         x = left;
897         while (x < right)
898         {
899             while ((x < right) && !TO_FLOOD(x,y)) x++;
900             if (x >= right) break;
901             while ((x < right) && TO_FLOOD(x,y)) x++;
902             GRAPH_InternalFloodFill( image, dc, x-1, y,
903                                      xOrg, yOrg, pixel, fillType );
904         }
905     }
906
907       /* Fill the line below */
908
909     if ((y += 2) < image->height)
910     {
911         x = left;
912         while (x < right)
913         {
914             while ((x < right) && !TO_FLOOD(x,y)) x++;
915             if (x >= right) break;
916             while ((x < right) && TO_FLOOD(x,y)) x++;
917             GRAPH_InternalFloodFill( image, dc, x-1, y,
918                                      xOrg, yOrg, pixel, fillType );
919         }
920     }
921 #undef TO_FLOOD    
922 }
923
924
925 /**********************************************************************
926  *          GRAPH_DoFloodFill
927  *
928  * Main flood-fill routine.
929  */
930 static BOOL GRAPH_DoFloodFill( DC *dc, RECT *rect, INT x, INT y,
931                                COLORREF color, WORD fillType )
932 {
933     XImage *image;
934
935     if (!(image = XGetImage( display, dc->u.x.drawable,
936                              dc->w.DCOrgX + rect->left,
937                              dc->w.DCOrgY + rect->top,
938                              rect->right - rect->left,
939                              rect->bottom - rect->top,
940                              AllPlanes, ZPixmap ))) return FALSE;
941
942     if (DC_SetupGCForBrush( dc ))
943     {
944           /* ROP mode is always GXcopy for flood-fill */
945         XSetFunction( display, dc->u.x.gc, GXcopy );
946         GRAPH_InternalFloodFill( image, dc,
947                                  XLPTODP(dc,x) - rect->left,
948                                  YLPTODP(dc,y) - rect->top,
949                                  dc->w.DCOrgX + rect->left,
950                                  dc->w.DCOrgY + rect->top,
951                                  COLOR_ToPhysical( dc, color ), fillType );
952     }
953
954     XDestroyImage( image );
955     return TRUE;
956 }
957
958
959 /**********************************************************************
960  *          ExtFloodFill  (GDI.372)
961  */
962 BOOL ExtFloodFill( HDC hdc, INT x, INT y, COLORREF color, WORD fillType )
963 {
964     RECT rect;
965     DC *dc;
966
967     dprintf_graphics( stddeb, "ExtFloodFill "NPFMT" %d,%d %06lx %d\n",
968                       hdc, x, y, color, fillType );
969     dc = (DC *) GDI_GetObjPtr(hdc, DC_MAGIC);
970     if (!dc) 
971     {
972         dc = (DC *)GDI_GetObjPtr(hdc, METAFILE_DC_MAGIC);
973         if (!dc) return FALSE;
974         MF_MetaParam4(dc, META_FLOODFILL, x, y, HIWORD(color), 
975                       LOWORD(color)); 
976         return TRUE;
977     }
978
979     if (!PtVisible( hdc, x, y )) return FALSE;
980     if (GetRgnBox( dc->w.hGCClipRgn, &rect ) == ERROR) return FALSE;
981
982     return CallTo32_LargeStack( (int(*)())GRAPH_DoFloodFill, 6,
983                                 dc, &rect, x, y, color, fillType );
984 }
985
986
987 /**********************************************************************
988  *          FloodFill  (GDI.25)
989  */
990 BOOL FloodFill( HDC hdc, INT x, INT y, COLORREF color )
991 {
992     return ExtFloodFill( hdc, x, y, color, FLOODFILLBORDER );
993 }