4 * Copyright 1993, 1994, 1995 Alexandre Julliard
14 /***********************************************************************
17 BOOL32
REGION_DeleteObject( HRGN32 hrgn
, RGNOBJ
* obj
)
19 dprintf_region(stddeb
, "DeleteRegion: %04x\n", hrgn
);
20 if (obj
->xrgn
) XDestroyRegion( obj
->xrgn
);
21 return GDI_FreeObject( hrgn
);
25 /***********************************************************************
26 * OffsetRgn16 (GDI.101)
28 INT16
OffsetRgn16( HRGN16 hrgn
, INT16 x
, INT16 y
)
30 return OffsetRgn32( hrgn
, x
, y
);
34 /***********************************************************************
35 * OffsetRgn32 (GDI32.256)
37 INT32
OffsetRgn32( HRGN32 hrgn
, INT32 x
, INT32 y
)
39 RGNOBJ
* obj
= (RGNOBJ
*) GDI_GetObjPtr( hrgn
, REGION_MAGIC
);
40 if (!obj
) return ERROR
;
41 dprintf_region(stddeb
, "OffsetRgn: %04x %d,%d\n", hrgn
, x
, y
);
42 if (!obj
->xrgn
) return NULLREGION
;
43 XOffsetRegion( obj
->xrgn
, x
, y
);
48 /***********************************************************************
49 * GetRgnBox16 (GDI.134)
51 INT16
GetRgnBox16( HRGN16 hrgn
, LPRECT16 rect
)
53 RGNOBJ
* obj
= (RGNOBJ
*) GDI_GetObjPtr( hrgn
, REGION_MAGIC
);
54 if (!obj
) return ERROR
;
55 dprintf_region(stddeb
, "GetRgnBox: %04x\n", hrgn
);
58 SetRectEmpty16( rect
);
64 XClipBox( obj
->xrgn
, &xrect
);
65 SetRect16( rect
, xrect
.x
, xrect
.y
,
66 xrect
.x
+ xrect
.width
, xrect
.y
+ xrect
.height
);
72 /***********************************************************************
73 * GetRgnBox32 (GDI32.219)
75 INT32
GetRgnBox32( HRGN32 hrgn
, LPRECT32 rect
)
78 INT16 ret
= GetRgnBox16( hrgn
, &r
);
79 CONV_RECT16TO32( &r
, rect
);
84 /***********************************************************************
85 * CreateRectRgn16 (GDI.64)
87 HRGN16
CreateRectRgn16( INT16 left
, INT16 top
, INT16 right
, INT16 bottom
)
89 return (HRGN16
)CreateRectRgn32( left
, top
, right
, bottom
);
93 /***********************************************************************
94 * CreateRectRgn32 (GDI32.59)
96 HRGN32
CreateRectRgn32( INT32 left
, INT32 top
, INT32 right
, INT32 bottom
)
101 if (!(hrgn
= GDI_AllocObject( sizeof(RGNOBJ
), REGION_MAGIC
))) return 0;
102 obj
= (RGNOBJ
*) GDI_HEAP_LIN_ADDR( hrgn
);
103 if ((right
> left
) && (bottom
> top
))
105 XRectangle rect
= { left
, top
, right
- left
, bottom
- top
};
106 if (!(obj
->xrgn
= XCreateRegion()))
108 GDI_FreeObject( hrgn
);
111 XUnionRectWithRegion( &rect
, obj
->xrgn
, obj
->xrgn
);
114 dprintf_region( stddeb
, "CreateRectRgn(%d,%d-%d,%d): returning %04x\n",
115 left
, top
, right
, bottom
, hrgn
);
120 /***********************************************************************
121 * CreateRectRgnIndirect16 (GDI.65)
123 HRGN16
CreateRectRgnIndirect16( const RECT16
* rect
)
125 return CreateRectRgn32( rect
->left
, rect
->top
, rect
->right
, rect
->bottom
);
129 /***********************************************************************
130 * CreateRectRgnIndirect32 (GDI32.60)
132 HRGN32
CreateRectRgnIndirect32( const RECT32
* rect
)
134 return CreateRectRgn32( rect
->left
, rect
->top
, rect
->right
, rect
->bottom
);
138 /***********************************************************************
139 * SetRectRgn16 (GDI.172)
141 VOID
SetRectRgn16( HRGN16 hrgn
, INT16 left
, INT16 top
,
142 INT16 right
, INT16 bottom
)
144 SetRectRgn32( hrgn
, left
, top
, right
, bottom
);
148 /***********************************************************************
149 * SetRectRgn32 (GDI32.332)
151 VOID
SetRectRgn32( HRGN32 hrgn
, INT32 left
, INT32 top
,
152 INT32 right
, INT32 bottom
)
156 dprintf_region(stddeb
, "SetRectRgn: %04x %d,%d-%d,%d\n",
157 hrgn
, left
, top
, right
, bottom
);
159 if (!(obj
= (RGNOBJ
*) GDI_GetObjPtr( hrgn
, REGION_MAGIC
))) return;
160 if (obj
->xrgn
) XDestroyRegion( obj
->xrgn
);
161 if ((right
> left
) && (bottom
> top
))
163 XRectangle rect
= { left
, top
, right
- left
, bottom
- top
};
164 if ((obj
->xrgn
= XCreateRegion()) != 0)
165 XUnionRectWithRegion( &rect
, obj
->xrgn
, obj
->xrgn
);
171 /***********************************************************************
172 * CreateRoundRectRgn16 (GDI.444)
174 HRGN16
CreateRoundRectRgn16( INT16 left
, INT16 top
, INT16 right
, INT16 bottom
,
175 INT16 ellipse_width
, INT16 ellipse_height
)
177 return (HRGN16
)CreateRoundRectRgn32( left
, top
, right
, bottom
,
178 ellipse_width
, ellipse_height
);
182 /***********************************************************************
183 * CreateRoundRectRgn32 (GDI32.61)
185 HRGN32
CreateRoundRectRgn32( INT32 left
, INT32 top
, INT32 right
, INT32 bottom
,
186 INT32 ellipse_width
, INT32 ellipse_height
)
191 int asq
, bsq
, d
, xd
, yd
;
193 /* Check if we can do a normal rectangle instead */
195 if ((right
<= left
) || (bottom
<= top
) ||
196 (ellipse_width
<= 0) || (ellipse_height
<= 0))
197 return CreateRectRgn32( left
, top
, right
, bottom
);
201 if (!(hrgn
= GDI_AllocObject( sizeof(RGNOBJ
), REGION_MAGIC
))) return 0;
202 obj
= (RGNOBJ
*) GDI_HEAP_LIN_ADDR( hrgn
);
203 obj
->xrgn
= XCreateRegion();
204 dprintf_region(stddeb
,"CreateRoundRectRgn(%d,%d-%d,%d %dx%d): return=%04x\n",
205 left
, top
, right
, bottom
, ellipse_width
, ellipse_height
, hrgn
);
207 /* Check parameters */
209 if (ellipse_width
> right
-left
) ellipse_width
= right
-left
;
210 if (ellipse_height
> bottom
-top
) ellipse_height
= bottom
-top
;
212 /* Ellipse algorithm, based on an article by K. Porter */
213 /* in DDJ Graphics Programming Column, 8/89 */
215 asq
= ellipse_width
* ellipse_width
/ 4; /* a^2 */
216 bsq
= ellipse_height
* ellipse_height
/ 4; /* b^2 */
217 d
= bsq
- asq
* ellipse_height
/ 2 + asq
/ 4; /* b^2 - a^2b + a^2/4 */
219 yd
= asq
* ellipse_height
; /* 2a^2b */
221 rect
.x
= left
+ ellipse_width
/ 2;
222 rect
.width
= right
- left
- ellipse_width
;
225 /* Loop to draw first half of quadrant */
229 if (d
> 0) /* if nearest pixel is toward the center */
231 /* move toward center */
233 XUnionRectWithRegion( &rect
, obj
->xrgn
, obj
->xrgn
);
235 XUnionRectWithRegion( &rect
, obj
->xrgn
, obj
->xrgn
);
239 rect
.x
--; /* next horiz point */
245 /* Loop to draw second half of quadrant */
247 d
+= (3 * (asq
-bsq
) / 2 - (xd
+yd
)) / 2;
250 /* next vertical point */
252 XUnionRectWithRegion( &rect
, obj
->xrgn
, obj
->xrgn
);
254 XUnionRectWithRegion( &rect
, obj
->xrgn
, obj
->xrgn
);
255 if (d
< 0) /* if nearest pixel is outside ellipse */
257 rect
.x
--; /* move away from center */
266 /* Add the inside rectangle */
271 rect
.height
= bottom
- top
+ 1;
272 XUnionRectWithRegion( &rect
, obj
->xrgn
, obj
->xrgn
);
278 /***********************************************************************
279 * CreateEllipticRgn16 (GDI.54)
281 HRGN16
CreateEllipticRgn16( INT16 left
, INT16 top
, INT16 right
, INT16 bottom
)
283 return (HRGN16
)CreateRoundRectRgn32( left
, top
, right
, bottom
,
284 right
-left
, bottom
-top
);
288 /***********************************************************************
289 * CreateEllipticRgn32 (GDI32.39)
291 HRGN32
CreateEllipticRgn32( INT32 left
, INT32 top
, INT32 right
, INT32 bottom
)
293 return CreateRoundRectRgn32( left
, top
, right
, bottom
,
294 right
-left
, bottom
-top
);
298 /***********************************************************************
299 * CreateEllipticRgnIndirect16 (GDI.55)
301 HRGN16
CreateEllipticRgnIndirect16( const RECT16
*rect
)
303 return CreateRoundRectRgn32( rect
->left
, rect
->top
, rect
->right
,
304 rect
->bottom
, rect
->right
- rect
->left
,
305 rect
->bottom
- rect
->top
);
309 /***********************************************************************
310 * CreateEllipticRgnIndirect32 (GDI32.40)
312 HRGN32
CreateEllipticRgnIndirect32( const RECT32
*rect
)
314 return CreateRoundRectRgn32( rect
->left
, rect
->top
, rect
->right
,
315 rect
->bottom
, rect
->right
- rect
->left
,
316 rect
->bottom
- rect
->top
);
320 /***********************************************************************
321 * CreatePolygonRgn16 (GDI.63)
323 HRGN16
CreatePolygonRgn16( const POINT16
* points
, INT16 count
, INT16 mode
)
325 return CreatePolyPolygonRgn16( points
, &count
, 1, mode
);
329 /***********************************************************************
330 * CreatePolyPolygonRgn16 (GDI.451)
332 HRGN16
CreatePolyPolygonRgn16( const POINT16
* points
, const INT16
* count
,
333 INT16 nbpolygons
, INT16 mode
)
341 for (i
=nbpolygons
;i
--;)
343 points32
= (LPPOINT32
)HeapAlloc( GetProcessHeap(), 0,
344 nrofpts
*sizeof(POINT32
) );
346 CONV_POINT16TO32( &(points
[i
]), &(points32
[i
]) );
347 count32
= (LPINT32
)HeapAlloc( GetProcessHeap(), 0,
348 sizeof(INT32
)*nbpolygons
);
349 for (i
=nbpolygons
;i
--;)
351 ret
= CreatePolyPolygonRgn32(points32
,count32
,nbpolygons
,mode
);
352 HeapFree( GetProcessHeap(), 0, count32
);
353 HeapFree( GetProcessHeap(), 0, points32
);
358 /***********************************************************************
359 * CreatePolygonRgn32 (GDI32.58)
361 HRGN32
CreatePolygonRgn32( const POINT32
*points
, INT32 count
, INT32 mode
)
363 return CreatePolyPolygonRgn32( points
, &count
, 1, mode
);
367 /***********************************************************************
368 * CreatePolyPolygonRgn32 (GDI32.57)
370 HRGN32
CreatePolyPolygonRgn32( const POINT32
* points
, const INT32
* count
,
371 INT32 nbpolygons
, INT32 mode
)
376 XPoint
*xpoints
, *pt
;
379 /* Allocate points array */
381 if (!nbpolygons
) return 0;
382 for (i
= maxPoints
= 0; i
< nbpolygons
; i
++)
383 if (maxPoints
< count
[i
]) maxPoints
= count
[i
];
384 if (!maxPoints
) return 0;
385 if (!(xpoints
= (XPoint
*)HeapAlloc( GetProcessHeap(), 0,
386 sizeof(XPoint
) * maxPoints
)))
389 /* Allocate region */
391 if (!(hrgn
= GDI_AllocObject( sizeof(RGNOBJ
), REGION_MAGIC
)))
393 HeapFree( GetProcessHeap(), 0, xpoints
);
396 obj
= (RGNOBJ
*) GDI_HEAP_LIN_ADDR( hrgn
);
398 dprintf_region(stddeb
, "CreatePolyPolygonRgn: %d polygons, returning %04x\n",
401 /* Create X region */
403 for (i
= 0; i
< nbpolygons
; i
++, count
++)
405 for (j
= *count
, pt
= xpoints
; j
> 0; j
--, points
++, pt
++)
410 xrgn
= XPolygonRegion( xpoints
, *count
,
411 (mode
== WINDING
) ? WindingRule
: EvenOddRule
);
414 if (obj
->xrgn
) XDestroyRegion( obj
->xrgn
);
415 HeapFree( GetProcessHeap(), 0, xpoints
);
416 GDI_FreeObject( hrgn
);
421 Region tmprgn
= XCreateRegion();
422 if (mode
== WINDING
) XUnionRegion( xrgn
, obj
->xrgn
, tmprgn
);
423 else XXorRegion( xrgn
, obj
->xrgn
, tmprgn
);
424 XDestroyRegion( obj
->xrgn
);
427 else obj
->xrgn
= xrgn
;
430 HeapFree( GetProcessHeap(), 0, xpoints
);
435 /***********************************************************************
436 * PtInRegion16 (GDI.161)
438 BOOL16
PtInRegion16( HRGN16 hrgn
, INT16 x
, INT16 y
)
440 return PtInRegion32( hrgn
, x
, y
);
444 /***********************************************************************
445 * PtInRegion32 (GDI32.278)
447 BOOL32
PtInRegion32( HRGN32 hrgn
, INT32 x
, INT32 y
)
451 if (!(obj
= (RGNOBJ
*) GDI_GetObjPtr( hrgn
, REGION_MAGIC
))) return FALSE
;
452 if (!obj
->xrgn
) return FALSE
;
453 return XPointInRegion( obj
->xrgn
, x
, y
);
457 /***********************************************************************
458 * RectInRegion16 (GDI.181)
460 BOOL16
RectInRegion16( HRGN16 hrgn
, const RECT16
*rect
)
464 if (!(obj
= (RGNOBJ
*) GDI_GetObjPtr( hrgn
, REGION_MAGIC
))) return FALSE
;
465 if (!obj
->xrgn
) return FALSE
;
466 return (XRectInRegion( obj
->xrgn
, rect
->left
, rect
->top
,
467 rect
->right
-rect
->left
,
468 rect
->bottom
-rect
->top
) != RectangleOut
);
472 /***********************************************************************
473 * RectInRegion32 (GDI32.281)
475 BOOL32
RectInRegion32( HRGN32 hrgn
, const RECT32
*rect
)
479 if (!(obj
= (RGNOBJ
*) GDI_GetObjPtr( hrgn
, REGION_MAGIC
))) return FALSE
;
480 if (!obj
->xrgn
) return FALSE
;
481 return (XRectInRegion( obj
->xrgn
, rect
->left
, rect
->top
,
482 rect
->right
-rect
->left
,
483 rect
->bottom
-rect
->top
) != RectangleOut
);
487 /***********************************************************************
488 * EqualRgn16 (GDI.72)
490 BOOL16
EqualRgn16( HRGN16 rgn1
, HRGN16 rgn2
)
492 return EqualRgn32( rgn1
, rgn2
);
496 /***********************************************************************
497 * EqualRgn32 (GDI32.90)
499 BOOL32
EqualRgn32( HRGN32 rgn1
, HRGN32 rgn2
)
502 if (!(obj1
= (RGNOBJ
*) GDI_GetObjPtr( rgn1
, REGION_MAGIC
))) return FALSE
;
503 if (!(obj2
= (RGNOBJ
*) GDI_GetObjPtr( rgn2
, REGION_MAGIC
))) return FALSE
;
504 if (!obj1
->xrgn
|| !obj2
->xrgn
) return (!obj1
->xrgn
&& !obj2
->xrgn
);
505 return XEqualRegion( obj1
->xrgn
, obj2
->xrgn
);
509 /***********************************************************************
512 * Copy region src into dest.
514 static INT32
REGION_CopyRegion( RGNOBJ
*src
, RGNOBJ
*dest
)
519 if (src
->xrgn
== dest
->xrgn
) return COMPLEXREGION
;
520 tmprgn
= XCreateRegion();
521 if (!dest
->xrgn
) dest
->xrgn
= XCreateRegion();
522 XUnionRegion( tmprgn
, src
->xrgn
, dest
->xrgn
);
523 XDestroyRegion( tmprgn
);
524 return COMPLEXREGION
;
528 if (dest
->xrgn
) XDestroyRegion( dest
->xrgn
);
534 /***********************************************************************
535 * REGION_UnionRectWithRgn
537 * Add rectangle to region
539 BOOL32
REGION_UnionRectWithRgn( HRGN32 hRgn
, const RECT32
*rc
)
541 RGNOBJ
*rgnObj
= (RGNOBJ
*) GDI_GetObjPtr( hRgn
, REGION_MAGIC
);
542 XRectangle rect
= { rc
->left
, rc
->top
, rc
->right
- rc
->left
, rc
->bottom
- rc
->top
};
549 if (!(rgnObj
->xrgn
= XCreateRegion()))
551 GDI_FreeObject( hRgn
);
558 XUnionRectWithRegion( &rect
, rgnObj
->xrgn
, rgnObj
->xrgn
);
564 /***********************************************************************
565 * REGION_CreateFrameRgn
567 * Create a region that is a frame around another region
569 BOOL32
REGION_FrameRgn( HRGN32 hDest
, HRGN32 hSrc
, INT32 x
, INT32 y
)
571 RGNOBJ
*destObj
,*srcObj
;
574 destObj
= (RGNOBJ
*) GDI_GetObjPtr( hDest
, REGION_MAGIC
);
575 srcObj
= (RGNOBJ
*) GDI_GetObjPtr( hSrc
, REGION_MAGIC
);
576 if (!srcObj
->xrgn
) return FALSE
;
577 REGION_CopyRegion( srcObj
, destObj
);
578 XShrinkRegion( destObj
->xrgn
, -x
, -y
);
579 result
= XCreateRegion();
580 XSubtractRegion( destObj
->xrgn
, srcObj
->xrgn
, result
);
581 XDestroyRegion( destObj
->xrgn
);
582 destObj
->xrgn
= result
;
587 /***********************************************************************
588 * CombineRgn16 (GDI.451)
590 INT16
CombineRgn16( HRGN16 hDest
, HRGN16 hSrc1
, HRGN16 hSrc2
, INT16 mode
)
592 return (INT16
)CombineRgn32( hDest
, hSrc1
, hSrc2
, mode
);
596 /***********************************************************************
597 * CombineRgn32 (GDI32.19)
599 * Note: The behavior is correct even if src and dest regions are the same.
601 INT32
CombineRgn32( HRGN32 hDest
, HRGN32 hSrc1
, HRGN32 hSrc2
, INT32 mode
)
603 RGNOBJ
*destObj
, *src1Obj
, *src2Obj
;
606 dprintf_region(stddeb
, "CombineRgn: %04x,%04x -> %04x mode=%x\n",
607 hSrc1
, hSrc2
, hDest
, mode
);
609 if (!(destObj
= (RGNOBJ
*) GDI_GetObjPtr( hDest
, REGION_MAGIC
)))
611 if (!(src1Obj
= (RGNOBJ
*) GDI_GetObjPtr( hSrc1
, REGION_MAGIC
)))
613 if (mode
== RGN_COPY
) return REGION_CopyRegion( src1Obj
, destObj
);
615 if (!(src2Obj
= (RGNOBJ
*) GDI_GetObjPtr( hSrc2
, REGION_MAGIC
)))
618 /* Some optimizations for null regions */
620 if (!src1Obj
->xrgn
|| !src2Obj
->xrgn
)
626 return REGION_CopyRegion( src1Obj
, destObj
);
627 /* else fall through */
629 if (destObj
->xrgn
) XDestroyRegion( destObj
->xrgn
);
635 return REGION_CopyRegion( src1Obj
, destObj
);
637 return REGION_CopyRegion( src2Obj
, destObj
);
643 /* Perform the operation with the two X regions */
645 if (!(destrgn
= XCreateRegion())) return ERROR
;
649 XIntersectRegion( src1Obj
->xrgn
, src2Obj
->xrgn
, destrgn
);
652 XUnionRegion( src1Obj
->xrgn
, src2Obj
->xrgn
, destrgn
);
655 XXorRegion( src1Obj
->xrgn
, src2Obj
->xrgn
, destrgn
);
658 XSubtractRegion( src1Obj
->xrgn
, src2Obj
->xrgn
, destrgn
);
661 XDestroyRegion( destrgn
);
664 if (destObj
->xrgn
) XDestroyRegion( destObj
->xrgn
);
665 destObj
->xrgn
= destrgn
;
666 if (XEmptyRegion(destObj
->xrgn
))
668 XDestroyRegion( destObj
->xrgn
);
672 return COMPLEXREGION
;