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