Release 951003
[wine/hacks.git] / windows / graphics.c
blob608fbea13d3c5fbc23d7beb340113be83c765f10
1 /*
2 * GDI graphics operations
4 * Copyright 1993, 1994 Alexandre Julliard
5 */
7 #include <math.h>
8 #include <stdlib.h>
9 #include <X11/Xlib.h>
10 #include <X11/Xutil.h>
11 #include <X11/Intrinsic.h>
12 #ifndef PI
13 #define PI M_PI
14 #endif
15 #include "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"
25 static __inline__ void swap_int(int *a, int *b)
27 int c;
29 c = *a;
30 *a = *b;
31 *b = c;
34 /***********************************************************************
35 * LineTo (GDI.19)
37 BOOL LineTo( HDC hdc, short x, short y )
39 DC * dc = (DC *) GDI_GetObjPtr( hdc, DC_MAGIC );
40 if (!dc)
42 dc = (DC *)GDI_GetObjPtr(hdc, METAFILE_DC_MAGIC);
43 if (!dc) return FALSE;
44 MF_MetaParam2(dc, META_LINETO, x, y);
45 return TRUE;
48 if (DC_SetupGCForPen( dc ))
49 XDrawLine(display, dc->u.x.drawable, dc->u.x.gc,
50 dc->w.DCOrgX + XLPTODP( dc, dc->w.CursPosX ),
51 dc->w.DCOrgY + YLPTODP( dc, dc->w.CursPosY ),
52 dc->w.DCOrgX + XLPTODP( dc, x ),
53 dc->w.DCOrgY + YLPTODP( dc, y ) );
54 dc->w.CursPosX = x;
55 dc->w.CursPosY = y;
56 return TRUE;
60 /***********************************************************************
61 * MoveTo (GDI.20)
63 DWORD MoveTo( HDC hdc, short x, short y )
65 short oldx, oldy;
66 DC * dc = (DC *) GDI_GetObjPtr( hdc, DC_MAGIC );
67 if (!dc)
69 dc = (DC *)GDI_GetObjPtr(hdc, METAFILE_DC_MAGIC);
70 if (!dc) return FALSE;
71 MF_MetaParam2(dc, META_MOVETO, x, y);
72 return 0;
75 oldx = dc->w.CursPosX;
76 oldy = dc->w.CursPosY;
77 dc->w.CursPosX = x;
78 dc->w.CursPosY = y;
79 return oldx | (oldy << 16);
83 /***********************************************************************
84 * MoveToEx (GDI.483)
86 BOOL MoveToEx( HDC hdc, short x, short y, LPPOINT pt )
88 DC * dc = (DC *) GDI_GetObjPtr( hdc, DC_MAGIC );
89 if (!dc) return FALSE;
90 if (pt)
92 pt->x = dc->w.CursPosX;
93 pt->y = dc->w.CursPosY;
95 dc->w.CursPosX = x;
96 dc->w.CursPosY = y;
97 return TRUE;
101 /***********************************************************************
102 * GRAPH_DrawArc
104 * Helper functions for Arc(), Chord() and Pie().
105 * 'lines' is the number of lines to draw: 0 for Arc, 1 for Chord, 2 for Pie.
107 static BOOL GRAPH_DrawArc( HDC hdc, int left, int top, int right, int bottom,
108 int xstart, int ystart, int xend, int yend, int lines )
110 int xcenter, ycenter, istart_angle, idiff_angle;
111 double start_angle, end_angle;
112 XPoint points[3];
113 DC * dc = (DC *) GDI_GetObjPtr( hdc, DC_MAGIC );
114 if (!dc)
116 dc = (DC *)GDI_GetObjPtr(hdc, METAFILE_DC_MAGIC);
117 if (!dc) return FALSE;
118 switch (lines)
120 case 0:
121 MF_MetaParam8(dc, META_ARC, left, top, right, bottom,
122 xstart, ystart, xend, yend);
123 break;
125 case 1:
126 MF_MetaParam8(dc, META_CHORD, left, top, right, bottom,
127 xstart, ystart, xend, yend);
128 break;
130 case 2:
131 MF_MetaParam8(dc, META_PIE, left, top, right, bottom,
132 xstart, ystart, xend, yend);
133 break;
135 return 0;
138 left = XLPTODP( dc, left );
139 top = YLPTODP( dc, top );
140 right = XLPTODP( dc, right );
141 bottom = YLPTODP( dc, bottom );
142 xstart = XLPTODP( dc, xstart );
143 ystart = YLPTODP( dc, ystart );
144 xend = XLPTODP( dc, xend );
145 yend = YLPTODP( dc, yend );
146 if ((left == right) || (top == bottom)) return FALSE;
148 xcenter = (right + left) / 2;
149 ycenter = (bottom + top) / 2;
150 start_angle = atan2( (double)(ycenter-ystart)*(right-left),
151 (double)(xstart-xcenter)*(bottom-top) );
152 end_angle = atan2( (double)(ycenter-yend)*(right-left),
153 (double)(xend-xcenter)*(bottom-top) );
154 istart_angle = (int)(start_angle * 180 * 64 / PI);
155 idiff_angle = (int)((end_angle - start_angle) * 180 * 64 / PI );
156 if (idiff_angle <= 0) idiff_angle += 360 * 64;
157 if (left > right) swap_int( &left, &right );
158 if (top > bottom) swap_int( &top, &bottom );
160 /* Fill arc with brush if Chord() or Pie() */
162 if ((lines > 0) && DC_SetupGCForBrush( dc ))
164 XSetArcMode( display, dc->u.x.gc, (lines==1) ? ArcChord : ArcPieSlice);
165 XFillArc( 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 );
170 /* Draw arc and lines */
172 if (!DC_SetupGCForPen( dc )) return TRUE;
173 XDrawArc( display, dc->u.x.drawable, dc->u.x.gc,
174 dc->w.DCOrgX + left, dc->w.DCOrgY + top,
175 right-left-1, bottom-top-1, istart_angle, idiff_angle );
176 if (!lines) return TRUE;
178 points[0].x = dc->w.DCOrgX + xcenter + (int)(cos(start_angle) * (right-left) / 2);
179 points[0].y = dc->w.DCOrgY + ycenter - (int)(sin(start_angle) * (bottom-top) / 2);
180 points[1].x = dc->w.DCOrgX + xcenter + (int)(cos(end_angle) * (right-left) / 2);
181 points[1].y = dc->w.DCOrgY + ycenter - (int)(sin(end_angle) * (bottom-top) / 2);
182 if (lines == 2)
184 points[2] = points[1];
185 points[1].x = dc->w.DCOrgX + xcenter;
186 points[1].y = dc->w.DCOrgY + ycenter;
188 XDrawLines( display, dc->u.x.drawable, dc->u.x.gc,
189 points, lines+1, CoordModeOrigin );
190 return TRUE;
194 /***********************************************************************
195 * Arc (GDI.23)
197 BOOL Arc( HDC hdc, int left, int top, int right, int bottom,
198 int xstart, int ystart, int xend, int yend )
200 return GRAPH_DrawArc( hdc, left, top, right, bottom,
201 xstart, ystart, xend, yend, 0 );
205 /***********************************************************************
206 * Pie (GDI.26)
208 BOOL Pie( HDC hdc, int left, int top, int right, int bottom,
209 int xstart, int ystart, int xend, int yend )
211 return GRAPH_DrawArc( hdc, left, top, right, bottom,
212 xstart, ystart, xend, yend, 2 );
216 /***********************************************************************
217 * Chord (GDI.348)
219 BOOL Chord( HDC hdc, int left, int top, int right, int bottom,
220 int xstart, int ystart, int xend, int yend )
222 return GRAPH_DrawArc( hdc, left, top, right, bottom,
223 xstart, ystart, xend, yend, 1 );
227 /***********************************************************************
228 * Ellipse (GDI.24)
230 BOOL Ellipse( HDC hdc, int left, int top, int right, int bottom )
232 DC * dc = (DC *) GDI_GetObjPtr( hdc, DC_MAGIC );
233 if (!dc)
235 dc = (DC *)GDI_GetObjPtr(hdc, METAFILE_DC_MAGIC);
236 if (!dc) return FALSE;
237 MF_MetaParam4(dc, META_ELLIPSE, left, top, right, bottom);
238 return 0;
241 left = XLPTODP( dc, left );
242 top = YLPTODP( dc, top );
243 right = XLPTODP( dc, right );
244 bottom = YLPTODP( dc, bottom );
245 if ((left == right) || (top == bottom)) return FALSE;
247 if (right < left)
248 swap_int(&right, &left);
250 if (bottom < top)
251 swap_int(&bottom, &top);
253 if ((dc->u.x.pen.style == PS_INSIDEFRAME) &&
254 (dc->u.x.pen.width < right-left-1) &&
255 (dc->u.x.pen.width < bottom-top-1))
257 left += dc->u.x.pen.width / 2;
258 right -= (dc->u.x.pen.width + 1) / 2;
259 top += dc->u.x.pen.width / 2;
260 bottom -= (dc->u.x.pen.width + 1) / 2;
263 if (DC_SetupGCForBrush( dc ))
264 XFillArc( display, dc->u.x.drawable, dc->u.x.gc,
265 dc->w.DCOrgX + left, dc->w.DCOrgY + top,
266 right-left-1, bottom-top-1, 0, 360*64 );
267 if (DC_SetupGCForPen( dc ))
268 XDrawArc( display, dc->u.x.drawable, dc->u.x.gc,
269 dc->w.DCOrgX + left, dc->w.DCOrgY + top,
270 right-left-1, bottom-top-1, 0, 360*64 );
271 return TRUE;
275 /***********************************************************************
276 * Rectangle (GDI.27)
278 BOOL Rectangle( HDC hdc, int left, int top, int right, int bottom )
280 DC * dc = (DC *) GDI_GetObjPtr( hdc, DC_MAGIC );
281 if (!dc)
283 dc = (DC *)GDI_GetObjPtr(hdc, METAFILE_DC_MAGIC);
284 if (!dc) return FALSE;
285 MF_MetaParam4(dc, META_RECTANGLE, left, top, right, bottom);
286 return TRUE;
288 left = XLPTODP( dc, left );
289 top = YLPTODP( dc, top );
290 right = XLPTODP( dc, right );
291 bottom = YLPTODP( dc, bottom );
293 if (right < left)
294 swap_int(&right, &left);
296 if (bottom < top)
297 swap_int(&bottom, &top);
299 if ((left == right) || (top == bottom))
301 if (DC_SetupGCForPen( dc ))
302 XDrawLine(display, dc->u.x.drawable, dc->u.x.gc,
303 dc->w.DCOrgX + left,
304 dc->w.DCOrgY + top,
305 dc->w.DCOrgX + right,
306 dc->w.DCOrgY + bottom);
307 return TRUE;
310 if ((dc->u.x.pen.style == PS_INSIDEFRAME) &&
311 (dc->u.x.pen.width < right-left) &&
312 (dc->u.x.pen.width < bottom-top))
314 left += dc->u.x.pen.width / 2;
315 right -= (dc->u.x.pen.width + 1) / 2;
316 top += dc->u.x.pen.width / 2;
317 bottom -= (dc->u.x.pen.width + 1) / 2;
320 if (DC_SetupGCForBrush( dc ))
321 XFillRectangle( display, dc->u.x.drawable, dc->u.x.gc,
322 dc->w.DCOrgX + left, dc->w.DCOrgY + top,
323 right-left, bottom-top );
324 if (DC_SetupGCForPen( dc ))
325 XDrawRectangle( display, dc->u.x.drawable, dc->u.x.gc,
326 dc->w.DCOrgX + left, dc->w.DCOrgY + top,
327 right-left-1, bottom-top-1 );
328 return TRUE;
332 /***********************************************************************
333 * RoundRect (GDI.28)
335 BOOL RoundRect( HDC hDC, short left, short top, short right, short bottom,
336 short ell_width, short ell_height )
338 DC * dc = (DC *) GDI_GetObjPtr(hDC, DC_MAGIC);
339 if (!dc)
341 dc = (DC *)GDI_GetObjPtr(hDC, METAFILE_DC_MAGIC);
342 if (!dc) return FALSE;
343 MF_MetaParam6(dc, META_ROUNDRECT, left, top, right, bottom,
344 ell_width, ell_height);
345 return TRUE;
347 dprintf_graphics(stddeb, "RoundRect(%d %d %d %d %d %d\n",
348 left, top, right, bottom, ell_width, ell_height);
350 left = XLPTODP( dc, left );
351 top = YLPTODP( dc, top );
352 right = XLPTODP( dc, right );
353 bottom = YLPTODP( dc, bottom );
354 ell_width = abs( ell_width * dc->w.VportExtX / dc->w.WndExtX );
355 ell_height = abs( ell_height * dc->w.VportExtY / dc->w.WndExtY );
357 /* Fix the coordinates */
359 if (left > right) { short t = left; left = right; right = t; }
360 if (top > bottom) { short t = top; top = bottom; bottom = t; }
361 if (ell_width > right - left) ell_width = right - left;
362 if (ell_height > bottom - top) ell_height = bottom - top;
364 if (DC_SetupGCForBrush( dc ))
366 if (ell_width && ell_height)
368 XFillArc( display, dc->u.x.drawable, dc->u.x.gc,
369 dc->w.DCOrgX + left, dc->w.DCOrgY + top,
370 ell_width, ell_height, 90 * 64, 90 * 64 );
371 XFillArc( display, dc->u.x.drawable, dc->u.x.gc,
372 dc->w.DCOrgX + left, dc->w.DCOrgY + bottom - ell_height,
373 ell_width, ell_height, 180 * 64, 90 * 64 );
374 XFillArc( display, dc->u.x.drawable, dc->u.x.gc,
375 dc->w.DCOrgX + right - ell_width,
376 dc->w.DCOrgY + bottom - ell_height,
377 ell_width, ell_height, 270 * 64, 90 * 64 );
378 XFillArc( display, dc->u.x.drawable, dc->u.x.gc,
379 dc->w.DCOrgX + right - ell_width, dc->w.DCOrgY + top,
380 ell_width, ell_height, 0, 90 * 64 );
382 if (ell_width < right - left)
384 XFillRectangle( display, dc->u.x.drawable, dc->u.x.gc,
385 dc->w.DCOrgX + left + ell_width / 2,
386 dc->w.DCOrgY + top,
387 right - left - ell_width, ell_height / 2 );
388 XFillRectangle( display, dc->u.x.drawable, dc->u.x.gc,
389 dc->w.DCOrgX + left + ell_width / 2,
390 dc->w.DCOrgY + bottom - (ell_height+1) / 2,
391 right - left - ell_width, (ell_height+1) / 2 );
393 if (ell_height < bottom - top)
395 XFillRectangle( display, dc->u.x.drawable, dc->u.x.gc,
396 dc->w.DCOrgX + left,
397 dc->w.DCOrgY + top + ell_height / 2,
398 right - left, bottom - top - ell_height );
401 if (DC_SetupGCForPen(dc))
403 if (ell_width && ell_height)
405 XDrawArc( display, dc->u.x.drawable, dc->u.x.gc,
406 dc->w.DCOrgX + left, dc->w.DCOrgY + top,
407 ell_width, ell_height, 90 * 64, 90 * 64 );
408 XDrawArc( display, dc->u.x.drawable, dc->u.x.gc,
409 dc->w.DCOrgX + left, dc->w.DCOrgY + bottom - ell_height,
410 ell_width, ell_height, 180 * 64, 90 * 64 );
411 XDrawArc( display, dc->u.x.drawable, dc->u.x.gc,
412 dc->w.DCOrgX + right - ell_width,
413 dc->w.DCOrgY + bottom - ell_height,
414 ell_width, ell_height, 270 * 64, 90 * 64 );
415 XDrawArc( display, dc->u.x.drawable, dc->u.x.gc,
416 dc->w.DCOrgX + right - ell_width, dc->w.DCOrgY + top,
417 ell_width, ell_height, 0, 90 * 64 );
419 if (ell_width < right - left)
421 XDrawLine( display, dc->u.x.drawable, dc->u.x.gc,
422 dc->w.DCOrgX + left + ell_width / 2,
423 dc->w.DCOrgY + top,
424 dc->w.DCOrgX + right - ell_width / 2,
425 dc->w.DCOrgY + top );
426 XDrawLine( display, dc->u.x.drawable, dc->u.x.gc,
427 dc->w.DCOrgX + left + ell_width / 2,
428 dc->w.DCOrgY + bottom,
429 dc->w.DCOrgX + right - ell_width / 2,
430 dc->w.DCOrgY + bottom );
432 if (ell_height < bottom - top)
434 XDrawLine( display, dc->u.x.drawable, dc->u.x.gc,
435 dc->w.DCOrgX + right,
436 dc->w.DCOrgY + top + ell_height / 2,
437 dc->w.DCOrgX + right,
438 dc->w.DCOrgY + bottom - ell_height / 2 );
439 XDrawLine( display, dc->u.x.drawable, dc->u.x.gc,
440 dc->w.DCOrgX + left,
441 dc->w.DCOrgY + top + ell_height / 2,
442 dc->w.DCOrgX + left,
443 dc->w.DCOrgY + bottom - ell_height / 2 );
446 return TRUE;
450 /***********************************************************************
451 * FillRect (USER.81)
453 int FillRect( HDC hdc, LPRECT rect, HBRUSH hbrush )
455 HBRUSH prevBrush;
457 if ((rect->right <= rect->left) || (rect->bottom <= rect->top)) return 0;
458 if (!(prevBrush = SelectObject( hdc, hbrush ))) return 0;
459 PatBlt( hdc, rect->left, rect->top,
460 rect->right - rect->left, rect->bottom - rect->top, PATCOPY );
461 SelectObject( hdc, prevBrush );
462 return 1;
466 /***********************************************************************
467 * InvertRect (USER.82)
469 void InvertRect( HDC hdc, LPRECT rect )
471 if ((rect->right <= rect->left) || (rect->bottom <= rect->top)) return;
472 PatBlt( hdc, rect->left, rect->top,
473 rect->right - rect->left, rect->bottom - rect->top, DSTINVERT );
477 /***********************************************************************
478 * FrameRect (USER.83)
480 int FrameRect( HDC hdc, LPRECT rect, HBRUSH hbrush )
482 HBRUSH prevBrush;
483 int left, top, right, bottom;
485 DC * dc = (DC *) GDI_GetObjPtr( hdc, DC_MAGIC );
486 if (!dc) return FALSE;
488 if ((rect->right <= rect->left) || (rect->bottom <= rect->top)) return 0;
489 if (!(prevBrush = SelectObject( hdc, hbrush ))) return 0;
491 left = XLPTODP( dc, rect->left );
492 top = YLPTODP( dc, rect->top );
493 right = XLPTODP( dc, rect->right );
494 bottom = YLPTODP( dc, rect->bottom );
496 if (DC_SetupGCForBrush( dc ))
498 PatBlt( hdc, rect->left, rect->top, 1,
499 rect->bottom - rect->top, PATCOPY );
500 PatBlt( hdc, rect->right - 1, rect->top, 1,
501 rect->bottom - rect->top, PATCOPY );
502 PatBlt( hdc, rect->left, rect->top,
503 rect->right - rect->left, 1, PATCOPY );
504 PatBlt( hdc, rect->left, rect->bottom - 1,
505 rect->right - rect->left, 1, PATCOPY );
507 SelectObject( hdc, prevBrush );
508 return 1;
512 /***********************************************************************
513 * SetPixel (GDI.31)
515 COLORREF SetPixel( HDC hdc, short x, short y, COLORREF color )
517 Pixel pixel;
518 PALETTEENTRY entry;
520 DC * dc = (DC *) GDI_GetObjPtr( hdc, DC_MAGIC );
521 if (!dc)
523 dc = (DC *)GDI_GetObjPtr(hdc, METAFILE_DC_MAGIC);
524 if (!dc) return 0;
525 MF_MetaParam4(dc, META_SETPIXEL, x, y, HIWORD(color), LOWORD(color));
526 return 1;
529 x = dc->w.DCOrgX + XLPTODP( dc, x );
530 y = dc->w.DCOrgY + YLPTODP( dc, y );
531 pixel = COLOR_ToPhysical( dc, color );
533 XSetForeground( display, dc->u.x.gc, pixel );
534 XSetFunction( display, dc->u.x.gc, GXcopy );
535 XDrawPoint( display, dc->u.x.drawable, dc->u.x.gc, x, y );
537 if (screenDepth <= 8)
539 GetPaletteEntries( dc->w.hPalette, pixel, 1, &entry );
540 return RGB( entry.peRed, entry.peGreen, entry.peBlue );
542 else return (COLORREF)pixel;
546 /***********************************************************************
547 * GetPixel (GDI.83)
549 COLORREF GetPixel( HDC hdc, short x, short y )
551 PALETTEENTRY entry;
552 XImage * image;
553 WORD * mapping;
554 int pixel;
556 DC * dc = (DC *) GDI_GetObjPtr( hdc, DC_MAGIC );
557 if (!dc) return 0;
559 #ifdef SOLITAIRE_SPEED_HACK
560 return 0;
561 #endif
563 if (!PtVisible( hdc, x, y )) return 0;
565 x = dc->w.DCOrgX + XLPTODP( dc, x );
566 y = dc->w.DCOrgY + YLPTODP( dc, y );
567 image = XGetImage( display, dc->u.x.drawable, x, y,
568 1, 1, AllPlanes, ZPixmap );
569 pixel = XGetPixel( image, 0, 0 );
570 XDestroyImage( image );
572 if (screenDepth > 8) return pixel;
573 mapping = (WORD *) GDI_HEAP_LIN_ADDR( dc->u.x.pal.hRevMapping );
574 if (mapping) pixel = mapping[pixel];
575 GetPaletteEntries( dc->w.hPalette, pixel, 1, &entry );
576 return RGB( entry.peRed, entry.peGreen, entry.peBlue );
580 /***********************************************************************
581 * PaintRgn (GDI.43)
583 BOOL PaintRgn( HDC hdc, HRGN hrgn )
585 RECT box;
586 HRGN tmpVisRgn, prevVisRgn;
587 DC * dc = (DC *) GDI_GetObjPtr( hdc, DC_MAGIC );
588 if (!dc) return FALSE;
590 /* Modify visible region */
592 if (!(prevVisRgn = SaveVisRgn( hdc ))) return FALSE;
593 if (!(tmpVisRgn = CreateRectRgn( 0, 0, 0, 0 )))
595 RestoreVisRgn( hdc );
596 return FALSE;
598 CombineRgn( tmpVisRgn, prevVisRgn, hrgn, RGN_AND );
599 SelectVisRgn( hdc, tmpVisRgn );
600 DeleteObject( tmpVisRgn );
602 /* Fill the region */
604 GetRgnBox( dc->w.hGCClipRgn, &box );
605 if (DC_SetupGCForBrush( dc ))
606 XFillRectangle( display, dc->u.x.drawable, dc->u.x.gc,
607 dc->w.DCOrgX + box.left, dc->w.DCOrgY + box.top,
608 box.right-box.left, box.bottom-box.top );
610 /* Restore the visible region */
612 RestoreVisRgn( hdc );
613 return TRUE;
617 /***********************************************************************
618 * FillRgn (GDI.40)
620 BOOL FillRgn( HDC hdc, HRGN hrgn, HBRUSH hbrush )
622 BOOL retval;
623 HBRUSH prevBrush = SelectObject( hdc, hbrush );
624 if (!prevBrush) return FALSE;
625 retval = PaintRgn( hdc, hrgn );
626 SelectObject( hdc, prevBrush );
627 return retval;
630 /***********************************************************************
631 * FrameRgn (GDI.41)
633 BOOL FrameRgn( HDC hdc, HRGN hrgn, HBRUSH hbrush, int nWidth, int nHeight )
635 HRGN tmp = CreateRectRgn( 0, 0, 0, 0 );
636 if(!REGION_FrameRgn( tmp, hrgn, nWidth, nHeight )) return 0;
637 FillRgn( hdc, tmp, hbrush );
638 DeleteObject( tmp );
639 return 1;
642 /***********************************************************************
643 * InvertRgn (GDI.42)
645 BOOL InvertRgn( HDC hdc, HRGN hrgn )
647 HBRUSH prevBrush = SelectObject( hdc, GetStockObject(BLACK_BRUSH) );
648 WORD prevROP = SetROP2( hdc, R2_NOT );
649 BOOL retval = PaintRgn( hdc, hrgn );
650 SelectObject( hdc, prevBrush );
651 SetROP2( hdc, prevROP );
652 return retval;
656 /***********************************************************************
657 * DrawFocusRect (USER.466)
659 void DrawFocusRect( HDC hdc, LPRECT rc )
661 HPEN hOldPen;
662 int oldDrawMode, oldBkMode;
663 int left, top, right, bottom;
664 DC * dc = (DC *) GDI_GetObjPtr( hdc, DC_MAGIC );
665 if (!dc) return;
667 left = XLPTODP( dc, rc->left );
668 top = YLPTODP( dc, rc->top );
669 right = XLPTODP( dc, rc->right );
670 bottom = YLPTODP( dc, rc->bottom );
672 hOldPen = (HPEN)SelectObject(hdc, sysColorObjects.hpenWindowText );
673 oldDrawMode = SetROP2(hdc, R2_XORPEN);
674 oldBkMode = SetBkMode(hdc, TRANSPARENT);
676 if (DC_SetupGCForPen( dc ))
677 XDrawRectangle( display, dc->u.x.drawable, dc->u.x.gc,
678 dc->w.DCOrgX + left, dc->w.DCOrgY + top,
679 right-left-1, bottom-top-1 );
681 SetBkMode(hdc, oldBkMode);
682 SetROP2(hdc, oldDrawMode);
683 SelectObject(hdc, (HANDLE)hOldPen);
687 /**********************************************************************
688 * GRAPH_DrawBitmap
690 * Short-cut function to blit a bitmap into a device.
691 * Faster than CreateCompatibleDC() + SelectBitmap() + BitBlt() + DeleteDC().
693 BOOL GRAPH_DrawBitmap( HDC hdc, HBITMAP hbitmap, int xdest, int ydest,
694 int xsrc, int ysrc, int width, int height )
696 BITMAPOBJ *bmp;
697 DC *dc;
699 if (!(dc = (DC *) GDI_GetObjPtr( hdc, DC_MAGIC ))) return FALSE;
700 if (!(bmp = (BITMAPOBJ *) GDI_GetObjPtr( hbitmap, BITMAP_MAGIC )))
701 return FALSE;
702 XSetFunction( display, dc->u.x.gc, GXcopy );
703 if (bmp->bitmap.bmBitsPixel == 1)
705 XSetForeground( display, dc->u.x.gc, dc->w.backgroundPixel );
706 XSetBackground( display, dc->u.x.gc, dc->w.textPixel );
707 XCopyPlane( display, bmp->pixmap, dc->u.x.drawable, dc->u.x.gc,
708 xsrc, ysrc, width, height,
709 dc->w.DCOrgX + xdest, dc->w.DCOrgY + ydest, 1 );
710 return TRUE;
712 else if (bmp->bitmap.bmBitsPixel == dc->w.bitsPerPixel)
714 XCopyArea( display, bmp->pixmap, dc->u.x.drawable, dc->u.x.gc,
715 xsrc, ysrc, width, height,
716 dc->w.DCOrgX + xdest, dc->w.DCOrgY + ydest );
717 return TRUE;
719 else return FALSE;
723 /**********************************************************************
724 * GRAPH_DrawReliefRect (Not a MSWin Call)
726 void GRAPH_DrawReliefRect( HDC hdc, RECT *rect, int highlight_size,
727 int shadow_size, BOOL pressed )
729 HBRUSH hbrushOld;
730 int i;
732 hbrushOld = SelectObject( hdc, pressed ? sysColorObjects.hbrushBtnShadow :
733 sysColorObjects.hbrushBtnHighlight );
734 for (i = 0; i < highlight_size; i++)
736 PatBlt( hdc, rect->left + i, rect->top,
737 1, rect->bottom - rect->top - i, PATCOPY );
738 PatBlt( hdc, rect->left, rect->top + i,
739 rect->right - rect->left - i, 1, PATCOPY );
742 SelectObject( hdc, pressed ? sysColorObjects.hbrushBtnHighlight :
743 sysColorObjects.hbrushBtnShadow );
744 for (i = 0; i < shadow_size; i++)
746 PatBlt( hdc, rect->right - i - 1, rect->top + i,
747 1, rect->bottom - rect->top - i, PATCOPY );
748 PatBlt( hdc, rect->left + i, rect->bottom - i - 1,
749 rect->right - rect->left - i, 1, PATCOPY );
752 SelectObject( hdc, hbrushOld );
756 /**********************************************************************
757 * Polyline (GDI.37)
759 BOOL Polyline (HDC hdc, LPPOINT pt, int count)
761 register int i;
762 DC * dc = (DC *) GDI_GetObjPtr( hdc, DC_MAGIC );
763 if (!dc)
765 dc = (DC *)GDI_GetObjPtr(hdc, METAFILE_DC_MAGIC);
766 if (!dc) return FALSE;
767 MF_MetaPoly(dc, META_POLYLINE, pt, count);
768 return TRUE;
771 if (DC_SetupGCForPen( dc ))
772 for (i = 0; i < count-1; i ++)
773 XDrawLine (display, dc->u.x.drawable, dc->u.x.gc,
774 dc->w.DCOrgX + XLPTODP(dc, pt [i].x),
775 dc->w.DCOrgY + YLPTODP(dc, pt [i].y),
776 dc->w.DCOrgX + XLPTODP(dc, pt [i+1].x),
777 dc->w.DCOrgY + YLPTODP(dc, pt [i+1].y));
778 return TRUE;
782 /**********************************************************************
783 * Polygon (GDI.36)
785 BOOL Polygon (HDC hdc, LPPOINT pt, int count)
787 register int i;
788 DC * dc = (DC *) GDI_GetObjPtr( hdc, DC_MAGIC );
789 XPoint *points = (XPoint *) malloc (sizeof (XPoint) * (count+1));
791 if (!dc)
793 dc = (DC *)GDI_GetObjPtr(hdc, METAFILE_DC_MAGIC);
794 if (!dc) return FALSE;
795 MF_MetaPoly(dc, META_POLYGON, pt, count);
796 return TRUE;
799 for (i = 0; i < count; i++)
801 points[i].x = dc->w.DCOrgX + XLPTODP( dc, pt[i].x );
802 points[i].y = dc->w.DCOrgY + YLPTODP( dc, pt[i].y );
804 points[count] = points[0];
806 if (DC_SetupGCForBrush( dc ))
807 XFillPolygon( display, dc->u.x.drawable, dc->u.x.gc,
808 points, count+1, Complex, CoordModeOrigin);
810 if (DC_SetupGCForPen ( dc ))
811 XDrawLines( display, dc->u.x.drawable, dc->u.x.gc,
812 points, count+1, CoordModeOrigin );
814 free( points );
815 return TRUE;
819 /**********************************************************************
820 * PolyPolygon (GDI.450)
822 BOOL PolyPolygon( HDC hdc, LPPOINT pt, LPINT counts, WORD polygons )
824 HRGN hrgn;
825 DC * dc = (DC *) GDI_GetObjPtr( hdc, DC_MAGIC );
827 if (!dc)
829 dc = (DC *)GDI_GetObjPtr(hdc, METAFILE_DC_MAGIC);
830 if (!dc) return FALSE;
831 /* MF_MetaPoly(dc, META_POLYGON, pt, count); */
832 return TRUE;
834 /* FIXME: The points should be converted to device coords before */
835 /* creating the region. But as CreatePolyPolygonRgn is not */
836 /* really correct either, it doesn't matter much... */
837 /* At least the outline will be correct :-) */
838 hrgn = CreatePolyPolygonRgn( pt, counts, polygons, dc->w.polyFillMode );
839 PaintRgn( hdc, hrgn );
840 DeleteObject( hrgn );
842 /* Draw the outline of the polygons */
844 if (DC_SetupGCForPen ( dc ))
846 int i, j, max = 0;
847 XPoint *points;
849 for (i = 0; i < polygons; i++) if (counts[i] > max) max = counts[i];
850 points = (XPoint *) malloc( sizeof(XPoint) * (max+1) );
852 for (i = 0; i < polygons; i++)
854 for (j = 0; j < counts[i]; j++)
856 points[j].x = dc->w.DCOrgX + XLPTODP( dc, pt->x );
857 points[j].y = dc->w.DCOrgY + YLPTODP( dc, pt->y );
858 pt++;
860 points[j] = points[0];
861 XDrawLines( display, dc->u.x.drawable, dc->u.x.gc,
862 points, j + 1, CoordModeOrigin );
864 free( points );
866 return TRUE;
870 /**********************************************************************
871 * GRAPH_InternalFloodFill
873 * Internal helper function for flood fill.
874 * (xorg,yorg) is the origin of the X image relative to the drawable.
875 * (x,y) is relative to the origin of the X image.
877 static void GRAPH_InternalFloodFill( XImage *image, DC *dc,
878 int x, int y,
879 int xOrg, int yOrg,
880 Pixel pixel, WORD fillType )
882 int left, right;
884 #define TO_FLOOD(x,y) ((fillType == FLOODFILLBORDER) ? \
885 (XGetPixel(image,x,y) != pixel) : \
886 (XGetPixel(image,x,y) == pixel))
888 if (!TO_FLOOD(x,y)) return;
890 /* Find left and right boundaries */
892 left = right = x;
893 while ((left > 0) && TO_FLOOD( left-1, y )) left--;
894 while ((right < image->width) && TO_FLOOD( right, y )) right++;
895 XFillRectangle( display, dc->u.x.drawable, dc->u.x.gc,
896 xOrg + left, yOrg + y, right-left, 1 );
898 /* Set the pixels of this line so we don't fill it again */
900 for (x = left; x < right; x++)
902 if (fillType == FLOODFILLBORDER) XPutPixel( image, x, y, pixel );
903 else XPutPixel( image, x, y, ~pixel );
906 /* Fill the line above */
908 if (--y >= 0)
910 x = left;
911 while (x < right)
913 while ((x < right) && !TO_FLOOD(x,y)) x++;
914 if (x >= right) break;
915 while ((x < right) && TO_FLOOD(x,y)) x++;
916 GRAPH_InternalFloodFill( image, dc, x-1, y,
917 xOrg, yOrg, pixel, fillType );
921 /* Fill the line below */
923 if ((y += 2) < image->height)
925 x = left;
926 while (x < right)
928 while ((x < right) && !TO_FLOOD(x,y)) x++;
929 if (x >= right) break;
930 while ((x < right) && TO_FLOOD(x,y)) x++;
931 GRAPH_InternalFloodFill( image, dc, x-1, y,
932 xOrg, yOrg, pixel, fillType );
935 #undef TO_FLOOD
939 /**********************************************************************
940 * GRAPH_DoFloodFill
942 * Main flood-fill routine.
944 static BOOL GRAPH_DoFloodFill( DC *dc, RECT *rect, INT x, INT y,
945 COLORREF color, WORD fillType )
947 XImage *image;
949 if (!(image = XGetImage( display, dc->u.x.drawable,
950 dc->w.DCOrgX + rect->left,
951 dc->w.DCOrgY + rect->top,
952 rect->right - rect->left,
953 rect->bottom - rect->top,
954 AllPlanes, ZPixmap ))) return FALSE;
956 if (DC_SetupGCForBrush( dc ))
958 /* ROP mode is always GXcopy for flood-fill */
959 XSetFunction( display, dc->u.x.gc, GXcopy );
960 GRAPH_InternalFloodFill( image, dc,
961 XLPTODP(dc,x) - rect->left,
962 YLPTODP(dc,y) - rect->top,
963 dc->w.DCOrgX + rect->left,
964 dc->w.DCOrgY + rect->top,
965 COLOR_ToPhysical( dc, color ), fillType );
968 XDestroyImage( image );
969 return TRUE;
973 /**********************************************************************
974 * ExtFloodFill (GDI.372)
976 BOOL ExtFloodFill( HDC hdc, INT x, INT y, COLORREF color, WORD fillType )
978 RECT rect;
979 DC *dc;
981 dprintf_graphics( stddeb, "ExtFloodFill "NPFMT" %d,%d %06lx %d\n",
982 hdc, x, y, color, fillType );
983 dc = (DC *) GDI_GetObjPtr(hdc, DC_MAGIC);
984 if (!dc)
986 dc = (DC *)GDI_GetObjPtr(hdc, METAFILE_DC_MAGIC);
987 if (!dc) return FALSE;
988 MF_MetaParam4(dc, META_FLOODFILL, x, y, HIWORD(color),
989 LOWORD(color));
990 return TRUE;
993 if (!PtVisible( hdc, x, y )) return FALSE;
994 if (GetRgnBox( dc->w.hGCClipRgn, &rect ) == ERROR) return FALSE;
996 return CallTo32_LargeStack( (int(*)())GRAPH_DoFloodFill, 6,
997 dc, &rect, x, y, color, fillType );
1001 /**********************************************************************
1002 * FloodFill (GDI.25)
1004 BOOL FloodFill( HDC hdc, INT x, INT y, COLORREF color )
1006 return ExtFloodFill( hdc, x, y, color, FLOODFILLBORDER );