Release 970305
[wine/multimedia.git] / objects / region.c
blob3575132b6a10299e51498128ef3fd040b58d0b39
1 /*
2 * GDI region objects
4 * Copyright 1993, 1994, 1995 Alexandre Julliard
5 */
7 #include <stdlib.h>
8 #include <stdio.h>
9 #include "region.h"
10 #include "stddebug.h"
11 #include "debug.h"
14 /***********************************************************************
15 * REGION_DeleteObject
17 BOOL32 REGION_DeleteObject( HRGN32 hrgn, RGNOBJ * obj )
19 dprintf_region(stddeb, "DeleteRegion: %04x\n", hrgn );
20 if (obj->xrgn) XDestroyRegion( obj->xrgn );
21 return GDI_FreeObject( hrgn );
25 /***********************************************************************
26 * OffsetRgn16 (GDI.101)
28 INT16 OffsetRgn16( HRGN16 hrgn, INT16 x, INT16 y )
30 return OffsetRgn32( hrgn, x, y );
34 /***********************************************************************
35 * OffsetRgn32 (GDI32.256)
37 INT32 OffsetRgn32( HRGN32 hrgn, INT32 x, INT32 y )
39 RGNOBJ * obj = (RGNOBJ *) GDI_GetObjPtr( hrgn, REGION_MAGIC );
40 if (!obj) return ERROR;
41 dprintf_region(stddeb, "OffsetRgn: %04x %d,%d\n", hrgn, x, y );
42 if (!obj->xrgn) return NULLREGION;
43 XOffsetRegion( obj->xrgn, x, y );
44 return COMPLEXREGION;
48 /***********************************************************************
49 * GetRgnBox16 (GDI.134)
51 INT16 GetRgnBox16( HRGN16 hrgn, LPRECT16 rect )
53 RGNOBJ * obj = (RGNOBJ *) GDI_GetObjPtr( hrgn, REGION_MAGIC );
54 if (!obj) return ERROR;
55 dprintf_region(stddeb, "GetRgnBox: %04x\n", hrgn );
56 if (!obj->xrgn)
58 SetRectEmpty16( rect );
59 return NULLREGION;
61 else
63 XRectangle xrect;
64 XClipBox( obj->xrgn, &xrect );
65 SetRect16( rect, xrect.x, xrect.y,
66 xrect.x + xrect.width, xrect.y + xrect.height);
67 return COMPLEXREGION;
72 /***********************************************************************
73 * GetRgnBox32 (GDI32.219)
75 INT32 GetRgnBox32( HRGN32 hrgn, LPRECT32 rect )
77 RECT16 r;
78 INT16 ret = GetRgnBox16( hrgn, &r );
79 CONV_RECT16TO32( &r, rect );
80 return ret;
84 /***********************************************************************
85 * CreateRectRgn16 (GDI.64)
87 HRGN16 CreateRectRgn16( INT16 left, INT16 top, INT16 right, INT16 bottom )
89 return (HRGN16)CreateRectRgn32( left, top, right, bottom );
93 /***********************************************************************
94 * CreateRectRgn32 (GDI32.59)
96 HRGN32 CreateRectRgn32( INT32 left, INT32 top, INT32 right, INT32 bottom )
98 HRGN32 hrgn;
99 RGNOBJ *obj;
101 if (!(hrgn = GDI_AllocObject( sizeof(RGNOBJ), REGION_MAGIC ))) return 0;
102 obj = (RGNOBJ *) GDI_HEAP_LIN_ADDR( hrgn );
103 if ((right > left) && (bottom > top))
105 XRectangle rect = { left, top, right - left, bottom - top };
106 if (!(obj->xrgn = XCreateRegion()))
108 GDI_FreeObject( hrgn );
109 return 0;
111 XUnionRectWithRegion( &rect, obj->xrgn, obj->xrgn );
113 else obj->xrgn = 0;
114 dprintf_region( stddeb, "CreateRectRgn(%d,%d-%d,%d): returning %04x\n",
115 left, top, right, bottom, hrgn );
116 return hrgn;
120 /***********************************************************************
121 * CreateRectRgnIndirect16 (GDI.65)
123 HRGN16 CreateRectRgnIndirect16( const RECT16* rect )
125 return CreateRectRgn32( rect->left, rect->top, rect->right, rect->bottom );
129 /***********************************************************************
130 * CreateRectRgnIndirect32 (GDI32.60)
132 HRGN32 CreateRectRgnIndirect32( const RECT32* rect )
134 return CreateRectRgn32( rect->left, rect->top, rect->right, rect->bottom );
138 /***********************************************************************
139 * SetRectRgn16 (GDI.172)
141 VOID SetRectRgn16( HRGN16 hrgn, INT16 left, INT16 top,
142 INT16 right, INT16 bottom )
144 SetRectRgn32( hrgn, left, top, right, bottom );
148 /***********************************************************************
149 * SetRectRgn32 (GDI32.332)
151 VOID SetRectRgn32( HRGN32 hrgn, INT32 left, INT32 top,
152 INT32 right, INT32 bottom )
154 RGNOBJ * obj;
156 dprintf_region(stddeb, "SetRectRgn: %04x %d,%d-%d,%d\n",
157 hrgn, left, top, right, bottom );
159 if (!(obj = (RGNOBJ *) GDI_GetObjPtr( hrgn, REGION_MAGIC ))) return;
160 if (obj->xrgn) XDestroyRegion( obj->xrgn );
161 if ((right > left) && (bottom > top))
163 XRectangle rect = { left, top, right - left, bottom - top };
164 if ((obj->xrgn = XCreateRegion()) != 0)
165 XUnionRectWithRegion( &rect, obj->xrgn, obj->xrgn );
167 else obj->xrgn = 0;
171 /***********************************************************************
172 * CreateRoundRectRgn16 (GDI.444)
174 HRGN16 CreateRoundRectRgn16( INT16 left, INT16 top, INT16 right, INT16 bottom,
175 INT16 ellipse_width, INT16 ellipse_height )
177 return (HRGN16)CreateRoundRectRgn32( left, top, right, bottom,
178 ellipse_width, ellipse_height );
182 /***********************************************************************
183 * CreateRoundRectRgn32 (GDI32.61)
185 HRGN32 CreateRoundRectRgn32( INT32 left, INT32 top, INT32 right, INT32 bottom,
186 INT32 ellipse_width, INT32 ellipse_height )
188 RGNOBJ * obj;
189 HRGN32 hrgn;
190 XRectangle rect;
191 int asq, bsq, d, xd, yd;
193 /* Check if we can do a normal rectangle instead */
195 if ((right <= left) || (bottom <= top) ||
196 (ellipse_width <= 0) || (ellipse_height <= 0))
197 return CreateRectRgn32( left, top, right, bottom );
199 /* Create region */
201 if (!(hrgn = GDI_AllocObject( sizeof(RGNOBJ), REGION_MAGIC ))) return 0;
202 obj = (RGNOBJ *) GDI_HEAP_LIN_ADDR( hrgn );
203 obj->xrgn = XCreateRegion();
204 dprintf_region(stddeb,"CreateRoundRectRgn(%d,%d-%d,%d %dx%d): return=%04x\n",
205 left, top, right, bottom, ellipse_width, ellipse_height, hrgn );
207 /* Check parameters */
209 if (ellipse_width > right-left) ellipse_width = right-left;
210 if (ellipse_height > bottom-top) ellipse_height = bottom-top;
212 /* Ellipse algorithm, based on an article by K. Porter */
213 /* in DDJ Graphics Programming Column, 8/89 */
215 asq = ellipse_width * ellipse_width / 4; /* a^2 */
216 bsq = ellipse_height * ellipse_height / 4; /* b^2 */
217 d = bsq - asq * ellipse_height / 2 + asq / 4; /* b^2 - a^2b + a^2/4 */
218 xd = 0;
219 yd = asq * ellipse_height; /* 2a^2b */
221 rect.x = left + ellipse_width / 2;
222 rect.width = right - left - ellipse_width;
223 rect.height = 1;
225 /* Loop to draw first half of quadrant */
227 while (xd < yd)
229 if (d > 0) /* if nearest pixel is toward the center */
231 /* move toward center */
232 rect.y = top++;
233 XUnionRectWithRegion( &rect, obj->xrgn, obj->xrgn );
234 rect.y = --bottom;
235 XUnionRectWithRegion( &rect, obj->xrgn, obj->xrgn );
236 yd -= 2*asq;
237 d -= yd;
239 rect.x--; /* next horiz point */
240 rect.width += 2;
241 xd += 2*bsq;
242 d += bsq + xd;
245 /* Loop to draw second half of quadrant */
247 d += (3 * (asq-bsq) / 2 - (xd+yd)) / 2;
248 while (yd >= 0)
250 /* next vertical point */
251 rect.y = top++;
252 XUnionRectWithRegion( &rect, obj->xrgn, obj->xrgn );
253 rect.y = --bottom;
254 XUnionRectWithRegion( &rect, obj->xrgn, obj->xrgn );
255 if (d < 0) /* if nearest pixel is outside ellipse */
257 rect.x--; /* move away from center */
258 rect.width += 2;
259 xd += 2*bsq;
260 d += xd;
262 yd -= 2*asq;
263 d += asq - yd;
266 /* Add the inside rectangle */
268 if (top <= bottom)
270 rect.y = top;
271 rect.height = bottom - top + 1;
272 XUnionRectWithRegion( &rect, obj->xrgn, obj->xrgn );
274 return hrgn;
278 /***********************************************************************
279 * CreateEllipticRgn16 (GDI.54)
281 HRGN16 CreateEllipticRgn16( INT16 left, INT16 top, INT16 right, INT16 bottom )
283 return (HRGN16)CreateRoundRectRgn32( left, top, right, bottom,
284 right-left, bottom-top );
288 /***********************************************************************
289 * CreateEllipticRgn32 (GDI32.39)
291 HRGN32 CreateEllipticRgn32( INT32 left, INT32 top, INT32 right, INT32 bottom )
293 return CreateRoundRectRgn32( left, top, right, bottom,
294 right-left, bottom-top );
298 /***********************************************************************
299 * CreateEllipticRgnIndirect16 (GDI.55)
301 HRGN16 CreateEllipticRgnIndirect16( const RECT16 *rect )
303 return CreateRoundRectRgn32( rect->left, rect->top, rect->right,
304 rect->bottom, rect->right - rect->left,
305 rect->bottom - rect->top );
309 /***********************************************************************
310 * CreateEllipticRgnIndirect32 (GDI32.40)
312 HRGN32 CreateEllipticRgnIndirect32( const RECT32 *rect )
314 return CreateRoundRectRgn32( rect->left, rect->top, rect->right,
315 rect->bottom, rect->right - rect->left,
316 rect->bottom - rect->top );
320 /***********************************************************************
321 * CreatePolygonRgn16 (GDI.63)
323 HRGN16 CreatePolygonRgn16( const POINT16 * points, INT16 count, INT16 mode )
325 return CreatePolyPolygonRgn16( points, &count, 1, mode );
329 /***********************************************************************
330 * CreatePolyPolygonRgn16 (GDI.451)
332 HRGN16 CreatePolyPolygonRgn16( const POINT16 * points, const INT16 * count,
333 INT16 nbpolygons, INT16 mode )
335 int i,nrofpts;
336 LPINT32 count32;
337 LPPOINT32 points32;
338 HRGN32 ret;
340 nrofpts=0;
341 for (i=nbpolygons;i--;)
342 nrofpts+=count[i];
343 points32 = (LPPOINT32)HeapAlloc( GetProcessHeap(), 0,
344 nrofpts*sizeof(POINT32) );
345 for (i=nrofpts;i--;)
346 CONV_POINT16TO32( &(points[i]), &(points32[i]) );
347 count32 = (LPINT32)HeapAlloc( GetProcessHeap(), 0,
348 sizeof(INT32)*nbpolygons );
349 for (i=nbpolygons;i--;)
350 count32[i]=count[i];
351 ret = CreatePolyPolygonRgn32(points32,count32,nbpolygons,mode);
352 HeapFree( GetProcessHeap(), 0, count32 );
353 HeapFree( GetProcessHeap(), 0, points32 );
354 return ret;
358 /***********************************************************************
359 * CreatePolygonRgn32 (GDI32.58)
361 HRGN32 CreatePolygonRgn32( const POINT32 *points, INT32 count, INT32 mode )
363 return CreatePolyPolygonRgn32( points, &count, 1, mode );
367 /***********************************************************************
368 * CreatePolyPolygonRgn32 (GDI32.57)
370 HRGN32 CreatePolyPolygonRgn32( const POINT32 * points, const INT32 * count,
371 INT32 nbpolygons, INT32 mode )
373 RGNOBJ * obj;
374 HRGN32 hrgn;
375 int i, j, maxPoints;
376 XPoint *xpoints, *pt;
377 Region xrgn;
379 /* Allocate points array */
381 if (!nbpolygons) return 0;
382 for (i = maxPoints = 0; i < nbpolygons; i++)
383 if (maxPoints < count[i]) maxPoints = count[i];
384 if (!maxPoints) return 0;
385 if (!(xpoints = (XPoint *)HeapAlloc( GetProcessHeap(), 0,
386 sizeof(XPoint) * maxPoints )))
387 return 0;
389 /* Allocate region */
391 if (!(hrgn = GDI_AllocObject( sizeof(RGNOBJ), REGION_MAGIC )))
393 HeapFree( GetProcessHeap(), 0, xpoints );
394 return 0;
396 obj = (RGNOBJ *) GDI_HEAP_LIN_ADDR( hrgn );
397 obj->xrgn = 0;
398 dprintf_region(stddeb, "CreatePolyPolygonRgn: %d polygons, returning %04x\n",
399 nbpolygons, hrgn );
401 /* Create X region */
403 for (i = 0; i < nbpolygons; i++, count++)
405 for (j = *count, pt = xpoints; j > 0; j--, points++, pt++)
407 pt->x = points->x;
408 pt->y = points->y;
410 xrgn = XPolygonRegion( xpoints, *count,
411 (mode == WINDING) ? WindingRule : EvenOddRule );
412 if (!xrgn)
414 if (obj->xrgn) XDestroyRegion( obj->xrgn );
415 HeapFree( GetProcessHeap(), 0, xpoints );
416 GDI_FreeObject( hrgn );
417 return 0;
419 if (i > 0)
421 Region tmprgn = XCreateRegion();
422 if (mode == WINDING) XUnionRegion( xrgn, obj->xrgn, tmprgn );
423 else XXorRegion( xrgn, obj->xrgn, tmprgn );
424 XDestroyRegion( obj->xrgn );
425 obj->xrgn = tmprgn;
427 else obj->xrgn = xrgn;
430 HeapFree( GetProcessHeap(), 0, xpoints );
431 return hrgn;
435 /***********************************************************************
436 * PtInRegion16 (GDI.161)
438 BOOL16 PtInRegion16( HRGN16 hrgn, INT16 x, INT16 y )
440 return PtInRegion32( hrgn, x, y );
444 /***********************************************************************
445 * PtInRegion32 (GDI32.278)
447 BOOL32 PtInRegion32( HRGN32 hrgn, INT32 x, INT32 y )
449 RGNOBJ * obj;
451 if (!(obj = (RGNOBJ *) GDI_GetObjPtr( hrgn, REGION_MAGIC ))) return FALSE;
452 if (!obj->xrgn) return FALSE;
453 return XPointInRegion( obj->xrgn, x, y );
457 /***********************************************************************
458 * RectInRegion16 (GDI.181)
460 BOOL16 RectInRegion16( HRGN16 hrgn, const RECT16 *rect )
462 RGNOBJ * obj;
464 if (!(obj = (RGNOBJ *) GDI_GetObjPtr( hrgn, REGION_MAGIC ))) return FALSE;
465 if (!obj->xrgn) return FALSE;
466 return (XRectInRegion( obj->xrgn, rect->left, rect->top,
467 rect->right-rect->left,
468 rect->bottom-rect->top ) != RectangleOut);
472 /***********************************************************************
473 * RectInRegion32 (GDI32.281)
475 BOOL32 RectInRegion32( HRGN32 hrgn, const RECT32 *rect )
477 RGNOBJ * obj;
479 if (!(obj = (RGNOBJ *) GDI_GetObjPtr( hrgn, REGION_MAGIC ))) return FALSE;
480 if (!obj->xrgn) return FALSE;
481 return (XRectInRegion( obj->xrgn, rect->left, rect->top,
482 rect->right-rect->left,
483 rect->bottom-rect->top ) != RectangleOut);
487 /***********************************************************************
488 * EqualRgn16 (GDI.72)
490 BOOL16 EqualRgn16( HRGN16 rgn1, HRGN16 rgn2 )
492 return EqualRgn32( rgn1, rgn2 );
496 /***********************************************************************
497 * EqualRgn32 (GDI32.90)
499 BOOL32 EqualRgn32( HRGN32 rgn1, HRGN32 rgn2 )
501 RGNOBJ *obj1, *obj2;
502 if (!(obj1 = (RGNOBJ *) GDI_GetObjPtr( rgn1, REGION_MAGIC ))) return FALSE;
503 if (!(obj2 = (RGNOBJ *) GDI_GetObjPtr( rgn2, REGION_MAGIC ))) return FALSE;
504 if (!obj1->xrgn || !obj2->xrgn) return (!obj1->xrgn && !obj2->xrgn);
505 return XEqualRegion( obj1->xrgn, obj2->xrgn );
509 /***********************************************************************
510 * REGION_CopyRegion
512 * Copy region src into dest.
514 static INT32 REGION_CopyRegion( RGNOBJ *src, RGNOBJ *dest )
516 Region tmprgn;
517 if (src->xrgn)
519 if (src->xrgn == dest->xrgn) return COMPLEXREGION;
520 tmprgn = XCreateRegion();
521 if (!dest->xrgn) dest->xrgn = XCreateRegion();
522 XUnionRegion( tmprgn, src->xrgn, dest->xrgn );
523 XDestroyRegion( tmprgn );
524 return COMPLEXREGION;
526 else
528 if (dest->xrgn) XDestroyRegion( dest->xrgn );
529 dest->xrgn = 0;
530 return NULLREGION;
534 /***********************************************************************
535 * REGION_UnionRectWithRgn
537 * Add rectangle to region
539 BOOL32 REGION_UnionRectWithRgn( HRGN32 hRgn, const RECT32 *rc )
541 RGNOBJ *rgnObj = (RGNOBJ*) GDI_GetObjPtr( hRgn, REGION_MAGIC );
542 XRectangle rect = { rc->left, rc->top, rc->right - rc->left, rc->bottom - rc->top };
543 BOOL32 ret = FALSE;
545 if( rgnObj )
547 if( !rgnObj->xrgn )
549 if (!(rgnObj->xrgn = XCreateRegion()))
551 GDI_FreeObject( hRgn );
552 return 0;
554 ret = SIMPLEREGION;
556 else
557 ret = COMPLEXREGION;
558 XUnionRectWithRegion( &rect, rgnObj->xrgn, rgnObj->xrgn );
560 return ret;
564 /***********************************************************************
565 * REGION_CreateFrameRgn
567 * Create a region that is a frame around another region
569 BOOL32 REGION_FrameRgn( HRGN32 hDest, HRGN32 hSrc, INT32 x, INT32 y )
571 RGNOBJ *destObj,*srcObj;
572 Region result;
574 destObj = (RGNOBJ*) GDI_GetObjPtr( hDest, REGION_MAGIC );
575 srcObj = (RGNOBJ*) GDI_GetObjPtr( hSrc, REGION_MAGIC );
576 if (!srcObj->xrgn) return FALSE;
577 REGION_CopyRegion( srcObj, destObj );
578 XShrinkRegion( destObj->xrgn, -x, -y );
579 result = XCreateRegion();
580 XSubtractRegion( destObj->xrgn, srcObj->xrgn, result );
581 XDestroyRegion( destObj->xrgn );
582 destObj->xrgn = result;
583 return TRUE;
587 /***********************************************************************
588 * CombineRgn16 (GDI.451)
590 INT16 CombineRgn16( HRGN16 hDest, HRGN16 hSrc1, HRGN16 hSrc2, INT16 mode )
592 return (INT16)CombineRgn32( hDest, hSrc1, hSrc2, mode );
596 /***********************************************************************
597 * CombineRgn32 (GDI32.19)
599 * Note: The behavior is correct even if src and dest regions are the same.
601 INT32 CombineRgn32( HRGN32 hDest, HRGN32 hSrc1, HRGN32 hSrc2, INT32 mode )
603 RGNOBJ *destObj, *src1Obj, *src2Obj;
604 Region destrgn;
606 dprintf_region(stddeb, "CombineRgn: %04x,%04x -> %04x mode=%x\n",
607 hSrc1, hSrc2, hDest, mode );
609 if (!(destObj = (RGNOBJ *) GDI_GetObjPtr( hDest, REGION_MAGIC )))
610 return ERROR;
611 if (!(src1Obj = (RGNOBJ *) GDI_GetObjPtr( hSrc1, REGION_MAGIC )))
612 return ERROR;
613 if (mode == RGN_COPY) return REGION_CopyRegion( src1Obj, destObj );
615 if (!(src2Obj = (RGNOBJ *) GDI_GetObjPtr( hSrc2, REGION_MAGIC )))
616 return ERROR;
618 /* Some optimizations for null regions */
620 if (!src1Obj->xrgn || !src2Obj->xrgn)
622 switch(mode)
624 case RGN_DIFF:
625 if (src1Obj->xrgn)
626 return REGION_CopyRegion( src1Obj, destObj );
627 /* else fall through */
628 case RGN_AND:
629 if (destObj->xrgn) XDestroyRegion( destObj->xrgn );
630 destObj->xrgn = 0;
631 return NULLREGION;
632 case RGN_OR:
633 case RGN_XOR:
634 if (src1Obj->xrgn)
635 return REGION_CopyRegion( src1Obj, destObj );
636 else
637 return REGION_CopyRegion( src2Obj, destObj );
638 default:
639 return ERROR;
643 /* Perform the operation with the two X regions */
645 if (!(destrgn = XCreateRegion())) return ERROR;
646 switch(mode)
648 case RGN_AND:
649 XIntersectRegion( src1Obj->xrgn, src2Obj->xrgn, destrgn );
650 break;
651 case RGN_OR:
652 XUnionRegion( src1Obj->xrgn, src2Obj->xrgn, destrgn );
653 break;
654 case RGN_XOR:
655 XXorRegion( src1Obj->xrgn, src2Obj->xrgn, destrgn );
656 break;
657 case RGN_DIFF:
658 XSubtractRegion( src1Obj->xrgn, src2Obj->xrgn, destrgn );
659 break;
660 default:
661 XDestroyRegion( destrgn );
662 return ERROR;
664 if (destObj->xrgn) XDestroyRegion( destObj->xrgn );
665 destObj->xrgn = destrgn;
666 if (XEmptyRegion(destObj->xrgn))
668 XDestroyRegion( destObj->xrgn );
669 destObj->xrgn = 0;
670 return NULLREGION;
672 return COMPLEXREGION;