Release 970804
[wine.git] / objects / region.c
blob9148e6d4613fc554d3d76f04552bc5f0a24b8c03
1 /*
2 * GDI region objects
4 * Copyright 1993, 1994, 1995 Alexandre Julliard
6 * RGNOBJ is documented in the Dr. Dobbs Journal March 1993.
7 */
9 #include <stdlib.h>
10 #include <stdio.h>
11 #include "region.h"
12 #include "stddebug.h"
13 #include "debug.h"
16 /***********************************************************************
17 * REGION_DeleteObject
19 BOOL32 REGION_DeleteObject( HRGN32 hrgn, RGNOBJ * obj )
21 dprintf_region(stddeb, "DeleteRegion: %04x\n", hrgn );
22 if (obj->xrgn) XDestroyRegion( obj->xrgn );
23 return GDI_FreeObject( hrgn );
27 /***********************************************************************
28 * OffsetRgn16 (GDI.101)
30 INT16 OffsetRgn16( HRGN16 hrgn, INT16 x, INT16 y )
32 return OffsetRgn32( hrgn, x, y );
36 /***********************************************************************
37 * OffsetRgn32 (GDI32.256)
39 INT32 OffsetRgn32( HRGN32 hrgn, INT32 x, INT32 y )
41 RGNOBJ * obj = (RGNOBJ *) GDI_GetObjPtr( hrgn, REGION_MAGIC );
42 if (!obj) return ERROR;
43 dprintf_region(stddeb, "OffsetRgn: %04x %d,%d\n", hrgn, x, y );
44 if (!obj->xrgn) return NULLREGION;
45 XOffsetRegion( obj->xrgn, x, y );
46 return COMPLEXREGION;
50 /***********************************************************************
51 * GetRgnBox16 (GDI.134)
53 INT16 GetRgnBox16( HRGN16 hrgn, LPRECT16 rect )
55 RGNOBJ * obj = (RGNOBJ *) GDI_GetObjPtr( hrgn, REGION_MAGIC );
56 if (!obj) return ERROR;
57 dprintf_region(stddeb, "GetRgnBox: %04x\n", hrgn );
58 if (!obj->xrgn)
60 SetRectEmpty16( rect );
61 return NULLREGION;
63 else
65 XRectangle xrect;
66 XClipBox( obj->xrgn, &xrect );
67 SetRect16( rect, xrect.x, xrect.y,
68 xrect.x + xrect.width, xrect.y + xrect.height);
69 return COMPLEXREGION;
74 /***********************************************************************
75 * GetRgnBox32 (GDI32.219)
77 INT32 GetRgnBox32( HRGN32 hrgn, LPRECT32 rect )
79 RECT16 r;
80 INT16 ret = GetRgnBox16( hrgn, &r );
81 CONV_RECT16TO32( &r, rect );
82 return ret;
86 /***********************************************************************
87 * CreateRectRgn16 (GDI.64)
89 HRGN16 CreateRectRgn16( INT16 left, INT16 top, INT16 right, INT16 bottom )
91 return (HRGN16)CreateRectRgn32( left, top, right, bottom );
95 /***********************************************************************
96 * CreateRectRgn32 (GDI32.59)
98 HRGN32 CreateRectRgn32( INT32 left, INT32 top, INT32 right, INT32 bottom )
100 HRGN32 hrgn;
101 RGNOBJ *obj;
103 if (!(hrgn = GDI_AllocObject( sizeof(RGNOBJ), REGION_MAGIC ))) return 0;
104 obj = (RGNOBJ *) GDI_HEAP_LIN_ADDR( hrgn );
105 if ((right > left) && (bottom > top))
107 XRectangle rect = { left, top, right - left, bottom - top };
108 if (!(obj->xrgn = XCreateRegion()))
110 GDI_FreeObject( hrgn );
111 return 0;
113 XUnionRectWithRegion( &rect, obj->xrgn, obj->xrgn );
115 else obj->xrgn = 0;
116 dprintf_region( stddeb, "CreateRectRgn(%d,%d-%d,%d): returning %04x\n",
117 left, top, right, bottom, hrgn );
118 return hrgn;
122 /***********************************************************************
123 * CreateRectRgnIndirect16 (GDI.65)
125 HRGN16 CreateRectRgnIndirect16( const RECT16* rect )
127 return CreateRectRgn32( rect->left, rect->top, rect->right, rect->bottom );
131 /***********************************************************************
132 * CreateRectRgnIndirect32 (GDI32.60)
134 HRGN32 CreateRectRgnIndirect32( const RECT32* rect )
136 return CreateRectRgn32( rect->left, rect->top, rect->right, rect->bottom );
140 /***********************************************************************
141 * SetRectRgn16 (GDI.172)
143 VOID SetRectRgn16( HRGN16 hrgn, INT16 left, INT16 top,
144 INT16 right, INT16 bottom )
146 SetRectRgn32( hrgn, left, top, right, bottom );
150 /***********************************************************************
151 * SetRectRgn32 (GDI32.332)
153 VOID SetRectRgn32( HRGN32 hrgn, INT32 left, INT32 top,
154 INT32 right, INT32 bottom )
156 RGNOBJ * obj;
158 dprintf_region(stddeb, "SetRectRgn: %04x %d,%d-%d,%d\n",
159 hrgn, left, top, right, bottom );
161 if (!(obj = (RGNOBJ *) GDI_GetObjPtr( hrgn, REGION_MAGIC ))) return;
162 if (obj->xrgn) XDestroyRegion( obj->xrgn );
163 if ((right > left) && (bottom > top))
165 XRectangle rect = { left, top, right - left, bottom - top };
166 if ((obj->xrgn = XCreateRegion()) != 0)
167 XUnionRectWithRegion( &rect, obj->xrgn, obj->xrgn );
169 else obj->xrgn = 0;
173 /***********************************************************************
174 * CreateRoundRectRgn16 (GDI.444)
176 HRGN16 CreateRoundRectRgn16( INT16 left, INT16 top, INT16 right, INT16 bottom,
177 INT16 ellipse_width, INT16 ellipse_height )
179 return (HRGN16)CreateRoundRectRgn32( left, top, right, bottom,
180 ellipse_width, ellipse_height );
184 /***********************************************************************
185 * CreateRoundRectRgn32 (GDI32.61)
187 HRGN32 CreateRoundRectRgn32( INT32 left, INT32 top, INT32 right, INT32 bottom,
188 INT32 ellipse_width, INT32 ellipse_height )
190 RGNOBJ * obj;
191 HRGN32 hrgn;
192 XRectangle rect;
193 int asq, bsq, d, xd, yd;
195 /* Check if we can do a normal rectangle instead */
197 if ((right <= left) || (bottom <= top) ||
198 (ellipse_width <= 0) || (ellipse_height <= 0))
199 return CreateRectRgn32( left, top, right, bottom );
201 /* Create region */
203 if (!(hrgn = GDI_AllocObject( sizeof(RGNOBJ), REGION_MAGIC ))) return 0;
204 obj = (RGNOBJ *) GDI_HEAP_LIN_ADDR( hrgn );
205 obj->xrgn = XCreateRegion();
206 dprintf_region(stddeb,"CreateRoundRectRgn(%d,%d-%d,%d %dx%d): return=%04x\n",
207 left, top, right, bottom, ellipse_width, ellipse_height, hrgn );
209 /* Check parameters */
211 if (ellipse_width > right-left) ellipse_width = right-left;
212 if (ellipse_height > bottom-top) ellipse_height = bottom-top;
214 /* Ellipse algorithm, based on an article by K. Porter */
215 /* in DDJ Graphics Programming Column, 8/89 */
217 asq = ellipse_width * ellipse_width / 4; /* a^2 */
218 bsq = ellipse_height * ellipse_height / 4; /* b^2 */
219 d = bsq - asq * ellipse_height / 2 + asq / 4; /* b^2 - a^2b + a^2/4 */
220 xd = 0;
221 yd = asq * ellipse_height; /* 2a^2b */
223 rect.x = left + ellipse_width / 2;
224 rect.width = right - left - ellipse_width;
225 rect.height = 1;
227 /* Loop to draw first half of quadrant */
229 while (xd < yd)
231 if (d > 0) /* if nearest pixel is toward the center */
233 /* move toward center */
234 rect.y = top++;
235 XUnionRectWithRegion( &rect, obj->xrgn, obj->xrgn );
236 rect.y = --bottom;
237 XUnionRectWithRegion( &rect, obj->xrgn, obj->xrgn );
238 yd -= 2*asq;
239 d -= yd;
241 rect.x--; /* next horiz point */
242 rect.width += 2;
243 xd += 2*bsq;
244 d += bsq + xd;
247 /* Loop to draw second half of quadrant */
249 d += (3 * (asq-bsq) / 2 - (xd+yd)) / 2;
250 while (yd >= 0)
252 /* next vertical point */
253 rect.y = top++;
254 XUnionRectWithRegion( &rect, obj->xrgn, obj->xrgn );
255 rect.y = --bottom;
256 XUnionRectWithRegion( &rect, obj->xrgn, obj->xrgn );
257 if (d < 0) /* if nearest pixel is outside ellipse */
259 rect.x--; /* move away from center */
260 rect.width += 2;
261 xd += 2*bsq;
262 d += xd;
264 yd -= 2*asq;
265 d += asq - yd;
268 /* Add the inside rectangle */
270 if (top <= bottom)
272 rect.y = top;
273 rect.height = bottom - top + 1;
274 XUnionRectWithRegion( &rect, obj->xrgn, obj->xrgn );
276 return hrgn;
280 /***********************************************************************
281 * CreateEllipticRgn16 (GDI.54)
283 HRGN16 CreateEllipticRgn16( INT16 left, INT16 top, INT16 right, INT16 bottom )
285 return (HRGN16)CreateRoundRectRgn32( left, top, right, bottom,
286 right-left, bottom-top );
290 /***********************************************************************
291 * CreateEllipticRgn32 (GDI32.39)
293 HRGN32 CreateEllipticRgn32( INT32 left, INT32 top, INT32 right, INT32 bottom )
295 return CreateRoundRectRgn32( left, top, right, bottom,
296 right-left, bottom-top );
300 /***********************************************************************
301 * CreateEllipticRgnIndirect16 (GDI.55)
303 HRGN16 CreateEllipticRgnIndirect16( const RECT16 *rect )
305 return CreateRoundRectRgn32( rect->left, rect->top, rect->right,
306 rect->bottom, rect->right - rect->left,
307 rect->bottom - rect->top );
311 /***********************************************************************
312 * CreateEllipticRgnIndirect32 (GDI32.40)
314 HRGN32 CreateEllipticRgnIndirect32( const RECT32 *rect )
316 return CreateRoundRectRgn32( rect->left, rect->top, rect->right,
317 rect->bottom, rect->right - rect->left,
318 rect->bottom - rect->top );
322 /***********************************************************************
323 * CreatePolygonRgn16 (GDI.63)
325 HRGN16 CreatePolygonRgn16( const POINT16 * points, INT16 count, INT16 mode )
327 return CreatePolyPolygonRgn16( points, &count, 1, mode );
331 /***********************************************************************
332 * CreatePolyPolygonRgn16 (GDI.451)
334 HRGN16 CreatePolyPolygonRgn16( const POINT16 * points, const INT16 * count,
335 INT16 nbpolygons, INT16 mode )
337 int i,nrofpts;
338 LPINT32 count32;
339 LPPOINT32 points32;
340 HRGN32 ret;
342 nrofpts=0;
343 for (i=nbpolygons;i--;)
344 nrofpts+=count[i];
345 points32 = (LPPOINT32)HeapAlloc( GetProcessHeap(), 0,
346 nrofpts*sizeof(POINT32) );
347 for (i=nrofpts;i--;)
348 CONV_POINT16TO32( &(points[i]), &(points32[i]) );
349 count32 = (LPINT32)HeapAlloc( GetProcessHeap(), 0,
350 sizeof(INT32)*nbpolygons );
351 for (i=nbpolygons;i--;)
352 count32[i]=count[i];
353 ret = CreatePolyPolygonRgn32(points32,count32,nbpolygons,mode);
354 HeapFree( GetProcessHeap(), 0, count32 );
355 HeapFree( GetProcessHeap(), 0, points32 );
356 return ret;
360 /***********************************************************************
361 * CreatePolygonRgn32 (GDI32.58)
363 HRGN32 CreatePolygonRgn32( const POINT32 *points, INT32 count, INT32 mode )
365 return CreatePolyPolygonRgn32( points, &count, 1, mode );
369 /***********************************************************************
370 * CreatePolyPolygonRgn32 (GDI32.57)
372 HRGN32 CreatePolyPolygonRgn32( const POINT32 * points, const INT32 * count,
373 INT32 nbpolygons, INT32 mode )
375 RGNOBJ * obj;
376 HRGN32 hrgn;
377 int i, j, maxPoints;
378 XPoint *xpoints, *pt;
379 Region xrgn;
381 /* Allocate points array */
383 if (!nbpolygons) return 0;
384 for (i = maxPoints = 0; i < nbpolygons; i++)
385 if (maxPoints < count[i]) maxPoints = count[i];
386 if (!maxPoints) return 0;
387 if (!(xpoints = (XPoint *)HeapAlloc( GetProcessHeap(), 0,
388 sizeof(XPoint) * maxPoints )))
389 return 0;
391 /* Allocate region */
393 if (!(hrgn = GDI_AllocObject( sizeof(RGNOBJ), REGION_MAGIC )))
395 HeapFree( GetProcessHeap(), 0, xpoints );
396 return 0;
398 obj = (RGNOBJ *) GDI_HEAP_LIN_ADDR( hrgn );
399 obj->xrgn = 0;
400 dprintf_region(stddeb, "CreatePolyPolygonRgn: %d polygons, returning %04x\n",
401 nbpolygons, hrgn );
403 /* Create X region */
405 for (i = 0; i < nbpolygons; i++, count++)
407 for (j = *count, pt = xpoints; j > 0; j--, points++, pt++)
409 pt->x = points->x;
410 pt->y = points->y;
412 xrgn = XPolygonRegion( xpoints, *count,
413 (mode == WINDING) ? WindingRule : EvenOddRule );
414 if (!xrgn)
416 if (obj->xrgn) XDestroyRegion( obj->xrgn );
417 HeapFree( GetProcessHeap(), 0, xpoints );
418 GDI_FreeObject( hrgn );
419 return 0;
421 if (i > 0)
423 Region tmprgn = XCreateRegion();
424 if (mode == WINDING) XUnionRegion( xrgn, obj->xrgn, tmprgn );
425 else XXorRegion( xrgn, obj->xrgn, tmprgn );
426 XDestroyRegion( obj->xrgn );
427 obj->xrgn = tmprgn;
429 else obj->xrgn = xrgn;
432 HeapFree( GetProcessHeap(), 0, xpoints );
433 return hrgn;
437 /***********************************************************************
438 * PtInRegion16 (GDI.161)
440 BOOL16 PtInRegion16( HRGN16 hrgn, INT16 x, INT16 y )
442 return PtInRegion32( hrgn, x, y );
446 /***********************************************************************
447 * PtInRegion32 (GDI32.278)
449 BOOL32 PtInRegion32( HRGN32 hrgn, INT32 x, INT32 y )
451 RGNOBJ * obj;
453 if (!(obj = (RGNOBJ *) GDI_GetObjPtr( hrgn, REGION_MAGIC ))) return FALSE;
454 if (!obj->xrgn) return FALSE;
455 return XPointInRegion( obj->xrgn, x, y );
459 /***********************************************************************
460 * RectInRegion16 (GDI.181)
462 BOOL16 RectInRegion16( HRGN16 hrgn, const RECT16 *rect )
464 RGNOBJ * obj;
466 if (!(obj = (RGNOBJ *) GDI_GetObjPtr( hrgn, REGION_MAGIC ))) return FALSE;
467 if (!obj->xrgn) return FALSE;
468 return (XRectInRegion( obj->xrgn, rect->left, rect->top,
469 rect->right-rect->left,
470 rect->bottom-rect->top ) != RectangleOut);
474 /***********************************************************************
475 * RectInRegion32 (GDI32.281)
477 BOOL32 RectInRegion32( HRGN32 hrgn, const RECT32 *rect )
479 RGNOBJ * obj;
481 if (!(obj = (RGNOBJ *) GDI_GetObjPtr( hrgn, REGION_MAGIC ))) return FALSE;
482 if (!obj->xrgn) return FALSE;
483 return (XRectInRegion( obj->xrgn, rect->left, rect->top,
484 rect->right-rect->left,
485 rect->bottom-rect->top ) != RectangleOut);
489 /***********************************************************************
490 * EqualRgn16 (GDI.72)
492 BOOL16 EqualRgn16( HRGN16 rgn1, HRGN16 rgn2 )
494 return EqualRgn32( rgn1, rgn2 );
498 /***********************************************************************
499 * EqualRgn32 (GDI32.90)
501 BOOL32 EqualRgn32( HRGN32 rgn1, HRGN32 rgn2 )
503 RGNOBJ *obj1, *obj2;
504 if (!(obj1 = (RGNOBJ *) GDI_GetObjPtr( rgn1, REGION_MAGIC ))) return FALSE;
505 if (!(obj2 = (RGNOBJ *) GDI_GetObjPtr( rgn2, REGION_MAGIC ))) return FALSE;
506 if (!obj1->xrgn || !obj2->xrgn) return (!obj1->xrgn && !obj2->xrgn);
507 return XEqualRegion( obj1->xrgn, obj2->xrgn );
511 /***********************************************************************
512 * REGION_CopyRegion
514 * Copy region src into dest.
516 static INT32 REGION_CopyRegion( RGNOBJ *src, RGNOBJ *dest )
518 Region tmprgn;
519 if (src->xrgn)
521 if (src->xrgn == dest->xrgn) return COMPLEXREGION;
522 tmprgn = XCreateRegion();
523 if (!dest->xrgn) dest->xrgn = XCreateRegion();
524 XUnionRegion( tmprgn, src->xrgn, dest->xrgn );
525 XDestroyRegion( tmprgn );
526 return COMPLEXREGION;
528 else
530 if (dest->xrgn) XDestroyRegion( dest->xrgn );
531 dest->xrgn = 0;
532 return NULLREGION;
536 /***********************************************************************
537 * REGION_UnionRectWithRgn
539 * Add rectangle to region
541 BOOL32 REGION_UnionRectWithRgn( HRGN32 hRgn, const RECT32 *rc )
543 RGNOBJ *rgnObj = (RGNOBJ*) GDI_GetObjPtr( hRgn, REGION_MAGIC );
544 XRectangle rect = { rc->left, rc->top, rc->right - rc->left, rc->bottom - rc->top };
545 BOOL32 ret = FALSE;
547 if( rgnObj )
549 if( !rgnObj->xrgn )
551 if (!(rgnObj->xrgn = XCreateRegion()))
553 GDI_FreeObject( hRgn );
554 return 0;
556 ret = SIMPLEREGION;
558 else
559 ret = COMPLEXREGION;
560 XUnionRectWithRegion( &rect, rgnObj->xrgn, rgnObj->xrgn );
562 return ret;
566 /***********************************************************************
567 * REGION_CreateFrameRgn
569 * Create a region that is a frame around another region
571 BOOL32 REGION_FrameRgn( HRGN32 hDest, HRGN32 hSrc, INT32 x, INT32 y )
573 RGNOBJ *destObj,*srcObj;
574 Region result;
576 destObj = (RGNOBJ*) GDI_GetObjPtr( hDest, REGION_MAGIC );
577 srcObj = (RGNOBJ*) GDI_GetObjPtr( hSrc, REGION_MAGIC );
578 if (!srcObj->xrgn) return FALSE;
579 REGION_CopyRegion( srcObj, destObj );
580 XShrinkRegion( destObj->xrgn, -x, -y );
581 result = XCreateRegion();
582 XSubtractRegion( destObj->xrgn, srcObj->xrgn, result );
583 XDestroyRegion( destObj->xrgn );
584 destObj->xrgn = result;
585 return TRUE;
589 /***********************************************************************
590 * CombineRgn16 (GDI.451)
592 INT16 CombineRgn16( HRGN16 hDest, HRGN16 hSrc1, HRGN16 hSrc2, INT16 mode )
594 return (INT16)CombineRgn32( hDest, hSrc1, hSrc2, mode );
598 /***********************************************************************
599 * CombineRgn32 (GDI32.19)
601 * Note: The behavior is correct even if src and dest regions are the same.
603 INT32 CombineRgn32( HRGN32 hDest, HRGN32 hSrc1, HRGN32 hSrc2, INT32 mode )
605 RGNOBJ *destObj, *src1Obj, *src2Obj;
606 Region destrgn;
608 dprintf_region(stddeb, "CombineRgn: %04x,%04x -> %04x mode=%x\n",
609 hSrc1, hSrc2, hDest, mode );
611 if (!(destObj = (RGNOBJ *) GDI_GetObjPtr( hDest, REGION_MAGIC )))
612 return ERROR;
613 if (!(src1Obj = (RGNOBJ *) GDI_GetObjPtr( hSrc1, REGION_MAGIC )))
614 return ERROR;
615 if (mode == RGN_COPY) return REGION_CopyRegion( src1Obj, destObj );
617 if (!(src2Obj = (RGNOBJ *) GDI_GetObjPtr( hSrc2, REGION_MAGIC )))
618 return ERROR;
620 /* Some optimizations for null regions */
622 if (!src1Obj->xrgn || !src2Obj->xrgn)
624 switch(mode)
626 case RGN_DIFF:
627 if (src1Obj->xrgn)
628 return REGION_CopyRegion( src1Obj, destObj );
629 /* else fall through */
630 case RGN_AND:
631 if (destObj->xrgn) XDestroyRegion( destObj->xrgn );
632 destObj->xrgn = 0;
633 return NULLREGION;
634 case RGN_OR:
635 case RGN_XOR:
636 if (src1Obj->xrgn)
637 return REGION_CopyRegion( src1Obj, destObj );
638 else
639 return REGION_CopyRegion( src2Obj, destObj );
640 default:
641 return ERROR;
645 /* Perform the operation with the two X regions */
647 if (!(destrgn = XCreateRegion())) return ERROR;
648 switch(mode)
650 case RGN_AND:
651 XIntersectRegion( src1Obj->xrgn, src2Obj->xrgn, destrgn );
652 break;
653 case RGN_OR:
654 XUnionRegion( src1Obj->xrgn, src2Obj->xrgn, destrgn );
655 break;
656 case RGN_XOR:
657 XXorRegion( src1Obj->xrgn, src2Obj->xrgn, destrgn );
658 break;
659 case RGN_DIFF:
660 XSubtractRegion( src1Obj->xrgn, src2Obj->xrgn, destrgn );
661 break;
662 default:
663 XDestroyRegion( destrgn );
664 return ERROR;
666 if (destObj->xrgn) XDestroyRegion( destObj->xrgn );
667 destObj->xrgn = destrgn;
668 if (XEmptyRegion(destObj->xrgn))
670 XDestroyRegion( destObj->xrgn );
671 destObj->xrgn = 0;
672 return NULLREGION;
674 return COMPLEXREGION;