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 WINAPI
OffsetRgn16( HRGN16 hrgn
, INT16 x
, INT16 y
)
32 return OffsetRgn32( hrgn
, x
, y
);
36 /***********************************************************************
37 * OffsetRgn32 (GDI32.256)
39 INT32 WINAPI
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
);
46 GDI_HEAP_UNLOCK( hrgn
);
49 XOffsetRegion( obj
->xrgn
, x
, y
);
50 GDI_HEAP_UNLOCK( hrgn
);
55 /***********************************************************************
56 * GetRgnBox16 (GDI.134)
58 INT16 WINAPI
GetRgnBox16( HRGN16 hrgn
, LPRECT16 rect
)
60 RGNOBJ
* obj
= (RGNOBJ
*) GDI_GetObjPtr( hrgn
, REGION_MAGIC
);
61 if (!obj
) return ERROR
;
62 dprintf_region(stddeb
, "GetRgnBox: %04x\n", hrgn
);
65 SetRectEmpty16( rect
);
66 GDI_HEAP_UNLOCK( hrgn
);
72 XClipBox( obj
->xrgn
, &xrect
);
73 GDI_HEAP_UNLOCK(hrgn
);
74 SetRect16( rect
, xrect
.x
, xrect
.y
,
75 xrect
.x
+ xrect
.width
, xrect
.y
+ xrect
.height
);
81 /***********************************************************************
82 * GetRgnBox32 (GDI32.219)
84 INT32 WINAPI
GetRgnBox32( HRGN32 hrgn
, LPRECT32 rect
)
87 INT16 ret
= GetRgnBox16( hrgn
, &r
);
88 CONV_RECT16TO32( &r
, rect
);
93 /***********************************************************************
94 * CreateRectRgn16 (GDI.64)
96 HRGN16 WINAPI
CreateRectRgn16(INT16 left
, INT16 top
, INT16 right
, INT16 bottom
)
98 return (HRGN16
)CreateRectRgn32( left
, top
, right
, bottom
);
102 /***********************************************************************
103 * CreateRectRgn32 (GDI32.59)
105 HRGN32 WINAPI
CreateRectRgn32(INT32 left
, INT32 top
, INT32 right
, INT32 bottom
)
110 if (!(hrgn
= GDI_AllocObject( sizeof(RGNOBJ
), REGION_MAGIC
))) return 0;
111 obj
= (RGNOBJ
*) GDI_HEAP_LOCK( hrgn
);
112 if ((right
> left
) && (bottom
> top
))
114 XRectangle rect
= { left
, top
, right
- left
, bottom
- top
};
115 if (!(obj
->xrgn
= XCreateRegion()))
117 GDI_FreeObject( hrgn
);
120 XUnionRectWithRegion( &rect
, obj
->xrgn
, obj
->xrgn
);
123 dprintf_region( stddeb
, "CreateRectRgn(%d,%d-%d,%d): returning %04x\n",
124 left
, top
, right
, bottom
, hrgn
);
125 GDI_HEAP_UNLOCK( hrgn
);
130 /***********************************************************************
131 * CreateRectRgnIndirect16 (GDI.65)
133 HRGN16 WINAPI
CreateRectRgnIndirect16( const RECT16
* rect
)
135 return CreateRectRgn32( rect
->left
, rect
->top
, rect
->right
, rect
->bottom
);
139 /***********************************************************************
140 * CreateRectRgnIndirect32 (GDI32.60)
142 HRGN32 WINAPI
CreateRectRgnIndirect32( const RECT32
* rect
)
144 return CreateRectRgn32( rect
->left
, rect
->top
, rect
->right
, rect
->bottom
);
148 /***********************************************************************
149 * SetRectRgn16 (GDI.172)
151 VOID WINAPI
SetRectRgn16( HRGN16 hrgn
, INT16 left
, INT16 top
,
152 INT16 right
, INT16 bottom
)
154 SetRectRgn32( hrgn
, left
, top
, right
, bottom
);
158 /***********************************************************************
159 * SetRectRgn32 (GDI32.332)
161 VOID WINAPI
SetRectRgn32( HRGN32 hrgn
, INT32 left
, INT32 top
,
162 INT32 right
, INT32 bottom
)
166 dprintf_region(stddeb
, "SetRectRgn: %04x %d,%d-%d,%d\n",
167 hrgn
, left
, top
, right
, bottom
);
169 if (!(obj
= (RGNOBJ
*) GDI_GetObjPtr( hrgn
, REGION_MAGIC
))) return;
170 if (obj
->xrgn
) XDestroyRegion( obj
->xrgn
);
171 if ((right
> left
) && (bottom
> top
))
173 XRectangle rect
= { left
, top
, right
- left
, bottom
- top
};
174 if ((obj
->xrgn
= XCreateRegion()) != 0)
175 XUnionRectWithRegion( &rect
, obj
->xrgn
, obj
->xrgn
);
178 GDI_HEAP_UNLOCK( hrgn
);
182 /***********************************************************************
183 * CreateRoundRectRgn16 (GDI.444)
185 HRGN16 WINAPI
CreateRoundRectRgn16( INT16 left
, INT16 top
,
186 INT16 right
, INT16 bottom
,
187 INT16 ellipse_width
, INT16 ellipse_height
)
189 return (HRGN16
)CreateRoundRectRgn32( left
, top
, right
, bottom
,
190 ellipse_width
, ellipse_height
);
194 /***********************************************************************
195 * CreateRoundRectRgn32 (GDI32.61)
197 HRGN32 WINAPI
CreateRoundRectRgn32( INT32 left
, INT32 top
,
198 INT32 right
, INT32 bottom
,
199 INT32 ellipse_width
, INT32 ellipse_height
)
204 int asq
, bsq
, d
, xd
, yd
;
206 /* Check if we can do a normal rectangle instead */
208 if ((right
<= left
) || (bottom
<= top
) ||
209 (ellipse_width
<= 0) || (ellipse_height
<= 0))
210 return CreateRectRgn32( left
, top
, right
, bottom
);
214 if (!(hrgn
= GDI_AllocObject( sizeof(RGNOBJ
), REGION_MAGIC
))) return 0;
215 obj
= (RGNOBJ
*) GDI_HEAP_LOCK( hrgn
);
216 obj
->xrgn
= XCreateRegion();
217 dprintf_region(stddeb
,"CreateRoundRectRgn(%d,%d-%d,%d %dx%d): return=%04x\n",
218 left
, top
, right
, bottom
, ellipse_width
, ellipse_height
, hrgn
);
220 /* Check parameters */
222 if (ellipse_width
> right
-left
) ellipse_width
= right
-left
;
223 if (ellipse_height
> bottom
-top
) ellipse_height
= bottom
-top
;
225 /* Ellipse algorithm, based on an article by K. Porter */
226 /* in DDJ Graphics Programming Column, 8/89 */
228 asq
= ellipse_width
* ellipse_width
/ 4; /* a^2 */
229 bsq
= ellipse_height
* ellipse_height
/ 4; /* b^2 */
230 d
= bsq
- asq
* ellipse_height
/ 2 + asq
/ 4; /* b^2 - a^2b + a^2/4 */
232 yd
= asq
* ellipse_height
; /* 2a^2b */
234 rect
.x
= left
+ ellipse_width
/ 2;
235 rect
.width
= right
- left
- ellipse_width
;
238 /* Loop to draw first half of quadrant */
242 if (d
> 0) /* if nearest pixel is toward the center */
244 /* move toward center */
246 XUnionRectWithRegion( &rect
, obj
->xrgn
, obj
->xrgn
);
248 XUnionRectWithRegion( &rect
, obj
->xrgn
, obj
->xrgn
);
252 rect
.x
--; /* next horiz point */
258 /* Loop to draw second half of quadrant */
260 d
+= (3 * (asq
-bsq
) / 2 - (xd
+yd
)) / 2;
263 /* next vertical point */
265 XUnionRectWithRegion( &rect
, obj
->xrgn
, obj
->xrgn
);
267 XUnionRectWithRegion( &rect
, obj
->xrgn
, obj
->xrgn
);
268 if (d
< 0) /* if nearest pixel is outside ellipse */
270 rect
.x
--; /* move away from center */
279 /* Add the inside rectangle */
284 rect
.height
= bottom
- top
+ 1;
285 XUnionRectWithRegion( &rect
, obj
->xrgn
, obj
->xrgn
);
287 GDI_HEAP_UNLOCK( hrgn
);
292 /***********************************************************************
293 * CreateEllipticRgn16 (GDI.54)
295 HRGN16 WINAPI
CreateEllipticRgn16( INT16 left
, INT16 top
,
296 INT16 right
, INT16 bottom
)
298 return (HRGN16
)CreateRoundRectRgn32( left
, top
, right
, bottom
,
299 right
-left
, bottom
-top
);
303 /***********************************************************************
304 * CreateEllipticRgn32 (GDI32.39)
306 HRGN32 WINAPI
CreateEllipticRgn32( INT32 left
, INT32 top
,
307 INT32 right
, INT32 bottom
)
309 return CreateRoundRectRgn32( left
, top
, right
, bottom
,
310 right
-left
, bottom
-top
);
314 /***********************************************************************
315 * CreateEllipticRgnIndirect16 (GDI.55)
317 HRGN16 WINAPI
CreateEllipticRgnIndirect16( const RECT16
*rect
)
319 return CreateRoundRectRgn32( rect
->left
, rect
->top
, rect
->right
,
320 rect
->bottom
, rect
->right
- rect
->left
,
321 rect
->bottom
- rect
->top
);
325 /***********************************************************************
326 * CreateEllipticRgnIndirect32 (GDI32.40)
328 HRGN32 WINAPI
CreateEllipticRgnIndirect32( const RECT32
*rect
)
330 return CreateRoundRectRgn32( rect
->left
, rect
->top
, rect
->right
,
331 rect
->bottom
, rect
->right
- rect
->left
,
332 rect
->bottom
- rect
->top
);
336 /***********************************************************************
337 * CreatePolygonRgn16 (GDI.63)
339 HRGN16 WINAPI
CreatePolygonRgn16( const POINT16
* points
, INT16 count
,
342 return CreatePolyPolygonRgn16( points
, &count
, 1, mode
);
346 /***********************************************************************
347 * CreatePolyPolygonRgn16 (GDI.451)
349 HRGN16 WINAPI
CreatePolyPolygonRgn16( const POINT16
* points
,
351 INT16 nbpolygons
, INT16 mode
)
359 for (i
=nbpolygons
;i
--;)
361 points32
= (LPPOINT32
)HeapAlloc( GetProcessHeap(), 0,
362 nrofpts
*sizeof(POINT32
) );
364 CONV_POINT16TO32( &(points
[i
]), &(points32
[i
]) );
365 count32
= (LPINT32
)HeapAlloc( GetProcessHeap(), 0,
366 sizeof(INT32
)*nbpolygons
);
367 for (i
=nbpolygons
;i
--;)
369 ret
= CreatePolyPolygonRgn32(points32
,count32
,nbpolygons
,mode
);
370 HeapFree( GetProcessHeap(), 0, count32
);
371 HeapFree( GetProcessHeap(), 0, points32
);
376 /***********************************************************************
377 * CreatePolygonRgn32 (GDI32.58)
379 HRGN32 WINAPI
CreatePolygonRgn32( const POINT32
*points
, INT32 count
,
382 return CreatePolyPolygonRgn32( points
, &count
, 1, mode
);
386 /***********************************************************************
387 * CreatePolyPolygonRgn32 (GDI32.57)
389 HRGN32 WINAPI
CreatePolyPolygonRgn32( const POINT32
* points
,
391 INT32 nbpolygons
, INT32 mode
)
396 XPoint
*xpoints
, *pt
;
399 /* Allocate points array */
401 if (!nbpolygons
) return 0;
402 for (i
= maxPoints
= 0; i
< nbpolygons
; i
++)
403 if (maxPoints
< count
[i
]) maxPoints
= count
[i
];
404 if (!maxPoints
) return 0;
405 if (!(xpoints
= (XPoint
*)HeapAlloc( GetProcessHeap(), 0,
406 sizeof(XPoint
) * maxPoints
)))
409 /* Allocate region */
411 if (!(hrgn
= GDI_AllocObject( sizeof(RGNOBJ
), REGION_MAGIC
)))
413 HeapFree( GetProcessHeap(), 0, xpoints
);
416 obj
= (RGNOBJ
*) GDI_HEAP_LOCK( hrgn
);
418 dprintf_region(stddeb
, "CreatePolyPolygonRgn: %d polygons, returning %04x\n",
421 /* Create X region */
423 for (i
= 0; i
< nbpolygons
; i
++, count
++)
425 for (j
= *count
, pt
= xpoints
; j
> 0; j
--, points
++, pt
++)
430 xrgn
= XPolygonRegion( xpoints
, *count
,
431 (mode
== WINDING
) ? WindingRule
: EvenOddRule
);
434 if (obj
->xrgn
) XDestroyRegion( obj
->xrgn
);
435 HeapFree( GetProcessHeap(), 0, xpoints
);
436 GDI_FreeObject( hrgn
);
441 Region tmprgn
= XCreateRegion();
442 if (mode
== WINDING
) XUnionRegion( xrgn
, obj
->xrgn
, tmprgn
);
443 else XXorRegion( xrgn
, obj
->xrgn
, tmprgn
);
444 XDestroyRegion( obj
->xrgn
);
447 else obj
->xrgn
= xrgn
;
450 HeapFree( GetProcessHeap(), 0, xpoints
);
451 GDI_HEAP_UNLOCK( hrgn
);
456 /***********************************************************************
457 * PtInRegion16 (GDI.161)
459 BOOL16 WINAPI
PtInRegion16( HRGN16 hrgn
, INT16 x
, INT16 y
)
461 return PtInRegion32( hrgn
, x
, y
);
465 /***********************************************************************
466 * PtInRegion32 (GDI32.278)
468 BOOL32 WINAPI
PtInRegion32( HRGN32 hrgn
, INT32 x
, INT32 y
)
473 if (!(obj
= (RGNOBJ
*) GDI_GetObjPtr( hrgn
, REGION_MAGIC
))) return FALSE
;
474 if (!obj
->xrgn
) result
= FALSE
;
475 else result
= XPointInRegion( obj
->xrgn
, x
, y
);
476 GDI_HEAP_UNLOCK( hrgn
);
481 /***********************************************************************
482 * RectInRegion16 (GDI.181)
484 BOOL16 WINAPI
RectInRegion16( HRGN16 hrgn
, const RECT16
*rect
)
489 if (!(obj
= (RGNOBJ
*) GDI_GetObjPtr( hrgn
, REGION_MAGIC
))) return FALSE
;
490 if (!obj
->xrgn
) result
= FALSE
;
491 else result
= (XRectInRegion( obj
->xrgn
, rect
->left
, rect
->top
,
492 rect
->right
-rect
->left
,
493 rect
->bottom
-rect
->top
) != RectangleOut
);
494 GDI_HEAP_UNLOCK( hrgn
);
499 /***********************************************************************
500 * RectInRegion32 (GDI32.281)
502 BOOL32 WINAPI
RectInRegion32( HRGN32 hrgn
, const RECT32
*rect
)
507 if (!(obj
= (RGNOBJ
*) GDI_GetObjPtr( hrgn
, REGION_MAGIC
))) return FALSE
;
508 if (!obj
->xrgn
) result
= FALSE
;
509 else result
= (XRectInRegion( obj
->xrgn
, rect
->left
, rect
->top
,
510 rect
->right
-rect
->left
,
511 rect
->bottom
-rect
->top
) != RectangleOut
);
512 GDI_HEAP_UNLOCK( hrgn
);
517 /***********************************************************************
518 * EqualRgn16 (GDI.72)
520 BOOL16 WINAPI
EqualRgn16( HRGN16 rgn1
, HRGN16 rgn2
)
522 return EqualRgn32( rgn1
, rgn2
);
526 /***********************************************************************
527 * EqualRgn32 (GDI32.90)
529 BOOL32 WINAPI
EqualRgn32( HRGN32 rgn1
, HRGN32 rgn2
)
534 if (!(obj1
= (RGNOBJ
*) GDI_GetObjPtr( rgn1
, REGION_MAGIC
))) return FALSE
;
535 if (!(obj2
= (RGNOBJ
*) GDI_GetObjPtr( rgn2
, REGION_MAGIC
)))
537 GDI_HEAP_UNLOCK( rgn1
);
540 if (!obj1
->xrgn
|| !obj2
->xrgn
) result
= (!obj1
->xrgn
&& !obj2
->xrgn
);
541 else result
= XEqualRegion( obj1
->xrgn
, obj2
->xrgn
);
542 GDI_HEAP_UNLOCK( rgn1
);
543 GDI_HEAP_UNLOCK( rgn2
);
548 /***********************************************************************
551 * Copy region src into dest.
553 static INT32
REGION_CopyRegion( RGNOBJ
*src
, RGNOBJ
*dest
)
558 if (src
->xrgn
== dest
->xrgn
) return COMPLEXREGION
;
559 tmprgn
= XCreateRegion();
560 if (!dest
->xrgn
) dest
->xrgn
= XCreateRegion();
561 XUnionRegion( tmprgn
, src
->xrgn
, dest
->xrgn
);
562 XDestroyRegion( tmprgn
);
563 return COMPLEXREGION
;
567 if (dest
->xrgn
) XDestroyRegion( dest
->xrgn
);
573 /***********************************************************************
574 * REGION_UnionRectWithRgn
576 * Add rectangle to region
578 BOOL32
REGION_UnionRectWithRgn( HRGN32 hRgn
, const RECT32
*rc
)
580 RGNOBJ
*rgnObj
= (RGNOBJ
*) GDI_GetObjPtr( hRgn
, REGION_MAGIC
);
581 XRectangle rect
= { rc
->left
, rc
->top
, rc
->right
- rc
->left
, rc
->bottom
- rc
->top
};
588 if (!(rgnObj
->xrgn
= XCreateRegion()))
590 GDI_FreeObject( hRgn
);
597 XUnionRectWithRegion( &rect
, rgnObj
->xrgn
, rgnObj
->xrgn
);
598 GDI_HEAP_UNLOCK( hRgn
);
604 /***********************************************************************
605 * REGION_CreateFrameRgn
607 * Create a region that is a frame around another region
609 BOOL32
REGION_FrameRgn( HRGN32 hDest
, HRGN32 hSrc
, INT32 x
, INT32 y
)
611 RGNOBJ
*destObj
,*srcObj
;
614 destObj
= (RGNOBJ
*) GDI_GetObjPtr( hDest
, REGION_MAGIC
);
615 srcObj
= (RGNOBJ
*) GDI_GetObjPtr( hSrc
, REGION_MAGIC
);
618 GDI_HEAP_UNLOCK( hDest
);
619 GDI_HEAP_UNLOCK( hSrc
);
622 REGION_CopyRegion( srcObj
, destObj
);
623 XShrinkRegion( destObj
->xrgn
, -x
, -y
);
624 result
= XCreateRegion();
625 XSubtractRegion( destObj
->xrgn
, srcObj
->xrgn
, result
);
626 XDestroyRegion( destObj
->xrgn
);
627 destObj
->xrgn
= result
;
628 GDI_HEAP_UNLOCK( hDest
);
629 GDI_HEAP_UNLOCK( hSrc
);
634 /***********************************************************************
635 * CombineRgn16 (GDI.451)
637 INT16 WINAPI
CombineRgn16(HRGN16 hDest
, HRGN16 hSrc1
, HRGN16 hSrc2
, INT16 mode
)
639 return (INT16
)CombineRgn32( hDest
, hSrc1
, hSrc2
, mode
);
643 /***********************************************************************
644 * CombineRgn32 (GDI32.19)
646 * Note: The behavior is correct even if src and dest regions are the same.
648 INT32 WINAPI
CombineRgn32(HRGN32 hDest
, HRGN32 hSrc1
, HRGN32 hSrc2
, INT32 mode
)
650 RGNOBJ
*destObj
, *src1Obj
, *src2Obj
;
654 dprintf_region(stddeb
, "CombineRgn: %04x,%04x -> %04x mode=%x\n",
655 hSrc1
, hSrc2
, hDest
, mode
);
657 if (!(destObj
= (RGNOBJ
*) GDI_GetObjPtr( hDest
, REGION_MAGIC
)))
659 if (!(src1Obj
= (RGNOBJ
*) GDI_GetObjPtr( hSrc1
, REGION_MAGIC
)))
661 GDI_HEAP_UNLOCK( hDest
);
664 if (mode
== RGN_COPY
)
666 result
= REGION_CopyRegion( src1Obj
, destObj
);
667 GDI_HEAP_UNLOCK( hDest
);
668 GDI_HEAP_UNLOCK( hSrc1
);
672 if (!(src2Obj
= (RGNOBJ
*) GDI_GetObjPtr( hSrc2
, REGION_MAGIC
)))
674 GDI_HEAP_UNLOCK( hDest
);
675 GDI_HEAP_UNLOCK( hSrc1
);
678 /* Some optimizations for null regions */
680 if (!src1Obj
->xrgn
|| !src2Obj
->xrgn
)
687 result
= REGION_CopyRegion( src1Obj
, destObj
);
688 GDI_HEAP_UNLOCK( hDest
);
689 GDI_HEAP_UNLOCK( hSrc1
);
690 GDI_HEAP_UNLOCK( hSrc2
);
693 /* else fall through */
695 if (destObj
->xrgn
) XDestroyRegion( destObj
->xrgn
);
697 GDI_HEAP_UNLOCK( hDest
);
698 GDI_HEAP_UNLOCK( hSrc1
);
699 GDI_HEAP_UNLOCK( hSrc2
);
704 result
= REGION_CopyRegion( src1Obj
, destObj
);
706 result
= REGION_CopyRegion( src2Obj
, destObj
);
707 GDI_HEAP_UNLOCK( hDest
);
708 GDI_HEAP_UNLOCK( hSrc1
);
709 GDI_HEAP_UNLOCK( hSrc2
);
712 GDI_HEAP_UNLOCK( hDest
);
713 GDI_HEAP_UNLOCK( hSrc1
);
714 GDI_HEAP_UNLOCK( hSrc2
);
719 /* Perform the operation with the two X regions */
721 if (!(destrgn
= XCreateRegion()))
723 GDI_HEAP_UNLOCK( hDest
);
724 GDI_HEAP_UNLOCK( hSrc1
);
725 GDI_HEAP_UNLOCK( hSrc2
);
731 XIntersectRegion( src1Obj
->xrgn
, src2Obj
->xrgn
, destrgn
);
734 XUnionRegion( src1Obj
->xrgn
, src2Obj
->xrgn
, destrgn
);
737 XXorRegion( src1Obj
->xrgn
, src2Obj
->xrgn
, destrgn
);
740 XSubtractRegion( src1Obj
->xrgn
, src2Obj
->xrgn
, destrgn
);
743 XDestroyRegion( destrgn
);
744 GDI_HEAP_UNLOCK( hDest
);
745 GDI_HEAP_UNLOCK( hSrc1
);
746 GDI_HEAP_UNLOCK( hSrc2
);
749 if (destObj
->xrgn
) XDestroyRegion( destObj
->xrgn
);
750 destObj
->xrgn
= destrgn
;
751 if (XEmptyRegion(destObj
->xrgn
))
753 XDestroyRegion( destObj
->xrgn
);
755 GDI_HEAP_UNLOCK( hDest
);
756 GDI_HEAP_UNLOCK( hSrc1
);
757 GDI_HEAP_UNLOCK( hSrc2
);
760 GDI_HEAP_UNLOCK( hDest
);
761 GDI_HEAP_UNLOCK( hSrc1
);
762 GDI_HEAP_UNLOCK( hSrc2
);
763 return COMPLEXREGION
;