Release 960824
[wine/multimedia.git] / objects / region.c
bloba5e5cd6a0b0059c071fb17f5e197d3976d50aaa2
1 /*
2 * GDI region objects
4 * Copyright 1993, 1994, 1995 Alexandre Julliard
5 */
7 #define NO_TRANSITION_TYPES /* This file is Win32-clean */
8 #include <stdlib.h>
9 #include <stdio.h>
10 #include "region.h"
11 #include "stddebug.h"
12 #include "debug.h"
15 /***********************************************************************
16 * REGION_DeleteObject
18 BOOL16 REGION_DeleteObject( HRGN32 hrgn, RGNOBJ * obj )
20 dprintf_region(stddeb, "DeleteRegion: %04x\n", hrgn );
21 if (obj->xrgn) XDestroyRegion( obj->xrgn );
22 return GDI_FreeObject( hrgn );
26 /***********************************************************************
27 * OffsetRgn (GDI.101) (GDI32.256)
29 INT16 OffsetRgn( HRGN32 hrgn, INT32 x, INT32 y )
31 RGNOBJ * obj = (RGNOBJ *) GDI_GetObjPtr( hrgn, REGION_MAGIC );
32 if (!obj) return ERROR;
33 dprintf_region(stddeb, "OffsetRgn: %04x %d,%d\n", hrgn, x, y );
34 if (!obj->xrgn) return NULLREGION;
35 XOffsetRegion( obj->xrgn, x, y );
36 return COMPLEXREGION;
40 /***********************************************************************
41 * GetRgnBox16 (GDI.134)
43 INT16 GetRgnBox16( HRGN16 hrgn, LPRECT16 rect )
45 RGNOBJ * obj = (RGNOBJ *) GDI_GetObjPtr( hrgn, REGION_MAGIC );
46 if (!obj) return ERROR;
47 dprintf_region(stddeb, "GetRgnBox: %04x\n", hrgn );
48 if (!obj->xrgn)
50 SetRectEmpty16( rect );
51 return NULLREGION;
53 else
55 XRectangle xrect;
56 XClipBox( obj->xrgn, &xrect );
57 SetRect16( rect, xrect.x, xrect.y,
58 xrect.x + xrect.width, xrect.y + xrect.height);
59 return COMPLEXREGION;
64 /***********************************************************************
65 * GetRgnBox32 (GDI32.219)
67 INT32 GetRgnBox32( HRGN32 hrgn, LPRECT32 rect )
69 RECT16 r;
70 INT16 ret = GetRgnBox16( hrgn, &r );
71 CONV_RECT16TO32( &r, rect );
72 return ret;
76 /***********************************************************************
77 * CreateRectRgn (GDI.64) (GDI32.59)
79 HRGN16 CreateRectRgn( INT32 left, INT32 top, INT32 right, INT32 bottom )
81 HRGN16 hrgn;
82 RGNOBJ *obj;
84 if (!(hrgn = GDI_AllocObject( sizeof(RGNOBJ), REGION_MAGIC ))) return 0;
85 obj = (RGNOBJ *) GDI_HEAP_LIN_ADDR( hrgn );
86 if ((right > left) && (bottom > top))
88 XRectangle rect = { left, top, right - left, bottom - top };
89 if (!(obj->xrgn = XCreateRegion()))
91 GDI_FreeObject( hrgn );
92 return 0;
94 XUnionRectWithRegion( &rect, obj->xrgn, obj->xrgn );
96 else obj->xrgn = 0;
97 dprintf_region( stddeb, "CreateRectRgn(%d,%d-%d,%d): returning %04x\n",
98 left, top, right, bottom, hrgn );
99 return hrgn;
103 /***********************************************************************
104 * CreateRectRgnIndirect16 (GDI.65)
106 HRGN16 CreateRectRgnIndirect16( const RECT16* rect )
108 return CreateRectRgn( rect->left, rect->top, rect->right, rect->bottom );
112 /***********************************************************************
113 * CreateRectRgnIndirect32 (GDI32.60)
115 HRGN32 CreateRectRgnIndirect32( const RECT32* rect )
117 return CreateRectRgn( rect->left, rect->top, rect->right, rect->bottom );
121 /***********************************************************************
122 * SetRectRgn (GDI.172) (GDI32.332)
124 VOID SetRectRgn( HRGN32 hrgn, INT32 left, INT32 top, INT32 right, INT32 bottom)
126 RGNOBJ * obj;
128 dprintf_region(stddeb, "SetRectRgn: %04x %d,%d-%d,%d\n",
129 hrgn, left, top, right, bottom );
131 if (!(obj = (RGNOBJ *) GDI_GetObjPtr( hrgn, REGION_MAGIC ))) return;
132 if (obj->xrgn) XDestroyRegion( obj->xrgn );
133 if ((right > left) && (bottom > top))
135 XRectangle rect = { left, top, right - left, bottom - top };
136 if ((obj->xrgn = XCreateRegion()) != 0)
137 XUnionRectWithRegion( &rect, obj->xrgn, obj->xrgn );
139 else obj->xrgn = 0;
143 /***********************************************************************
144 * CreateRoundRectRgn (GDI.444) (GDI32.61)
146 HRGN16 CreateRoundRectRgn( INT32 left, INT32 top, INT32 right, INT32 bottom,
147 INT32 ellipse_width, INT32 ellipse_height )
149 RGNOBJ * obj;
150 HRGN16 hrgn;
151 XRectangle rect;
152 int asq, bsq, d, xd, yd;
154 /* Check if we can do a normal rectangle instead */
156 if ((right <= left) || (bottom <= top) ||
157 (ellipse_width <= 0) || (ellipse_height <= 0))
158 return CreateRectRgn( left, top, right, bottom );
160 /* Create region */
162 if (!(hrgn = GDI_AllocObject( sizeof(RGNOBJ), REGION_MAGIC ))) return 0;
163 obj = (RGNOBJ *) GDI_HEAP_LIN_ADDR( hrgn );
164 obj->xrgn = XCreateRegion();
165 dprintf_region(stddeb,"CreateRoundRectRgn(%d,%d-%d,%d %dx%d): return=%04x\n",
166 left, top, right, bottom, ellipse_width, ellipse_height, hrgn );
168 /* Check parameters */
170 if (ellipse_width > right-left) ellipse_width = right-left;
171 if (ellipse_height > bottom-top) ellipse_height = bottom-top;
173 /* Ellipse algorithm, based on an article by K. Porter */
174 /* in DDJ Graphics Programming Column, 8/89 */
176 asq = ellipse_width * ellipse_width / 4; /* a^2 */
177 bsq = ellipse_height * ellipse_height / 4; /* b^2 */
178 d = bsq - asq * ellipse_height / 2 + asq / 4; /* b^2 - a^2b + a^2/4 */
179 xd = 0;
180 yd = asq * ellipse_height; /* 2a^2b */
182 rect.x = left + ellipse_width / 2;
183 rect.width = right - left - ellipse_width;
184 rect.height = 1;
186 /* Loop to draw first half of quadrant */
188 while (xd < yd)
190 if (d > 0) /* if nearest pixel is toward the center */
192 /* move toward center */
193 rect.y = top++;
194 XUnionRectWithRegion( &rect, obj->xrgn, obj->xrgn );
195 rect.y = --bottom;
196 XUnionRectWithRegion( &rect, obj->xrgn, obj->xrgn );
197 yd -= 2*asq;
198 d -= yd;
200 rect.x--; /* next horiz point */
201 rect.width += 2;
202 xd += 2*bsq;
203 d += bsq + xd;
206 /* Loop to draw second half of quadrant */
208 d += (3 * (asq-bsq) / 2 - (xd+yd)) / 2;
209 while (yd >= 0)
211 /* next vertical point */
212 rect.y = top++;
213 XUnionRectWithRegion( &rect, obj->xrgn, obj->xrgn );
214 rect.y = --bottom;
215 XUnionRectWithRegion( &rect, obj->xrgn, obj->xrgn );
216 if (d < 0) /* if nearest pixel is outside ellipse */
218 rect.x--; /* move away from center */
219 rect.width += 2;
220 xd += 2*bsq;
221 d += xd;
223 yd -= 2*asq;
224 d += asq - yd;
227 /* Add the inside rectangle */
229 if (top <= bottom)
231 rect.y = top;
232 rect.height = bottom - top + 1;
233 XUnionRectWithRegion( &rect, obj->xrgn, obj->xrgn );
235 return hrgn;
239 /***********************************************************************
240 * CreateEllipticRgn (GDI.54) (GDI32.39)
242 HRGN16 CreateEllipticRgn( INT32 left, INT32 top, INT32 right, INT32 bottom )
244 return CreateRoundRectRgn( left, top, right, bottom,
245 right-left, bottom-top );
249 /***********************************************************************
250 * CreateEllipticRgnIndirect16 (GDI.55)
252 HRGN16 CreateEllipticRgnIndirect16( const RECT16 *rect )
254 return CreateRoundRectRgn(rect->left, rect->top, rect->right, rect->bottom,
255 rect->right-rect->left, rect->bottom-rect->top );
259 /***********************************************************************
260 * CreateEllipticRgnIndirect32 (GDI32.40)
262 HRGN32 CreateEllipticRgnIndirect32( const RECT32 *rect )
264 return CreateRoundRectRgn(rect->left, rect->top, rect->right, rect->bottom,
265 rect->right-rect->left, rect->bottom-rect->top );
269 /***********************************************************************
270 * CreatePolygonRgn16 (GDI.63)
272 HRGN16 CreatePolygonRgn16( const POINT16 * points, INT16 count, INT16 mode )
274 return CreatePolyPolygonRgn16( points, &count, 1, mode );
278 /***********************************************************************
279 * CreatePolyPolygonRgn16 (GDI.451)
281 HRGN16 CreatePolyPolygonRgn16( const POINT16 * points, const INT16 * count,
282 INT16 nbpolygons, INT16 mode )
284 RGNOBJ * obj;
285 HRGN16 hrgn;
286 int i, j, maxPoints;
287 XPoint *xpoints, *pt;
288 Region xrgn;
290 /* Allocate points array */
292 if (!nbpolygons) return 0;
293 for (i = maxPoints = 0; i < nbpolygons; i++)
294 if (maxPoints < count[i]) maxPoints = count[i];
295 if (!maxPoints) return 0;
296 if (!(xpoints = (XPoint *) malloc( sizeof(XPoint) * maxPoints )))
297 return 0;
299 /* Allocate region */
301 if (!(hrgn = GDI_AllocObject( sizeof(RGNOBJ), REGION_MAGIC )))
303 free( xpoints );
304 return 0;
306 obj = (RGNOBJ *) GDI_HEAP_LIN_ADDR( hrgn );
307 obj->xrgn = 0;
308 dprintf_region(stddeb, "CreatePolyPolygonRgn: %d polygons, returning %04x\n",
309 nbpolygons, hrgn );
311 /* Create X region */
313 for (i = 0; i < nbpolygons; i++, count++)
315 for (j = *count, pt = xpoints; j > 0; j--, points++, pt++)
317 pt->x = points->x;
318 pt->y = points->y;
320 xrgn = XPolygonRegion( xpoints, *count,
321 (mode == WINDING) ? WindingRule : EvenOddRule );
322 if (!xrgn)
324 if (obj->xrgn) XDestroyRegion( obj->xrgn );
325 free( xpoints );
326 GDI_FreeObject( hrgn );
327 return 0;
329 if (i > 0)
331 Region tmprgn = XCreateRegion();
332 if (mode == WINDING) XUnionRegion( xrgn, obj->xrgn, tmprgn );
333 else XXorRegion( xrgn, obj->xrgn, tmprgn );
334 XDestroyRegion( obj->xrgn );
335 obj->xrgn = tmprgn;
337 else obj->xrgn = xrgn;
340 free( xpoints );
341 return hrgn;
345 /***********************************************************************
346 * PtInRegion (GDI.161) (GDI32.278)
348 BOOL16 PtInRegion( HRGN32 hrgn, INT32 x, INT32 y )
350 RGNOBJ * obj;
352 if (!(obj = (RGNOBJ *) GDI_GetObjPtr( hrgn, REGION_MAGIC ))) return FALSE;
353 if (!obj->xrgn) return FALSE;
354 return XPointInRegion( obj->xrgn, x, y );
358 /***********************************************************************
359 * RectInRegion16 (GDI.181)
361 BOOL16 RectInRegion16( HRGN16 hrgn, const RECT16 *rect )
363 RGNOBJ * obj;
365 if (!(obj = (RGNOBJ *) GDI_GetObjPtr( hrgn, REGION_MAGIC ))) return FALSE;
366 if (!obj->xrgn) return FALSE;
367 return (XRectInRegion( obj->xrgn, rect->left, rect->top,
368 rect->right-rect->left,
369 rect->bottom-rect->top ) != RectangleOut);
373 /***********************************************************************
374 * RectInRegion32 (GDI32.281)
376 BOOL32 RectInRegion32( HRGN32 hrgn, const RECT32 *rect )
378 RGNOBJ * obj;
380 if (!(obj = (RGNOBJ *) GDI_GetObjPtr( hrgn, REGION_MAGIC ))) return FALSE;
381 if (!obj->xrgn) return FALSE;
382 return (XRectInRegion( obj->xrgn, rect->left, rect->top,
383 rect->right-rect->left,
384 rect->bottom-rect->top ) != RectangleOut);
388 /***********************************************************************
389 * EqualRgn (GDI.72) (GDI32.90)
391 BOOL16 EqualRgn( HRGN32 rgn1, HRGN32 rgn2 )
393 RGNOBJ *obj1, *obj2;
394 if (!(obj1 = (RGNOBJ *) GDI_GetObjPtr( rgn1, REGION_MAGIC ))) return FALSE;
395 if (!(obj2 = (RGNOBJ *) GDI_GetObjPtr( rgn2, REGION_MAGIC ))) return FALSE;
396 if (!obj1->xrgn || !obj2->xrgn) return (!obj1->xrgn && !obj2->xrgn);
397 return XEqualRegion( obj1->xrgn, obj2->xrgn );
401 /***********************************************************************
402 * REGION_CopyRegion
404 * Copy region src into dest.
406 static int REGION_CopyRegion( RGNOBJ *src, RGNOBJ *dest )
408 Region tmprgn;
409 if (src->xrgn)
411 if (src->xrgn == dest->xrgn) return COMPLEXREGION;
412 tmprgn = XCreateRegion();
413 if (!dest->xrgn) dest->xrgn = XCreateRegion();
414 XUnionRegion( tmprgn, src->xrgn, dest->xrgn );
415 XDestroyRegion( tmprgn );
416 return COMPLEXREGION;
418 else
420 if (dest->xrgn) XDestroyRegion( dest->xrgn );
421 dest->xrgn = 0;
422 return NULLREGION;
426 /***********************************************************************
427 * REGION_UnionRectWithRgn
429 * Add rectangle to region
431 BOOL16 REGION_UnionRectWithRgn( HRGN32 hRgn, LPRECT16 rc )
433 RGNOBJ *rgnObj = (RGNOBJ*) GDI_GetObjPtr( hRgn, REGION_MAGIC );
434 XRectangle rect = { rc->left, rc->top, rc->right - rc->left, rc->bottom - rc->top };
435 BOOL16 ret = 0;
437 if( rgnObj )
439 if( !rgnObj->xrgn )
441 if (!(rgnObj->xrgn = XCreateRegion()))
443 GDI_FreeObject( hRgn );
444 return 0;
446 ret = SIMPLEREGION;
448 else
449 ret = COMPLEXREGION;
450 XUnionRectWithRegion( &rect, rgnObj->xrgn, rgnObj->xrgn );
452 return ret;
455 /***********************************************************************
456 * REGION_CreateFrameRgn
458 * Create a region that is a frame around another region
460 BOOL16 REGION_FrameRgn( HRGN32 hDest, HRGN32 hSrc, INT32 x, INT32 y )
462 RGNOBJ *destObj,*srcObj;
463 Region result;
465 destObj = (RGNOBJ*) GDI_GetObjPtr( hDest, REGION_MAGIC );
466 srcObj = (RGNOBJ*) GDI_GetObjPtr( hSrc, REGION_MAGIC );
467 if (!srcObj->xrgn) return 0;
468 REGION_CopyRegion( srcObj, destObj );
469 XShrinkRegion( destObj->xrgn, -x, -y );
470 result = XCreateRegion();
471 XSubtractRegion( destObj->xrgn, srcObj->xrgn, result );
472 XDestroyRegion( destObj->xrgn );
473 destObj->xrgn = result;
474 return 1;
477 /***********************************************************************
478 * CombineRgn (GDI.451) (GDI32.19)
480 * The behavior is correct even if src and dest regions are the same.
482 INT16 CombineRgn( HRGN32 hDest, HRGN32 hSrc1, HRGN32 hSrc2, INT32 mode )
484 RGNOBJ *destObj, *src1Obj, *src2Obj;
485 Region destrgn;
487 dprintf_region(stddeb, "CombineRgn: %04x,%04x -> %04x mode=%x\n",
488 hSrc1, hSrc2, hDest, mode );
490 if (!(destObj = (RGNOBJ *) GDI_GetObjPtr( hDest, REGION_MAGIC )))
491 return ERROR;
492 if (!(src1Obj = (RGNOBJ *) GDI_GetObjPtr( hSrc1, REGION_MAGIC )))
493 return ERROR;
494 if (mode == RGN_COPY) return REGION_CopyRegion( src1Obj, destObj );
496 if (!(src2Obj = (RGNOBJ *) GDI_GetObjPtr( hSrc2, REGION_MAGIC )))
497 return ERROR;
499 /* Some optimizations for null regions */
501 if (!src1Obj->xrgn || !src2Obj->xrgn)
503 switch(mode)
505 case RGN_DIFF:
506 if (src1Obj->xrgn)
507 return REGION_CopyRegion( src1Obj, destObj );
508 /* else fall through */
509 case RGN_AND:
510 if (destObj->xrgn) XDestroyRegion( destObj->xrgn );
511 destObj->xrgn = 0;
512 return NULLREGION;
513 case RGN_OR:
514 case RGN_XOR:
515 if (src1Obj->xrgn)
516 return REGION_CopyRegion( src1Obj, destObj );
517 else
518 return REGION_CopyRegion( src2Obj, destObj );
519 default:
520 return ERROR;
524 /* Perform the operation with the two X regions */
526 if (!(destrgn = XCreateRegion())) return ERROR;
527 switch(mode)
529 case RGN_AND:
530 XIntersectRegion( src1Obj->xrgn, src2Obj->xrgn, destrgn );
531 break;
532 case RGN_OR:
533 XUnionRegion( src1Obj->xrgn, src2Obj->xrgn, destrgn );
534 break;
535 case RGN_XOR:
536 XXorRegion( src1Obj->xrgn, src2Obj->xrgn, destrgn );
537 break;
538 case RGN_DIFF:
539 XSubtractRegion( src1Obj->xrgn, src2Obj->xrgn, destrgn );
540 break;
541 default:
542 XDestroyRegion( destrgn );
543 return ERROR;
545 if (destObj->xrgn) XDestroyRegion( destObj->xrgn );
546 destObj->xrgn = destrgn;
547 if (XEmptyRegion(destObj->xrgn))
549 XDestroyRegion( destObj->xrgn );
550 destObj->xrgn = 0;
551 return NULLREGION;
553 return COMPLEXREGION;