4 * Copyright 1993, 1994 Alexandre Julliard
7 static char Copyright
[] = "Copyright Alexandre Julliard, 1993, 1994";
14 /* #define DEBUG_REGION /* */
15 /* #undef DEBUG_REGION /* */
18 /* GC used for region operations */
19 static GC regionGC
= 0;
21 /***********************************************************************
28 /* CreateGC needs a drawable */
29 tmpPixmap
= XCreatePixmap( display
, rootWindow
, 1, 1, 1 );
32 regionGC
= XCreateGC( display
, tmpPixmap
, 0, NULL
);
33 XFreePixmap( display
, tmpPixmap
);
34 if (!regionGC
) return FALSE
;
35 XSetForeground( display
, regionGC
, 1 );
36 XSetGraphicsExposures( display
, regionGC
, False
);
43 /***********************************************************************
46 * Make a pixmap of an X region.
48 static BOOL
REGION_MakePixmap( REGION
*region
)
50 int width
= region
->box
.right
- region
->box
.left
;
51 int height
= region
->box
.bottom
- region
->box
.top
;
53 if (!region
->xrgn
) return TRUE
; /* Null region */
54 region
->pixmap
= XCreatePixmap( display
, rootWindow
, width
, height
, 1 );
55 if (!region
->pixmap
) return FALSE
;
56 XSetRegion( display
, regionGC
, region
->xrgn
);
57 XSetClipOrigin( display
, regionGC
, -region
->box
.left
, -region
->box
.top
);
58 XSetFunction( display
, regionGC
, GXset
);
59 XFillRectangle( display
, region
->pixmap
, regionGC
, 0, 0, width
, height
);
60 XSetClipMask( display
, regionGC
, None
); /* Clear clip region */
65 /***********************************************************************
68 * Set the bounding box of the region and create the pixmap (or the X rgn).
69 * The hrgn must be valid.
71 static BOOL
REGION_SetRect( HRGN hrgn
, LPRECT rect
, BOOL createXrgn
)
77 REGION
* region
= &((RGNOBJ
*)GDI_HEAP_ADDR( hrgn
))->region
;
78 width
= rect
->right
- rect
->left
;
79 height
= rect
->bottom
- rect
->top
;
80 if ((width
<= 0) || (height
<= 0))
82 region
->type
= NULLREGION
;
84 region
->box
.right
= 0;
86 region
->box
.bottom
= 0;
91 region
->type
= SIMPLEREGION
;
96 if (createXrgn
) /* Create and set the X region */
98 XRectangle xrect
= { region
->box
.left
, region
->box
.top
, width
, height
};
99 if (!(region
->xrgn
= XCreateRegion())) return FALSE
;
100 XUnionRectWithRegion( &xrect
, region
->xrgn
, region
->xrgn
);
102 else /* Create the pixmap */
104 region
->pixmap
= XCreatePixmap( display
, rootWindow
, width
, height
, 1);
105 if (!region
->pixmap
) return FALSE
;
106 /* Fill the pixmap */
107 XSetFunction( display
, regionGC
, GXclear
);
108 XFillRectangle(display
, region
->pixmap
, regionGC
, 0, 0, width
, height
);
114 /***********************************************************************
115 * REGION_DeleteObject
117 BOOL
REGION_DeleteObject( HRGN hrgn
, RGNOBJ
* obj
)
119 if (obj
->region
.pixmap
) XFreePixmap( display
, obj
->region
.pixmap
);
120 if (obj
->region
.xrgn
) XDestroyRegion( obj
->region
.xrgn
);
121 return GDI_FreeObject( hrgn
);
125 /***********************************************************************
126 * OffsetRgn (GDI.101)
128 int OffsetRgn( HRGN hrgn
, short x
, short y
)
130 RGNOBJ
* obj
= (RGNOBJ
*) GDI_GetObjPtr( hrgn
, REGION_MAGIC
);
131 if (!obj
) return ERROR
;
132 dprintf_region(stddeb
, "OffsetRgn: %d %d,%d\n", hrgn
, x
, y
);
133 OffsetRect( &obj
->region
.box
, x
, y
);
134 if (obj
->region
.xrgn
) XOffsetRegion( obj
->region
.xrgn
, x
, y
);
135 return obj
->region
.type
;
139 /***********************************************************************
140 * GetRgnBox (GDI.134)
142 int GetRgnBox( HRGN hrgn
, LPRECT rect
)
144 RGNOBJ
* obj
= (RGNOBJ
*) GDI_GetObjPtr( hrgn
, REGION_MAGIC
);
145 if (!obj
) return ERROR
;
146 dprintf_region(stddeb
, "GetRgnBox: %d\n", hrgn
);
147 *rect
= obj
->region
.box
;
148 return obj
->region
.type
;
152 /***********************************************************************
153 * CreateRectRgn (GDI.64)
155 HRGN
CreateRectRgn( short left
, short top
, short right
, short bottom
)
157 RECT rect
= { left
, top
, right
, bottom
};
158 return CreateRectRgnIndirect( &rect
);
162 /***********************************************************************
163 * CreateRectRgnIndirect (GDI.65)
165 HRGN
CreateRectRgnIndirect( LPRECT rect
)
169 dprintf_region(stddeb
, "CreateRectRgnIndirect: %d,%d-%d,%d\n",
170 rect
->left
, rect
->top
, rect
->right
, rect
->bottom
);
174 if (!(hrgn
= GDI_AllocObject( sizeof(RGNOBJ
), REGION_MAGIC
))) return 0;
175 if (!REGION_SetRect( hrgn
, rect
, TRUE
))
177 GDI_FreeObject( hrgn
);
184 /***********************************************************************
185 * CreateRoundRectRgn (GDI.444)
187 HRGN
CreateRoundRectRgn( short left
, short top
, short right
, short bottom
,
188 short ellipse_width
, short ellipse_height
)
190 RECT rect
= { left
, top
, right
, bottom
};
194 dprintf_region(stddeb
, "CreateRoundRectRgn: %d,%d-%d,%d %dx%d\n",
195 left
, top
, right
, bottom
, ellipse_width
, ellipse_height
);
199 if (!(hrgn
= GDI_AllocObject( sizeof(RGNOBJ
), REGION_MAGIC
))) return 0;
200 if (!REGION_SetRect( hrgn
, &rect
, FALSE
))
202 GDI_FreeObject( hrgn
);
205 rgnObj
= (RGNOBJ
*) GDI_HEAP_ADDR( hrgn
);
209 if (rgnObj
->region
.type
!= NULLREGION
)
211 int width
= rgnObj
->region
.box
.right
- rgnObj
->region
.box
.left
;
212 int height
= rgnObj
->region
.box
.bottom
- rgnObj
->region
.box
.top
;
213 XSetFunction( display
, regionGC
, GXcopy
);
214 XFillRectangle( display
, rgnObj
->region
.pixmap
, regionGC
,
215 0, ellipse_height
/ 2,
216 width
, height
- ellipse_height
);
217 XFillRectangle( display
, rgnObj
->region
.pixmap
, regionGC
,
218 ellipse_width
/ 2, 0,
219 width
- ellipse_width
, height
);
220 XFillArc( display
, rgnObj
->region
.pixmap
, regionGC
,
222 ellipse_width
, ellipse_height
, 0, 360*64 );
223 XFillArc( display
, rgnObj
->region
.pixmap
, regionGC
,
224 width
- ellipse_width
, 0,
225 ellipse_width
, ellipse_height
, 0, 360*64 );
226 XFillArc( display
, rgnObj
->region
.pixmap
, regionGC
,
227 0, height
- ellipse_height
,
228 ellipse_width
, ellipse_height
, 0, 360*64 );
229 XFillArc( display
, rgnObj
->region
.pixmap
, regionGC
,
230 width
- ellipse_width
, height
- ellipse_height
,
231 ellipse_width
, ellipse_height
, 0, 360*64 );
238 /***********************************************************************
239 * SetRectRgn (GDI.172)
241 void SetRectRgn( HRGN hrgn
, short left
, short top
, short right
, short bottom
)
243 RECT rect
= { left
, top
, right
, bottom
};
246 dprintf_region(stddeb
, "SetRectRgn: %d %d,%d-%d,%d\n",
247 hrgn
, left
, top
, right
, bottom
);
249 /* Free previous pixmap */
251 if (!(rgnObj
= (RGNOBJ
*) GDI_GetObjPtr( hrgn
, REGION_MAGIC
))) return;
252 if (rgnObj
->region
.pixmap
) XFreePixmap( display
, rgnObj
->region
.pixmap
);
253 if (rgnObj
->region
.xrgn
) XDestroyRegion( rgnObj
->region
.xrgn
);
254 REGION_SetRect( hrgn
, &rect
, TRUE
);
258 /***********************************************************************
259 * CreateEllipticRgn (GDI.54)
261 HRGN
CreateEllipticRgn( short left
, short top
, short right
, short bottom
)
263 RECT rect
= { left
, top
, right
, bottom
};
264 return CreateEllipticRgnIndirect( &rect
);
268 /***********************************************************************
269 * CreateEllipticRgnIndirect (GDI.55)
271 HRGN
CreateEllipticRgnIndirect( LPRECT rect
)
276 dprintf_region(stddeb
, "CreateEllipticRgnIndirect: %d,%d-%d,%d\n",
277 rect
->left
, rect
->top
, rect
->right
, rect
->bottom
);
281 if (!(hrgn
= GDI_AllocObject( sizeof(RGNOBJ
), REGION_MAGIC
))) return 0;
282 if (!REGION_SetRect( hrgn
, rect
, FALSE
))
284 GDI_FreeObject( hrgn
);
287 rgnObj
= (RGNOBJ
*) GDI_HEAP_ADDR( hrgn
);
291 if (rgnObj
->region
.type
!= NULLREGION
)
293 int width
= rgnObj
->region
.box
.right
- rgnObj
->region
.box
.left
;
294 int height
= rgnObj
->region
.box
.bottom
- rgnObj
->region
.box
.top
;
295 XSetFunction( display
, regionGC
, GXcopy
);
296 XFillArc( display
, rgnObj
->region
.pixmap
, regionGC
,
297 0, 0, width
, height
, 0, 360*64 );
304 /***********************************************************************
305 * CreatePolygonRgn (GDI.63)
307 HRGN
CreatePolygonRgn( POINT
* points
, short count
, short mode
)
309 return CreatePolyPolygonRgn( points
, &count
, 1, mode
);
313 /***********************************************************************
314 * CreatePolyPolygonRgn (GDI.451)
316 HRGN
CreatePolyPolygonRgn( POINT
* points
, short * count
,
317 short nbpolygons
, short mode
)
322 XPoint
*xpoints
, *pt
;
326 dprintf_region(stddeb
, "CreatePolyPolygonRgn: %d polygons\n", nbpolygons
);
328 /* Allocate points array */
330 if (!nbpolygons
) return 0;
331 for (i
= maxPoints
= 0; i
< nbpolygons
; i
++)
332 if (maxPoints
< count
[i
]) maxPoints
= count
[i
];
333 if (!maxPoints
) return 0;
334 if (!(xpoints
= (XPoint
*) malloc( sizeof(XPoint
) * maxPoints
)))
337 /* Allocate region */
339 if (!(hrgn
= GDI_AllocObject( sizeof(RGNOBJ
), REGION_MAGIC
)))
344 rgnObj
= (RGNOBJ
*) GDI_HEAP_ADDR( hrgn
);
345 rgnObj
->region
.type
= SIMPLEREGION
;
346 rgnObj
->region
.pixmap
= 0;
348 /* Create X region */
350 for (i
= 0; i
< nbpolygons
; i
++, count
++)
352 for (j
= *count
, pt
= xpoints
; j
> 0; j
--, points
++, pt
++)
357 xrgn
= XPolygonRegion( xpoints
, *count
,
358 (mode
== WINDING
) ? WindingRule
: EvenOddRule
);
362 Region tmprgn
= XCreateRegion();
363 if (mode
== WINDING
) XUnionRegion(xrgn
,rgnObj
->region
.xrgn
,tmprgn
);
364 else XXorRegion( xrgn
, rgnObj
->region
.xrgn
, tmprgn
);
365 XDestroyRegion( rgnObj
->region
.xrgn
);
366 rgnObj
->region
.xrgn
= tmprgn
;
368 else rgnObj
->region
.xrgn
= xrgn
;
374 GDI_FreeObject( hrgn
);
377 XClipBox( rgnObj
->region
.xrgn
, &rect
);
378 SetRect( &rgnObj
->region
.box
, rect
.x
, rect
.y
,
379 rect
.x
+ rect
.width
, rect
.y
+ rect
.height
);
384 /***********************************************************************
385 * PtInRegion (GDI.161)
387 BOOL
PtInRegion( HRGN hrgn
, short x
, short y
)
393 if (!(obj
= (RGNOBJ
*) GDI_GetObjPtr( hrgn
, REGION_MAGIC
))) return FALSE
;
394 if (!PtInRect( &obj
->region
.box
, pt
)) return FALSE
;
395 if (obj
->region
.xrgn
)
397 return XPointInRegion( obj
->region
.xrgn
, x
, y
);
401 XImage
*image
= XGetImage( display
, obj
->region
.pixmap
,
402 x
- obj
->region
.box
.left
, y
- obj
->region
.box
.top
,
403 1, 1, AllPlanes
, ZPixmap
);
404 if (!image
) return FALSE
;
405 res
= (XGetPixel( image
, 0, 0 ) != 0);
406 XDestroyImage( image
);
412 /***********************************************************************
413 * RectInRegion (GDI.181)
415 BOOL
RectInRegion( HRGN hrgn
, LPRECT rect
)
422 if (!(obj
= (RGNOBJ
*) GDI_GetObjPtr( hrgn
, REGION_MAGIC
))) return FALSE
;
423 if (obj
->region
.xrgn
)
425 return (XRectInRegion( obj
->region
.xrgn
, rect
->left
, rect
->top
,
426 rect
->right
-rect
->left
,
427 rect
->bottom
-rect
->top
) != RectangleOut
);
431 if (!IntersectRect( &intersect
, &obj
->region
.box
, rect
)) return FALSE
;
433 image
= XGetImage( display
, obj
->region
.pixmap
,
434 intersect
.left
- obj
->region
.box
.left
,
435 intersect
.top
- obj
->region
.box
.top
,
436 intersect
.right
- intersect
.left
,
437 intersect
.bottom
- intersect
.top
,
438 AllPlanes
, ZPixmap
);
439 if (!image
) return FALSE
;
440 for (y
= 0; y
< image
->height
; y
++)
441 for (x
= 0; x
< image
->width
; x
++)
442 if (XGetPixel( image
, x
, y
) != 0)
444 XDestroyImage( image
);
448 XDestroyImage( image
);
454 /***********************************************************************
457 BOOL
EqualRgn( HRGN rgn1
, HRGN rgn2
)
460 XImage
*image1
, *image2
;
461 Pixmap pixmap1
, pixmap2
;
462 int width
, height
, x
, y
;
464 /* Compare bounding boxes */
466 if (!(obj1
= (RGNOBJ
*) GDI_GetObjPtr( rgn1
, REGION_MAGIC
))) return FALSE
;
467 if (!(obj2
= (RGNOBJ
*) GDI_GetObjPtr( rgn2
, REGION_MAGIC
))) return FALSE
;
468 if (obj1
->region
.type
== NULLREGION
)
469 return (obj2
->region
.type
== NULLREGION
);
470 else if (obj2
->region
.type
== NULLREGION
) return FALSE
;
471 if (!EqualRect( &obj1
->region
.box
, &obj2
->region
.box
)) return FALSE
;
472 if (obj1
->region
.xrgn
&& obj2
->region
.xrgn
)
474 return XEqualRegion( obj1
->region
.xrgn
, obj2
->region
.xrgn
);
477 /* Get pixmap contents */
479 if (!(pixmap1
= obj1
->region
.pixmap
) &&
480 !REGION_MakePixmap( &obj1
->region
)) return FALSE
;
481 if (!(pixmap2
= obj2
->region
.pixmap
) &&
482 !REGION_MakePixmap( &obj2
->region
)) return FALSE
;
483 width
= obj1
->region
.box
.right
- obj1
->region
.box
.left
;
484 height
= obj1
->region
.box
.bottom
- obj1
->region
.box
.top
;
485 image1
= XGetImage( display
, obj1
->region
.pixmap
,
486 0, 0, width
, height
, AllPlanes
, ZPixmap
);
487 image2
= XGetImage( display
, obj2
->region
.pixmap
,
488 0, 0, width
, height
, AllPlanes
, ZPixmap
);
489 if (!image1
|| !image2
)
491 if (image1
) XDestroyImage( image1
);
492 if (image2
) XDestroyImage( image2
);
496 /* Compare pixmaps */
497 for (y
= 0; y
< height
; y
++)
498 for (x
= 0; x
< width
; x
++)
499 if (XGetPixel( image1
, x
, y
) != XGetPixel( image2
, x
, y
))
501 XDestroyImage( image1
);
502 XDestroyImage( image2
);
506 XDestroyImage( image1
);
507 XDestroyImage( image2
);
512 /***********************************************************************
513 * REGION_CopyIntersection
515 * Copy to dest->pixmap the area of src->pixmap delimited by
516 * the intersection of dest and src regions, using the current GC function.
518 void REGION_CopyIntersection( REGION
* dest
, REGION
* src
)
521 if (!IntersectRect( &inter
, &dest
->box
, &src
->box
)) return;
522 XCopyArea( display
, src
->pixmap
, dest
->pixmap
, regionGC
,
523 inter
.left
- src
->box
.left
, inter
.top
- src
->box
.top
,
524 inter
.right
- inter
.left
, inter
.bottom
- inter
.top
,
525 inter
.left
- dest
->box
.left
, inter
.top
- dest
->box
.top
);
529 /***********************************************************************
532 * Copy region src into dest.
534 static int REGION_CopyRegion( RGNOBJ
*src
, RGNOBJ
*dest
)
536 if (dest
->region
.pixmap
) XFreePixmap( display
, dest
->region
.pixmap
);
537 dest
->region
.type
= src
->region
.type
;
538 dest
->region
.box
= src
->region
.box
;
539 dest
->region
.pixmap
= 0;
540 if (src
->region
.xrgn
) /* Copy only the X region */
542 Region tmprgn
= XCreateRegion();
543 if (!dest
->region
.xrgn
) dest
->region
.xrgn
= XCreateRegion();
544 XUnionRegion( tmprgn
, src
->region
.xrgn
, dest
->region
.xrgn
);
545 XDestroyRegion( tmprgn
);
547 else /* Copy the pixmap (if any) */
549 if (dest
->region
.xrgn
)
551 XDestroyRegion( dest
->region
.xrgn
);
552 dest
->region
.xrgn
= 0;
554 if (src
->region
.pixmap
)
556 int width
= src
->region
.box
.right
- src
->region
.box
.left
;
557 int height
= src
->region
.box
.bottom
- src
->region
.box
.top
;
559 dest
->region
.pixmap
= XCreatePixmap( display
, rootWindow
,
561 XSetFunction( display
, regionGC
, GXcopy
);
562 XCopyArea( display
, src
->region
.pixmap
, dest
->region
.pixmap
,
563 regionGC
, 0, 0, width
, height
, 0, 0 );
566 return dest
->region
.type
;
570 /***********************************************************************
571 * CombineRgn (GDI.451)
573 int CombineRgn( HRGN hDest
, HRGN hSrc1
, HRGN hSrc2
, short mode
)
575 RGNOBJ
*destObj
, *src1Obj
, *src2Obj
;
580 dprintf_region(stddeb
, "CombineRgn: %d %d %d %d\n",
581 hDest
, hSrc1
, hSrc2
, mode
);
583 if (!(destObj
= (RGNOBJ
*) GDI_GetObjPtr( hDest
, REGION_MAGIC
)))
585 if (!(src1Obj
= (RGNOBJ
*) GDI_GetObjPtr( hSrc1
, REGION_MAGIC
)))
587 if (mode
== RGN_COPY
) return REGION_CopyRegion( src1Obj
, destObj
);
589 if (!(src2Obj
= (RGNOBJ
*) GDI_GetObjPtr( hSrc2
, REGION_MAGIC
)))
591 region
= &destObj
->region
;
593 if (src1Obj
->region
.xrgn
&& src2Obj
->region
.xrgn
)
595 /* Perform the operation with X regions */
597 if (region
->pixmap
) XFreePixmap( display
, region
->pixmap
);
599 if (!region
->xrgn
) region
->xrgn
= XCreateRegion();
603 XIntersectRegion( src1Obj
->region
.xrgn
, src2Obj
->region
.xrgn
,
607 XUnionRegion( src1Obj
->region
.xrgn
, src2Obj
->region
.xrgn
,
611 XXorRegion( src1Obj
->region
.xrgn
, src2Obj
->region
.xrgn
,
615 XSubtractRegion( src1Obj
->region
.xrgn
, src2Obj
->region
.xrgn
,
621 if (XEmptyRegion(region
->xrgn
))
623 XDestroyRegion( region
->xrgn
);
624 region
->type
= NULLREGION
;
631 XClipBox( region
->xrgn
, &rect
);
632 region
->type
= COMPLEXREGION
;
633 region
->box
.left
= rect
.x
;
634 region
->box
.top
= rect
.y
;
635 region
->box
.right
= rect
.x
+ rect
.width
;
636 region
->box
.bottom
= rect
.y
+ rect
.height
;
637 return COMPLEXREGION
;
640 else /* Create pixmaps if needed */
642 if (!src1Obj
->region
.pixmap
)
643 if (!REGION_MakePixmap( &src1Obj
->region
)) return ERROR
;
644 if (!src2Obj
->region
.pixmap
)
645 if (!REGION_MakePixmap( &src2Obj
->region
)) return ERROR
;
652 res
= IntersectRect( ®ion
->box
, &src1Obj
->region
.box
,
653 &src2Obj
->region
.box
);
654 region
->type
= COMPLEXREGION
;
659 res
= UnionRect( ®ion
->box
, &src1Obj
->region
.box
,
660 &src2Obj
->region
.box
);
661 region
->type
= COMPLEXREGION
;
665 res
= SubtractRect( ®ion
->box
, &src1Obj
->region
.box
,
666 &src2Obj
->region
.box
);
667 region
->type
= COMPLEXREGION
;
674 if (region
->pixmap
) XFreePixmap( display
, region
->pixmap
);
675 if (region
->xrgn
) XDestroyRegion( region
->xrgn
);
678 region
->type
= NULLREGION
;
684 width
= region
->box
.right
- region
->box
.left
;
685 height
= region
->box
.bottom
- region
->box
.top
;
686 if (!width
|| !height
)
688 fprintf(stderr
, "CombineRgn: width or height is 0. Please report this.\n" );
689 fprintf(stderr
, "src1=%d,%d-%d,%d src2=%d,%d-%d,%d dst=%d,%d-%d,%d op=%d\n",
690 src1Obj
->region
.box
.left
, src1Obj
->region
.box
.top
,
691 src1Obj
->region
.box
.right
, src1Obj
->region
.box
.bottom
,
692 src2Obj
->region
.box
.left
, src2Obj
->region
.box
.top
,
693 src2Obj
->region
.box
.right
, src2Obj
->region
.box
.bottom
,
694 region
->box
.left
, region
->box
.top
,
695 region
->box
.right
, region
->box
.bottom
, mode
);
698 region
->pixmap
= XCreatePixmap( display
, rootWindow
, width
, height
, 1 );
704 XSetFunction( display
, regionGC
, GXcopy
);
705 REGION_CopyIntersection( region
, &src1Obj
->region
);
706 XSetFunction( display
, regionGC
, GXand
);
707 REGION_CopyIntersection( region
, &src2Obj
->region
);
712 XSetFunction( display
, regionGC
, GXclear
);
713 XFillRectangle( display
, region
->pixmap
, regionGC
,
714 0, 0, width
, height
);
715 XSetFunction( display
, regionGC
, (mode
== RGN_OR
) ? GXor
: GXxor
);
716 REGION_CopyIntersection( region
, &src1Obj
->region
);
717 REGION_CopyIntersection( region
, &src2Obj
->region
);
721 XSetFunction( display
, regionGC
, GXclear
);
722 XFillRectangle( display
, region
->pixmap
, regionGC
,
723 0, 0, width
, height
);
724 XSetFunction( display
, regionGC
, GXcopy
);
725 REGION_CopyIntersection( region
, &src1Obj
->region
);
726 XSetFunction( display
, regionGC
, GXandInverted
);
727 REGION_CopyIntersection( region
, &src2Obj
->region
);