4 * Copyright 1993, 1994, 1995 Alexandre Julliard
13 /* #define DEBUG_REGION */
17 /***********************************************************************
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 /***********************************************************************
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 );
42 /***********************************************************************
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 );
58 XClipBox( obj->xrgn, &xrect );
59 SetRect( rect, xrect.x, xrect.y,
60 xrect.x + xrect.width, xrect.y + xrect.height);
66 /***********************************************************************
67 * CreateRectRgn (GDI.64)
69 HRGN CreateRectRgn( short left, short top, short right, short bottom )
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 );
84 XUnionRectWithRegion( &rect, obj->xrgn, obj->xrgn );
87 dprintf_region( stddeb, "CreateRectRgn(%d,%d-%d,%d): returning %x\n",
88 left, top, right, bottom, 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 )
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 );
124 /***********************************************************************
125 * CreateRoundRectRgn (GDI.444)
127 HRGN CreateRoundRectRgn( short left, short top, short right, short bottom,
128 short ellipse_width, short ellipse_height )
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 );
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 */
161 yd = asq * ellipse_height; /* 2a^2b */
163 rect.x = left + ellipse_width / 2;
164 rect.width = right - left - ellipse_width;
167 /* Loop to draw first half of quadrant */
171 if (d > 0) /* if nearest pixel is toward the center */
173 /* move toward center */
175 XUnionRectWithRegion( &rect, obj->xrgn, obj->xrgn );
177 XUnionRectWithRegion( &rect, obj->xrgn, obj->xrgn );
181 rect.x--; /* next horiz point */
187 /* Loop to draw second half of quadrant */
189 d += (3 * (asq-bsq) / 2 - (xd+yd)) / 2;
192 /* next vertical point */
194 XUnionRectWithRegion( &rect, obj->xrgn, obj->xrgn );
196 XUnionRectWithRegion( &rect, obj->xrgn, obj->xrgn );
197 if (d < 0) /* if nearest pixel is outside ellipse */
199 rect.x--; /* move away from center */
208 /* Add the inside rectangle */
213 rect.height = bottom - top + 1;
214 XUnionRectWithRegion( &rect, obj->xrgn, obj->xrgn );
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 )
258 XPoint *xpoints, *pt;
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 )))
270 /* Allocate region */
272 if (!(hrgn = GDI_AllocObject( sizeof(RGNOBJ), REGION_MAGIC )))
277 obj = (RGNOBJ *) GDI_HEAP_LIN_ADDR( hrgn );
279 dprintf_region(stddeb, "CreatePolyPolygonRgn: %d polygons, returning %x\n",
282 /* Create X region */
284 for (i = 0; i < nbpolygons; i++, count++)
286 for (j = *count, pt = xpoints; j > 0; j--, points++, pt++)
291 xrgn = XPolygonRegion( xpoints, *count,
292 (mode == WINDING) ? WindingRule : EvenOddRule );
295 if (obj->xrgn) XDestroyRegion( obj->xrgn );
297 GDI_FreeObject( hrgn );
302 Region tmprgn = XCreateRegion();
303 if (mode == WINDING) XUnionRegion( xrgn, obj->xrgn, tmprgn );
304 else XXorRegion( xrgn, obj->xrgn, tmprgn );
305 XDestroyRegion( obj->xrgn );
308 else obj->xrgn = xrgn;
316 /***********************************************************************
317 * PtInRegion (GDI.161)
319 BOOL PtInRegion( HRGN hrgn, short x, short y )
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 )
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 /***********************************************************************
347 BOOL EqualRgn( HRGN rgn1, HRGN rgn2 )
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 /***********************************************************************
360 * Copy region src into dest.
362 static int REGION_CopyRegion( RGNOBJ *src, RGNOBJ *dest )
366 Region tmprgn = XCreateRegion();
367 if (!dest->xrgn) dest->xrgn = XCreateRegion();
368 XUnionRegion( tmprgn, src->xrgn, dest->xrgn );
369 XDestroyRegion( tmprgn );
370 return COMPLEXREGION;
374 if (dest->xrgn) XDestroyRegion( dest->xrgn );
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;
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;
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 )))
414 if (!(src1Obj = (RGNOBJ *) GDI_GetObjPtr( hSrc1, REGION_MAGIC )))
416 if (mode == RGN_COPY) return REGION_CopyRegion( src1Obj, destObj );
418 if (!(src2Obj = (RGNOBJ *) GDI_GetObjPtr( hSrc2, REGION_MAGIC )))
421 /* Some optimizations for null regions */
423 if (!src1Obj->xrgn || !src2Obj->xrgn)
429 return REGION_CopyRegion( src1Obj, destObj );
430 /* else fall through */
432 if (destObj->xrgn) XDestroyRegion( destObj->xrgn );
438 return REGION_CopyRegion( src1Obj, destObj );
440 return REGION_CopyRegion( src2Obj, destObj );
446 /* Perform the operation with the two X regions */
448 if (!destObj->xrgn) destObj->xrgn = XCreateRegion();
452 XIntersectRegion( src1Obj->xrgn, src2Obj->xrgn, destObj->xrgn );
455 XUnionRegion( src1Obj->xrgn, src2Obj->xrgn, destObj->xrgn );
458 XXorRegion( src1Obj->xrgn, src2Obj->xrgn, destObj->xrgn );
461 XSubtractRegion( src1Obj->xrgn, src2Obj->xrgn, destObj->xrgn );
466 if (XEmptyRegion(destObj->xrgn))
468 XDestroyRegion( destObj->xrgn );
472 else return COMPLEXREGION;