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
;