Release 950727
[wine/multimedia.git] / objects / region.c
blob02a10d71935f99ae28a1f0ee1e4f6791863e3c18
1 /*
2 * GDI region objects
4 * Copyright 1993, 1994, 1995 Alexandre Julliard
6 */
8 #include <stdlib.h>
9 #include <stdio.h>
11 #include "region.h"
12 #include "stddebug.h"
13 /* #define DEBUG_REGION */
14 #include "debug.h"
17 /***********************************************************************
18 * REGION_DeleteObject
20 BOOL REGION_DeleteObject( HRGN hrgn, RGNOBJ * obj )
22 dprintf_region(stddeb, "DeleteRegion: %x\n", hrgn );
23 if (obj->xrgn) XDestroyRegion( obj->xrgn );
24 return GDI_FreeObject( hrgn );
28 /***********************************************************************
29 * OffsetRgn (GDI.101)
31 int OffsetRgn( HRGN hrgn, short x, short y )
33 RGNOBJ * obj = (RGNOBJ *) GDI_GetObjPtr( hrgn, REGION_MAGIC );
34 if (!obj) return ERROR;
35 dprintf_region(stddeb, "OffsetRgn: %d %d,%d\n", hrgn, x, y );
36 if (!obj->xrgn) return NULLREGION;
37 XOffsetRegion( obj->xrgn, x, y );
38 return COMPLEXREGION;
42 /***********************************************************************
43 * GetRgnBox (GDI.134)
45 int GetRgnBox( HRGN hrgn, LPRECT rect )
47 RGNOBJ * obj = (RGNOBJ *) GDI_GetObjPtr( hrgn, REGION_MAGIC );
48 if (!obj) return ERROR;
49 dprintf_region(stddeb, "GetRgnBox: %d\n", hrgn );
50 if (!obj->xrgn)
52 SetRectEmpty( rect );
53 return NULLREGION;
55 else
57 XRectangle xrect;
58 XClipBox( obj->xrgn, &xrect );
59 SetRect( rect, xrect.x, xrect.y,
60 xrect.x + xrect.width, xrect.y + xrect.height);
61 return COMPLEXREGION;
66 /***********************************************************************
67 * CreateRectRgn (GDI.64)
69 HRGN CreateRectRgn( short left, short top, short right, short bottom )
71 HRGN hrgn;
72 RGNOBJ *obj;
74 if (!(hrgn = GDI_AllocObject( sizeof(RGNOBJ), REGION_MAGIC ))) return 0;
75 obj = (RGNOBJ *) GDI_HEAP_LIN_ADDR( hrgn );
76 if ((right > left) && (bottom > top))
78 XRectangle rect = { left, top, right - left, bottom - top };
79 if (!(obj->xrgn = XCreateRegion()))
81 GDI_FreeObject( hrgn );
82 return 0;
84 XUnionRectWithRegion( &rect, obj->xrgn, obj->xrgn );
86 else obj->xrgn = 0;
87 dprintf_region( stddeb, "CreateRectRgn(%d,%d-%d,%d): returning %x\n",
88 left, top, right, bottom, hrgn );
89 return hrgn;
93 /***********************************************************************
94 * CreateRectRgnIndirect (GDI.65)
96 HRGN CreateRectRgnIndirect( LPRECT rect )
98 return CreateRectRgn( rect->left, rect->top, rect->right, rect->bottom );
102 /***********************************************************************
103 * SetRectRgn (GDI.172)
105 void SetRectRgn( HRGN hrgn, short left, short top, short right, short bottom )
107 RGNOBJ * obj;
109 dprintf_region(stddeb, "SetRectRgn: %x %d,%d-%d,%d\n",
110 hrgn, left, top, right, bottom );
112 if (!(obj = (RGNOBJ *) GDI_GetObjPtr( hrgn, REGION_MAGIC ))) return;
113 if (obj->xrgn) XDestroyRegion( obj->xrgn );
114 if ((right > left) && (bottom > top))
116 XRectangle rect = { left, top, right - left, bottom - top };
117 if ((obj->xrgn = XCreateRegion()) != 0)
118 XUnionRectWithRegion( &rect, obj->xrgn, obj->xrgn );
120 else obj->xrgn = 0;
124 /***********************************************************************
125 * CreateRoundRectRgn (GDI.444)
127 HRGN CreateRoundRectRgn( short left, short top, short right, short bottom,
128 short ellipse_width, short ellipse_height )
130 RGNOBJ * obj;
131 HRGN hrgn;
132 XRectangle rect;
133 int asq, bsq, d, xd, yd;
135 /* Check if we can do a normal rectangle instead */
137 if ((right <= left) || (bottom <= top) ||
138 (ellipse_width <= 0) || (ellipse_height <= 0))
139 return CreateRectRgn( left, top, right, bottom );
141 /* Create region */
143 if (!(hrgn = GDI_AllocObject( sizeof(RGNOBJ), REGION_MAGIC ))) return 0;
144 obj = (RGNOBJ *) GDI_HEAP_LIN_ADDR( hrgn );
145 obj->xrgn = XCreateRegion();
146 dprintf_region(stddeb,"CreateRoundRectRgn(%d,%d-%d,%d %dx%d): return=%x\n",
147 left, top, right, bottom, ellipse_width, ellipse_height, hrgn );
149 /* Check parameters */
151 if (ellipse_width > right-left) ellipse_width = right-left;
152 if (ellipse_height > bottom-top) ellipse_height = bottom-top;
154 /* Ellipse algorithm, based on an article by K. Porter */
155 /* in DDJ Graphics Programming Column, 8/89 */
157 asq = ellipse_width * ellipse_width / 4; /* a^2 */
158 bsq = ellipse_height * ellipse_height / 4; /* b^2 */
159 d = bsq - asq * ellipse_height / 2 + asq / 4; /* b^2 - a^2b + a^2/4 */
160 xd = 0;
161 yd = asq * ellipse_height; /* 2a^2b */
163 rect.x = left + ellipse_width / 2;
164 rect.width = right - left - ellipse_width;
165 rect.height = 1;
167 /* Loop to draw first half of quadrant */
169 while (xd < yd)
171 if (d > 0) /* if nearest pixel is toward the center */
173 /* move toward center */
174 rect.y = top++;
175 XUnionRectWithRegion( &rect, obj->xrgn, obj->xrgn );
176 rect.y = --bottom;
177 XUnionRectWithRegion( &rect, obj->xrgn, obj->xrgn );
178 yd -= 2*asq;
179 d -= yd;
181 rect.x--; /* next horiz point */
182 rect.width += 2;
183 xd += 2*bsq;
184 d += bsq + xd;
187 /* Loop to draw second half of quadrant */
189 d += (3 * (asq-bsq) / 2 - (xd+yd)) / 2;
190 while (yd >= 0)
192 /* next vertical point */
193 rect.y = top++;
194 XUnionRectWithRegion( &rect, obj->xrgn, obj->xrgn );
195 rect.y = --bottom;
196 XUnionRectWithRegion( &rect, obj->xrgn, obj->xrgn );
197 if (d < 0) /* if nearest pixel is outside ellipse */
199 rect.x--; /* move away from center */
200 rect.width += 2;
201 xd += 2*bsq;
202 d += xd;
204 yd -= 2*asq;
205 d += asq - yd;
208 /* Add the inside rectangle */
210 if (top <= bottom)
212 rect.y = top;
213 rect.height = bottom - top + 1;
214 XUnionRectWithRegion( &rect, obj->xrgn, obj->xrgn );
216 return hrgn;
220 /***********************************************************************
221 * CreateEllipticRgn (GDI.54)
223 HRGN CreateEllipticRgn( short left, short top, short right, short bottom )
225 return CreateRoundRectRgn( left, top, right, bottom,
226 right-left, bottom-top );
230 /***********************************************************************
231 * CreateEllipticRgnIndirect (GDI.55)
233 HRGN CreateEllipticRgnIndirect( LPRECT rect )
235 return CreateRoundRectRgn(rect->left, rect->top, rect->right, rect->bottom,
236 rect->right-rect->left, rect->bottom-rect->top );
240 /***********************************************************************
241 * CreatePolygonRgn (GDI.63)
243 HRGN CreatePolygonRgn( POINT * points, short count, short mode )
245 return CreatePolyPolygonRgn( points, &count, 1, mode );
249 /***********************************************************************
250 * CreatePolyPolygonRgn (GDI.451)
252 HRGN CreatePolyPolygonRgn( POINT * points, short * count,
253 short nbpolygons, short mode )
255 RGNOBJ * obj;
256 HRGN hrgn;
257 int i, j, maxPoints;
258 XPoint *xpoints, *pt;
259 Region xrgn;
261 /* Allocate points array */
263 if (!nbpolygons) return 0;
264 for (i = maxPoints = 0; i < nbpolygons; i++)
265 if (maxPoints < count[i]) maxPoints = count[i];
266 if (!maxPoints) return 0;
267 if (!(xpoints = (XPoint *) malloc( sizeof(XPoint) * maxPoints )))
268 return 0;
270 /* Allocate region */
272 if (!(hrgn = GDI_AllocObject( sizeof(RGNOBJ), REGION_MAGIC )))
274 free( xpoints );
275 return 0;
277 obj = (RGNOBJ *) GDI_HEAP_LIN_ADDR( hrgn );
278 obj->xrgn = 0;
279 dprintf_region(stddeb, "CreatePolyPolygonRgn: %d polygons, returning %x\n",
280 nbpolygons, hrgn );
282 /* Create X region */
284 for (i = 0; i < nbpolygons; i++, count++)
286 for (j = *count, pt = xpoints; j > 0; j--, points++, pt++)
288 pt->x = points->x;
289 pt->y = points->y;
291 xrgn = XPolygonRegion( xpoints, *count,
292 (mode == WINDING) ? WindingRule : EvenOddRule );
293 if (!xrgn)
295 if (obj->xrgn) XDestroyRegion( obj->xrgn );
296 free( xpoints );
297 GDI_FreeObject( hrgn );
298 return 0;
300 if (i > 0)
302 Region tmprgn = XCreateRegion();
303 if (mode == WINDING) XUnionRegion( xrgn, obj->xrgn, tmprgn );
304 else XXorRegion( xrgn, obj->xrgn, tmprgn );
305 XDestroyRegion( obj->xrgn );
306 obj->xrgn = tmprgn;
308 else obj->xrgn = xrgn;
311 free( xpoints );
312 return hrgn;
316 /***********************************************************************
317 * PtInRegion (GDI.161)
319 BOOL PtInRegion( HRGN hrgn, short x, short y )
321 RGNOBJ * obj;
323 if (!(obj = (RGNOBJ *) GDI_GetObjPtr( hrgn, REGION_MAGIC ))) return FALSE;
324 if (!obj->xrgn) return FALSE;
325 return XPointInRegion( obj->xrgn, x, y );
329 /***********************************************************************
330 * RectInRegion (GDI.181)
332 BOOL RectInRegion( HRGN hrgn, LPRECT rect )
334 RGNOBJ * obj;
336 if (!(obj = (RGNOBJ *) GDI_GetObjPtr( hrgn, REGION_MAGIC ))) return FALSE;
337 if (!obj->xrgn) return FALSE;
338 return (XRectInRegion( obj->xrgn, rect->left, rect->top,
339 rect->right-rect->left,
340 rect->bottom-rect->top ) != RectangleOut);
344 /***********************************************************************
345 * EqualRgn (GDI.72)
347 BOOL EqualRgn( HRGN rgn1, HRGN rgn2 )
349 RGNOBJ *obj1, *obj2;
350 if (!(obj1 = (RGNOBJ *) GDI_GetObjPtr( rgn1, REGION_MAGIC ))) return FALSE;
351 if (!(obj2 = (RGNOBJ *) GDI_GetObjPtr( rgn2, REGION_MAGIC ))) return FALSE;
352 if (!obj1->xrgn || !obj2->xrgn) return (!obj1->xrgn && !obj2->xrgn);
353 return XEqualRegion( obj1->xrgn, obj2->xrgn );
357 /***********************************************************************
358 * REGION_CopyRegion
360 * Copy region src into dest.
362 static int REGION_CopyRegion( RGNOBJ *src, RGNOBJ *dest )
364 if (src->xrgn)
366 Region tmprgn = XCreateRegion();
367 if (!dest->xrgn) dest->xrgn = XCreateRegion();
368 XUnionRegion( tmprgn, src->xrgn, dest->xrgn );
369 XDestroyRegion( tmprgn );
370 return COMPLEXREGION;
372 else
374 if (dest->xrgn) XDestroyRegion( dest->xrgn );
375 dest->xrgn = 0;
376 return NULLREGION;
380 /***********************************************************************
381 * REGION_CreateFrameRgn
383 * Create a region that is a frame around another region
385 BOOL REGION_FrameRgn( HRGN hDest, HRGN hSrc, int x, int y )
387 RGNOBJ *destObj,*srcObj;
388 Region result;
390 destObj = (RGNOBJ*) GDI_GetObjPtr( hDest, REGION_MAGIC );
391 srcObj = (RGNOBJ*) GDI_GetObjPtr( hSrc, REGION_MAGIC );
392 if (!srcObj->xrgn) return 0;
393 REGION_CopyRegion( srcObj, destObj );
394 XShrinkRegion( destObj->xrgn, -x, -y );
395 result = XCreateRegion();
396 XSubtractRegion( destObj->xrgn, srcObj->xrgn, result );
397 XDestroyRegion( destObj->xrgn );
398 destObj->xrgn = result;
399 return 1;
402 /***********************************************************************
403 * CombineRgn (GDI.451)
405 int CombineRgn( HRGN hDest, HRGN hSrc1, HRGN hSrc2, short mode )
407 RGNOBJ *destObj, *src1Obj, *src2Obj;
409 dprintf_region(stddeb, "CombineRgn: %x,%x -> %x mode=%x\n",
410 hSrc1, hSrc2, hDest, mode );
412 if (!(destObj = (RGNOBJ *) GDI_GetObjPtr( hDest, REGION_MAGIC )))
413 return ERROR;
414 if (!(src1Obj = (RGNOBJ *) GDI_GetObjPtr( hSrc1, REGION_MAGIC )))
415 return ERROR;
416 if (mode == RGN_COPY) return REGION_CopyRegion( src1Obj, destObj );
418 if (!(src2Obj = (RGNOBJ *) GDI_GetObjPtr( hSrc2, REGION_MAGIC )))
419 return ERROR;
421 /* Some optimizations for null regions */
423 if (!src1Obj->xrgn || !src2Obj->xrgn)
425 switch(mode)
427 case RGN_DIFF:
428 if (src1Obj->xrgn)
429 return REGION_CopyRegion( src1Obj, destObj );
430 /* else fall through */
431 case RGN_AND:
432 if (destObj->xrgn) XDestroyRegion( destObj->xrgn );
433 destObj->xrgn = 0;
434 return NULLREGION;
435 case RGN_OR:
436 case RGN_XOR:
437 if (src1Obj->xrgn)
438 return REGION_CopyRegion( src1Obj, destObj );
439 else
440 return REGION_CopyRegion( src2Obj, destObj );
441 default:
442 return ERROR;
446 /* Perform the operation with the two X regions */
448 if (!destObj->xrgn) destObj->xrgn = XCreateRegion();
449 switch(mode)
451 case RGN_AND:
452 XIntersectRegion( src1Obj->xrgn, src2Obj->xrgn, destObj->xrgn );
453 break;
454 case RGN_OR:
455 XUnionRegion( src1Obj->xrgn, src2Obj->xrgn, destObj->xrgn );
456 break;
457 case RGN_XOR:
458 XXorRegion( src1Obj->xrgn, src2Obj->xrgn, destObj->xrgn );
459 break;
460 case RGN_DIFF:
461 XSubtractRegion( src1Obj->xrgn, src2Obj->xrgn, destObj->xrgn );
462 break;
463 default:
464 return ERROR;
466 if (XEmptyRegion(destObj->xrgn))
468 XDestroyRegion( destObj->xrgn );
469 destObj->xrgn = 0;
470 return NULLREGION;
472 else return COMPLEXREGION;