4 * Copyright 1993, 1994, 1995 Alexandre Julliard
6 * RGNOBJ is documented in the Dr. Dobbs Journal March 1993.
16 /***********************************************************************
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
);
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
);
60 SetRectEmpty16( rect
);
66 XClipBox( obj
->xrgn
, &xrect
);
67 SetRect16( rect
, xrect
.x
, xrect
.y
,
68 xrect
.x
+ xrect
.width
, xrect
.y
+ xrect
.height
);
74 /***********************************************************************
75 * GetRgnBox32 (GDI32.219)
77 INT32
GetRgnBox32( HRGN32 hrgn
, LPRECT32 rect
)
80 INT16 ret
= GetRgnBox16( hrgn
, &r
);
81 CONV_RECT16TO32( &r
, rect
);
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
)
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
);
113 XUnionRectWithRegion( &rect
, obj
->xrgn
, obj
->xrgn
);
116 dprintf_region( stddeb
, "CreateRectRgn(%d,%d-%d,%d): returning %04x\n",
117 left
, top
, right
, bottom
, 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
)
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
);
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
)
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
);
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 */
221 yd
= asq
* ellipse_height
; /* 2a^2b */
223 rect
.x
= left
+ ellipse_width
/ 2;
224 rect
.width
= right
- left
- ellipse_width
;
227 /* Loop to draw first half of quadrant */
231 if (d
> 0) /* if nearest pixel is toward the center */
233 /* move toward center */
235 XUnionRectWithRegion( &rect
, obj
->xrgn
, obj
->xrgn
);
237 XUnionRectWithRegion( &rect
, obj
->xrgn
, obj
->xrgn
);
241 rect
.x
--; /* next horiz point */
247 /* Loop to draw second half of quadrant */
249 d
+= (3 * (asq
-bsq
) / 2 - (xd
+yd
)) / 2;
252 /* next vertical point */
254 XUnionRectWithRegion( &rect
, obj
->xrgn
, obj
->xrgn
);
256 XUnionRectWithRegion( &rect
, obj
->xrgn
, obj
->xrgn
);
257 if (d
< 0) /* if nearest pixel is outside ellipse */
259 rect
.x
--; /* move away from center */
268 /* Add the inside rectangle */
273 rect
.height
= bottom
- top
+ 1;
274 XUnionRectWithRegion( &rect
, obj
->xrgn
, obj
->xrgn
);
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
)
343 for (i
=nbpolygons
;i
--;)
345 points32
= (LPPOINT32
)HeapAlloc( GetProcessHeap(), 0,
346 nrofpts
*sizeof(POINT32
) );
348 CONV_POINT16TO32( &(points
[i
]), &(points32
[i
]) );
349 count32
= (LPINT32
)HeapAlloc( GetProcessHeap(), 0,
350 sizeof(INT32
)*nbpolygons
);
351 for (i
=nbpolygons
;i
--;)
353 ret
= CreatePolyPolygonRgn32(points32
,count32
,nbpolygons
,mode
);
354 HeapFree( GetProcessHeap(), 0, count32
);
355 HeapFree( GetProcessHeap(), 0, points32
);
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
)
378 XPoint
*xpoints
, *pt
;
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
)))
391 /* Allocate region */
393 if (!(hrgn
= GDI_AllocObject( sizeof(RGNOBJ
), REGION_MAGIC
)))
395 HeapFree( GetProcessHeap(), 0, xpoints
);
398 obj
= (RGNOBJ
*) GDI_HEAP_LIN_ADDR( hrgn
);
400 dprintf_region(stddeb
, "CreatePolyPolygonRgn: %d polygons, returning %04x\n",
403 /* Create X region */
405 for (i
= 0; i
< nbpolygons
; i
++, count
++)
407 for (j
= *count
, pt
= xpoints
; j
> 0; j
--, points
++, pt
++)
412 xrgn
= XPolygonRegion( xpoints
, *count
,
413 (mode
== WINDING
) ? WindingRule
: EvenOddRule
);
416 if (obj
->xrgn
) XDestroyRegion( obj
->xrgn
);
417 HeapFree( GetProcessHeap(), 0, xpoints
);
418 GDI_FreeObject( hrgn
);
423 Region tmprgn
= XCreateRegion();
424 if (mode
== WINDING
) XUnionRegion( xrgn
, obj
->xrgn
, tmprgn
);
425 else XXorRegion( xrgn
, obj
->xrgn
, tmprgn
);
426 XDestroyRegion( obj
->xrgn
);
429 else obj
->xrgn
= xrgn
;
432 HeapFree( GetProcessHeap(), 0, xpoints
);
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
)
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
)
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
)
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
)
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 /***********************************************************************
514 * Copy region src into dest.
516 static INT32
REGION_CopyRegion( RGNOBJ
*src
, RGNOBJ
*dest
)
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
;
530 if (dest
->xrgn
) XDestroyRegion( dest
->xrgn
);
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
};
551 if (!(rgnObj
->xrgn
= XCreateRegion()))
553 GDI_FreeObject( hRgn
);
560 XUnionRectWithRegion( &rect
, rgnObj
->xrgn
, rgnObj
->xrgn
);
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
;
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
;
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
;
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
)))
613 if (!(src1Obj
= (RGNOBJ
*) GDI_GetObjPtr( hSrc1
, REGION_MAGIC
)))
615 if (mode
== RGN_COPY
) return REGION_CopyRegion( src1Obj
, destObj
);
617 if (!(src2Obj
= (RGNOBJ
*) GDI_GetObjPtr( hSrc2
, REGION_MAGIC
)))
620 /* Some optimizations for null regions */
622 if (!src1Obj
->xrgn
|| !src2Obj
->xrgn
)
628 return REGION_CopyRegion( src1Obj
, destObj
);
629 /* else fall through */
631 if (destObj
->xrgn
) XDestroyRegion( destObj
->xrgn
);
637 return REGION_CopyRegion( src1Obj
, destObj
);
639 return REGION_CopyRegion( src2Obj
, destObj
);
645 /* Perform the operation with the two X regions */
647 if (!(destrgn
= XCreateRegion())) return ERROR
;
651 XIntersectRegion( src1Obj
->xrgn
, src2Obj
->xrgn
, destrgn
);
654 XUnionRegion( src1Obj
->xrgn
, src2Obj
->xrgn
, destrgn
);
657 XXorRegion( src1Obj
->xrgn
, src2Obj
->xrgn
, destrgn
);
660 XSubtractRegion( src1Obj
->xrgn
, src2Obj
->xrgn
, destrgn
);
663 XDestroyRegion( destrgn
);
666 if (destObj
->xrgn
) XDestroyRegion( destObj
->xrgn
);
667 destObj
->xrgn
= destrgn
;
668 if (XEmptyRegion(destObj
->xrgn
))
670 XDestroyRegion( destObj
->xrgn
);
674 return COMPLEXREGION
;