Release 970112
[wine.git] / objects / region.c
blob18e808db6c8885e7ab6f342eccbb01919f1fce92
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 BOOL32 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 * OffsetRgn16 (GDI.101)
29 INT16 OffsetRgn16( HRGN16 hrgn, INT16 x, INT16 y )
31 return OffsetRgn32( hrgn, x, y );
35 /***********************************************************************
36 * OffsetRgn32 (GDI32.256)
38 INT32 OffsetRgn32( HRGN32 hrgn, INT32 x, INT32 y )
40 RGNOBJ * obj = (RGNOBJ *) GDI_GetObjPtr( hrgn, REGION_MAGIC );
41 if (!obj) return ERROR;
42 dprintf_region(stddeb, "OffsetRgn: %04x %d,%d\n", hrgn, x, y );
43 if (!obj->xrgn) return NULLREGION;
44 XOffsetRegion( obj->xrgn, x, y );
45 return COMPLEXREGION;
49 /***********************************************************************
50 * GetRgnBox16 (GDI.134)
52 INT16 GetRgnBox16( HRGN16 hrgn, LPRECT16 rect )
54 RGNOBJ * obj = (RGNOBJ *) GDI_GetObjPtr( hrgn, REGION_MAGIC );
55 if (!obj) return ERROR;
56 dprintf_region(stddeb, "GetRgnBox: %04x\n", hrgn );
57 if (!obj->xrgn)
59 SetRectEmpty16( rect );
60 return NULLREGION;
62 else
64 XRectangle xrect;
65 XClipBox( obj->xrgn, &xrect );
66 SetRect16( rect, xrect.x, xrect.y,
67 xrect.x + xrect.width, xrect.y + xrect.height);
68 return COMPLEXREGION;
73 /***********************************************************************
74 * GetRgnBox32 (GDI32.219)
76 INT32 GetRgnBox32( HRGN32 hrgn, LPRECT32 rect )
78 RECT16 r;
79 INT16 ret = GetRgnBox16( hrgn, &r );
80 CONV_RECT16TO32( &r, rect );
81 return ret;
85 /***********************************************************************
86 * CreateRectRgn16 (GDI.64)
88 HRGN16 CreateRectRgn16( INT16 left, INT16 top, INT16 right, INT16 bottom )
90 return (HRGN16)CreateRectRgn32( left, top, right, bottom );
94 /***********************************************************************
95 * CreateRectRgn32 (GDI32.59)
97 HRGN32 CreateRectRgn32( INT32 left, INT32 top, INT32 right, INT32 bottom )
99 HRGN32 hrgn;
100 RGNOBJ *obj;
102 if (!(hrgn = GDI_AllocObject( sizeof(RGNOBJ), REGION_MAGIC ))) return 0;
103 obj = (RGNOBJ *) GDI_HEAP_LIN_ADDR( hrgn );
104 if ((right > left) && (bottom > top))
106 XRectangle rect = { left, top, right - left, bottom - top };
107 if (!(obj->xrgn = XCreateRegion()))
109 GDI_FreeObject( hrgn );
110 return 0;
112 XUnionRectWithRegion( &rect, obj->xrgn, obj->xrgn );
114 else obj->xrgn = 0;
115 dprintf_region( stddeb, "CreateRectRgn(%d,%d-%d,%d): returning %04x\n",
116 left, top, right, bottom, hrgn );
117 return hrgn;
121 /***********************************************************************
122 * CreateRectRgnIndirect16 (GDI.65)
124 HRGN16 CreateRectRgnIndirect16( const RECT16* rect )
126 return CreateRectRgn32( rect->left, rect->top, rect->right, rect->bottom );
130 /***********************************************************************
131 * CreateRectRgnIndirect32 (GDI32.60)
133 HRGN32 CreateRectRgnIndirect32( const RECT32* rect )
135 return CreateRectRgn32( rect->left, rect->top, rect->right, rect->bottom );
139 /***********************************************************************
140 * SetRectRgn (GDI.172) (GDI32.332)
142 VOID SetRectRgn( HRGN32 hrgn, INT32 left, INT32 top, INT32 right, INT32 bottom)
144 RGNOBJ * obj;
146 dprintf_region(stddeb, "SetRectRgn: %04x %d,%d-%d,%d\n",
147 hrgn, left, top, right, bottom );
149 if (!(obj = (RGNOBJ *) GDI_GetObjPtr( hrgn, REGION_MAGIC ))) return;
150 if (obj->xrgn) XDestroyRegion( obj->xrgn );
151 if ((right > left) && (bottom > top))
153 XRectangle rect = { left, top, right - left, bottom - top };
154 if ((obj->xrgn = XCreateRegion()) != 0)
155 XUnionRectWithRegion( &rect, obj->xrgn, obj->xrgn );
157 else obj->xrgn = 0;
161 /***********************************************************************
162 * CreateRoundRectRgn16 (GDI.444)
164 HRGN16 CreateRoundRectRgn16( INT16 left, INT16 top, INT16 right, INT16 bottom,
165 INT16 ellipse_width, INT16 ellipse_height )
167 return (HRGN16)CreateRoundRectRgn32( left, top, right, bottom,
168 ellipse_width, ellipse_height );
172 /***********************************************************************
173 * CreateRoundRectRgn32 (GDI32.61)
175 HRGN32 CreateRoundRectRgn32( INT32 left, INT32 top, INT32 right, INT32 bottom,
176 INT32 ellipse_width, INT32 ellipse_height )
178 RGNOBJ * obj;
179 HRGN32 hrgn;
180 XRectangle rect;
181 int asq, bsq, d, xd, yd;
183 /* Check if we can do a normal rectangle instead */
185 if ((right <= left) || (bottom <= top) ||
186 (ellipse_width <= 0) || (ellipse_height <= 0))
187 return CreateRectRgn32( left, top, right, bottom );
189 /* Create region */
191 if (!(hrgn = GDI_AllocObject( sizeof(RGNOBJ), REGION_MAGIC ))) return 0;
192 obj = (RGNOBJ *) GDI_HEAP_LIN_ADDR( hrgn );
193 obj->xrgn = XCreateRegion();
194 dprintf_region(stddeb,"CreateRoundRectRgn(%d,%d-%d,%d %dx%d): return=%04x\n",
195 left, top, right, bottom, ellipse_width, ellipse_height, hrgn );
197 /* Check parameters */
199 if (ellipse_width > right-left) ellipse_width = right-left;
200 if (ellipse_height > bottom-top) ellipse_height = bottom-top;
202 /* Ellipse algorithm, based on an article by K. Porter */
203 /* in DDJ Graphics Programming Column, 8/89 */
205 asq = ellipse_width * ellipse_width / 4; /* a^2 */
206 bsq = ellipse_height * ellipse_height / 4; /* b^2 */
207 d = bsq - asq * ellipse_height / 2 + asq / 4; /* b^2 - a^2b + a^2/4 */
208 xd = 0;
209 yd = asq * ellipse_height; /* 2a^2b */
211 rect.x = left + ellipse_width / 2;
212 rect.width = right - left - ellipse_width;
213 rect.height = 1;
215 /* Loop to draw first half of quadrant */
217 while (xd < yd)
219 if (d > 0) /* if nearest pixel is toward the center */
221 /* move toward center */
222 rect.y = top++;
223 XUnionRectWithRegion( &rect, obj->xrgn, obj->xrgn );
224 rect.y = --bottom;
225 XUnionRectWithRegion( &rect, obj->xrgn, obj->xrgn );
226 yd -= 2*asq;
227 d -= yd;
229 rect.x--; /* next horiz point */
230 rect.width += 2;
231 xd += 2*bsq;
232 d += bsq + xd;
235 /* Loop to draw second half of quadrant */
237 d += (3 * (asq-bsq) / 2 - (xd+yd)) / 2;
238 while (yd >= 0)
240 /* next vertical point */
241 rect.y = top++;
242 XUnionRectWithRegion( &rect, obj->xrgn, obj->xrgn );
243 rect.y = --bottom;
244 XUnionRectWithRegion( &rect, obj->xrgn, obj->xrgn );
245 if (d < 0) /* if nearest pixel is outside ellipse */
247 rect.x--; /* move away from center */
248 rect.width += 2;
249 xd += 2*bsq;
250 d += xd;
252 yd -= 2*asq;
253 d += asq - yd;
256 /* Add the inside rectangle */
258 if (top <= bottom)
260 rect.y = top;
261 rect.height = bottom - top + 1;
262 XUnionRectWithRegion( &rect, obj->xrgn, obj->xrgn );
264 return hrgn;
268 /***********************************************************************
269 * CreateEllipticRgn16 (GDI.54)
271 HRGN16 CreateEllipticRgn16( INT16 left, INT16 top, INT16 right, INT16 bottom )
273 return (HRGN16)CreateRoundRectRgn32( left, top, right, bottom,
274 right-left, bottom-top );
278 /***********************************************************************
279 * CreateEllipticRgn32 (GDI32.39)
281 HRGN32 CreateEllipticRgn32( INT32 left, INT32 top, INT32 right, INT32 bottom )
283 return CreateRoundRectRgn32( left, top, right, bottom,
284 right-left, bottom-top );
288 /***********************************************************************
289 * CreateEllipticRgnIndirect16 (GDI.55)
291 HRGN16 CreateEllipticRgnIndirect16( const RECT16 *rect )
293 return CreateRoundRectRgn32( rect->left, rect->top, rect->right,
294 rect->bottom, rect->right - rect->left,
295 rect->bottom - rect->top );
299 /***********************************************************************
300 * CreateEllipticRgnIndirect32 (GDI32.40)
302 HRGN32 CreateEllipticRgnIndirect32( const RECT32 *rect )
304 return CreateRoundRectRgn32( rect->left, rect->top, rect->right,
305 rect->bottom, rect->right - rect->left,
306 rect->bottom - rect->top );
310 /***********************************************************************
311 * CreatePolygonRgn16 (GDI.63)
313 HRGN16 CreatePolygonRgn16( const POINT16 * points, INT16 count, INT16 mode )
315 return CreatePolyPolygonRgn16( points, &count, 1, mode );
319 /***********************************************************************
320 * CreatePolyPolygonRgn16 (GDI.451)
322 HRGN16 CreatePolyPolygonRgn16( const POINT16 * points, const INT16 * count,
323 INT16 nbpolygons, INT16 mode )
325 int i,nrofpts;
326 LPINT32 count32;
327 LPPOINT32 points32;
328 HRGN32 ret;
330 nrofpts=0;
331 for (i=nbpolygons;i--;)
332 nrofpts+=count[i];
333 points32 = (LPPOINT32)HeapAlloc( GetProcessHeap(), 0,
334 nrofpts*sizeof(POINT32) );
335 for (i=nrofpts;i--;)
336 CONV_POINT16TO32( &(points[i]), &(points32[i]) );
337 count32 = (LPINT32)HeapAlloc( GetProcessHeap(), 0,
338 sizeof(INT32)*nbpolygons );
339 for (i=nbpolygons;i--;)
340 count32[i]=count[i];
341 ret = CreatePolyPolygonRgn32(points32,count32,nbpolygons,mode);
342 HeapFree( GetProcessHeap(), 0, count32 );
343 HeapFree( GetProcessHeap(), 0, points32 );
344 return ret;
348 /***********************************************************************
349 * CreatePolygonRgn32 (GDI32.58)
351 HRGN32 CreatePolygonRgn32( const POINT32 *points, INT32 count, INT32 mode )
353 return CreatePolyPolygonRgn32( points, &count, 1, mode );
357 /***********************************************************************
358 * CreatePolyPolygonRgn32 (GDI32.57)
360 HRGN32 CreatePolyPolygonRgn32( const POINT32 * points, const INT32 * count,
361 INT32 nbpolygons, INT32 mode )
363 RGNOBJ * obj;
364 HRGN32 hrgn;
365 int i, j, maxPoints;
366 XPoint *xpoints, *pt;
367 Region xrgn;
369 /* Allocate points array */
371 if (!nbpolygons) return 0;
372 for (i = maxPoints = 0; i < nbpolygons; i++)
373 if (maxPoints < count[i]) maxPoints = count[i];
374 if (!maxPoints) return 0;
375 if (!(xpoints = (XPoint *)HeapAlloc( GetProcessHeap(), 0,
376 sizeof(XPoint) * maxPoints )))
377 return 0;
379 /* Allocate region */
381 if (!(hrgn = GDI_AllocObject( sizeof(RGNOBJ), REGION_MAGIC )))
383 HeapFree( GetProcessHeap(), 0, xpoints );
384 return 0;
386 obj = (RGNOBJ *) GDI_HEAP_LIN_ADDR( hrgn );
387 obj->xrgn = 0;
388 dprintf_region(stddeb, "CreatePolyPolygonRgn: %d polygons, returning %04x\n",
389 nbpolygons, hrgn );
391 /* Create X region */
393 for (i = 0; i < nbpolygons; i++, count++)
395 for (j = *count, pt = xpoints; j > 0; j--, points++, pt++)
397 pt->x = points->x;
398 pt->y = points->y;
400 xrgn = XPolygonRegion( xpoints, *count,
401 (mode == WINDING) ? WindingRule : EvenOddRule );
402 if (!xrgn)
404 if (obj->xrgn) XDestroyRegion( obj->xrgn );
405 HeapFree( GetProcessHeap(), 0, xpoints );
406 GDI_FreeObject( hrgn );
407 return 0;
409 if (i > 0)
411 Region tmprgn = XCreateRegion();
412 if (mode == WINDING) XUnionRegion( xrgn, obj->xrgn, tmprgn );
413 else XXorRegion( xrgn, obj->xrgn, tmprgn );
414 XDestroyRegion( obj->xrgn );
415 obj->xrgn = tmprgn;
417 else obj->xrgn = xrgn;
420 HeapFree( GetProcessHeap(), 0, xpoints );
421 return hrgn;
425 /***********************************************************************
426 * PtInRegion16 (GDI.161)
428 BOOL16 PtInRegion16( HRGN16 hrgn, INT16 x, INT16 y )
430 return PtInRegion32( hrgn, x, y );
434 /***********************************************************************
435 * PtInRegion32 (GDI32.278)
437 BOOL32 PtInRegion32( HRGN32 hrgn, INT32 x, INT32 y )
439 RGNOBJ * obj;
441 if (!(obj = (RGNOBJ *) GDI_GetObjPtr( hrgn, REGION_MAGIC ))) return FALSE;
442 if (!obj->xrgn) return FALSE;
443 return XPointInRegion( obj->xrgn, x, y );
447 /***********************************************************************
448 * RectInRegion16 (GDI.181)
450 BOOL16 RectInRegion16( HRGN16 hrgn, const RECT16 *rect )
452 RGNOBJ * obj;
454 if (!(obj = (RGNOBJ *) GDI_GetObjPtr( hrgn, REGION_MAGIC ))) return FALSE;
455 if (!obj->xrgn) return FALSE;
456 return (XRectInRegion( obj->xrgn, rect->left, rect->top,
457 rect->right-rect->left,
458 rect->bottom-rect->top ) != RectangleOut);
462 /***********************************************************************
463 * RectInRegion32 (GDI32.281)
465 BOOL32 RectInRegion32( HRGN32 hrgn, const RECT32 *rect )
467 RGNOBJ * obj;
469 if (!(obj = (RGNOBJ *) GDI_GetObjPtr( hrgn, REGION_MAGIC ))) return FALSE;
470 if (!obj->xrgn) return FALSE;
471 return (XRectInRegion( obj->xrgn, rect->left, rect->top,
472 rect->right-rect->left,
473 rect->bottom-rect->top ) != RectangleOut);
477 /***********************************************************************
478 * EqualRgn16 (GDI.72)
480 BOOL16 EqualRgn16( HRGN16 rgn1, HRGN16 rgn2 )
482 return EqualRgn32( rgn1, rgn2 );
486 /***********************************************************************
487 * EqualRgn32 (GDI32.90)
489 BOOL32 EqualRgn32( HRGN32 rgn1, HRGN32 rgn2 )
491 RGNOBJ *obj1, *obj2;
492 if (!(obj1 = (RGNOBJ *) GDI_GetObjPtr( rgn1, REGION_MAGIC ))) return FALSE;
493 if (!(obj2 = (RGNOBJ *) GDI_GetObjPtr( rgn2, REGION_MAGIC ))) return FALSE;
494 if (!obj1->xrgn || !obj2->xrgn) return (!obj1->xrgn && !obj2->xrgn);
495 return XEqualRegion( obj1->xrgn, obj2->xrgn );
499 /***********************************************************************
500 * REGION_CopyRegion
502 * Copy region src into dest.
504 static INT32 REGION_CopyRegion( RGNOBJ *src, RGNOBJ *dest )
506 Region tmprgn;
507 if (src->xrgn)
509 if (src->xrgn == dest->xrgn) return COMPLEXREGION;
510 tmprgn = XCreateRegion();
511 if (!dest->xrgn) dest->xrgn = XCreateRegion();
512 XUnionRegion( tmprgn, src->xrgn, dest->xrgn );
513 XDestroyRegion( tmprgn );
514 return COMPLEXREGION;
516 else
518 if (dest->xrgn) XDestroyRegion( dest->xrgn );
519 dest->xrgn = 0;
520 return NULLREGION;
524 /***********************************************************************
525 * REGION_UnionRectWithRgn
527 * Add rectangle to region
529 BOOL32 REGION_UnionRectWithRgn( HRGN32 hRgn, const RECT32 *rc )
531 RGNOBJ *rgnObj = (RGNOBJ*) GDI_GetObjPtr( hRgn, REGION_MAGIC );
532 XRectangle rect = { rc->left, rc->top, rc->right - rc->left, rc->bottom - rc->top };
533 BOOL32 ret = FALSE;
535 if( rgnObj )
537 if( !rgnObj->xrgn )
539 if (!(rgnObj->xrgn = XCreateRegion()))
541 GDI_FreeObject( hRgn );
542 return 0;
544 ret = SIMPLEREGION;
546 else
547 ret = COMPLEXREGION;
548 XUnionRectWithRegion( &rect, rgnObj->xrgn, rgnObj->xrgn );
550 return ret;
554 /***********************************************************************
555 * REGION_CreateFrameRgn
557 * Create a region that is a frame around another region
559 BOOL32 REGION_FrameRgn( HRGN32 hDest, HRGN32 hSrc, INT32 x, INT32 y )
561 RGNOBJ *destObj,*srcObj;
562 Region result;
564 destObj = (RGNOBJ*) GDI_GetObjPtr( hDest, REGION_MAGIC );
565 srcObj = (RGNOBJ*) GDI_GetObjPtr( hSrc, REGION_MAGIC );
566 if (!srcObj->xrgn) return FALSE;
567 REGION_CopyRegion( srcObj, destObj );
568 XShrinkRegion( destObj->xrgn, -x, -y );
569 result = XCreateRegion();
570 XSubtractRegion( destObj->xrgn, srcObj->xrgn, result );
571 XDestroyRegion( destObj->xrgn );
572 destObj->xrgn = result;
573 return TRUE;
577 /***********************************************************************
578 * CombineRgn16 (GDI.451)
580 INT16 CombineRgn16( HRGN16 hDest, HRGN16 hSrc1, HRGN16 hSrc2, INT16 mode )
582 return (INT16)CombineRgn32( hDest, hSrc1, hSrc2, mode );
586 /***********************************************************************
587 * CombineRgn32 (GDI32.19)
589 * Note: The behavior is correct even if src and dest regions are the same.
591 INT32 CombineRgn32( HRGN32 hDest, HRGN32 hSrc1, HRGN32 hSrc2, INT32 mode )
593 RGNOBJ *destObj, *src1Obj, *src2Obj;
594 Region destrgn;
596 dprintf_region(stddeb, "CombineRgn: %04x,%04x -> %04x mode=%x\n",
597 hSrc1, hSrc2, hDest, mode );
599 if (!(destObj = (RGNOBJ *) GDI_GetObjPtr( hDest, REGION_MAGIC )))
600 return ERROR;
601 if (!(src1Obj = (RGNOBJ *) GDI_GetObjPtr( hSrc1, REGION_MAGIC )))
602 return ERROR;
603 if (mode == RGN_COPY) return REGION_CopyRegion( src1Obj, destObj );
605 if (!(src2Obj = (RGNOBJ *) GDI_GetObjPtr( hSrc2, REGION_MAGIC )))
606 return ERROR;
608 /* Some optimizations for null regions */
610 if (!src1Obj->xrgn || !src2Obj->xrgn)
612 switch(mode)
614 case RGN_DIFF:
615 if (src1Obj->xrgn)
616 return REGION_CopyRegion( src1Obj, destObj );
617 /* else fall through */
618 case RGN_AND:
619 if (destObj->xrgn) XDestroyRegion( destObj->xrgn );
620 destObj->xrgn = 0;
621 return NULLREGION;
622 case RGN_OR:
623 case RGN_XOR:
624 if (src1Obj->xrgn)
625 return REGION_CopyRegion( src1Obj, destObj );
626 else
627 return REGION_CopyRegion( src2Obj, destObj );
628 default:
629 return ERROR;
633 /* Perform the operation with the two X regions */
635 if (!(destrgn = XCreateRegion())) return ERROR;
636 switch(mode)
638 case RGN_AND:
639 XIntersectRegion( src1Obj->xrgn, src2Obj->xrgn, destrgn );
640 break;
641 case RGN_OR:
642 XUnionRegion( src1Obj->xrgn, src2Obj->xrgn, destrgn );
643 break;
644 case RGN_XOR:
645 XXorRegion( src1Obj->xrgn, src2Obj->xrgn, destrgn );
646 break;
647 case RGN_DIFF:
648 XSubtractRegion( src1Obj->xrgn, src2Obj->xrgn, destrgn );
649 break;
650 default:
651 XDestroyRegion( destrgn );
652 return ERROR;
654 if (destObj->xrgn) XDestroyRegion( destObj->xrgn );
655 destObj->xrgn = destrgn;
656 if (XEmptyRegion(destObj->xrgn))
658 XDestroyRegion( destObj->xrgn );
659 destObj->xrgn = 0;
660 return NULLREGION;
662 return COMPLEXREGION;