4 * Copyright 1993, 1994 Alexandre Julliard
7 static char Copyright
[] = "Copyright Alexandre Julliard, 1993, 1994";
14 /* GC used for region operations */
15 static GC regionGC
= 0;
17 /***********************************************************************
24 /* CreateGC needs a drawable */
25 tmpPixmap
= XCreatePixmap( display
, rootWindow
, 1, 1, 1 );
28 regionGC
= XCreateGC( display
, tmpPixmap
, 0, NULL
);
29 XFreePixmap( display
, tmpPixmap
);
30 if (!regionGC
) return FALSE
;
31 XSetForeground( display
, regionGC
, 1 );
32 XSetGraphicsExposures( display
, regionGC
, False
);
39 /***********************************************************************
42 * Make a pixmap of an X region.
44 static BOOL
REGION_MakePixmap( REGION
*region
)
46 int width
= region
->box
.right
- region
->box
.left
;
47 int height
= region
->box
.bottom
- region
->box
.top
;
49 if (!region
->xrgn
) return TRUE
; /* Null region */
50 region
->pixmap
= XCreatePixmap( display
, rootWindow
, width
, height
, 1 );
51 if (!region
->pixmap
) return FALSE
;
52 XSetRegion( display
, regionGC
, region
->xrgn
);
53 XSetClipOrigin( display
, regionGC
, region
->box
.left
, region
->box
.top
);
54 XSetFunction( display
, regionGC
, GXcopy
);
55 XFillRectangle( display
, region
->pixmap
, regionGC
, 0, 0, width
, height
);
56 XSetClipMask( display
, regionGC
, None
); /* Clear clip region */
61 /***********************************************************************
64 * Set the bounding box of the region and create the pixmap (or the X rgn).
65 * The hrgn must be valid.
67 static BOOL
REGION_SetRect( HRGN hrgn
, LPRECT rect
, BOOL createXrgn
)
73 REGION
* region
= &((RGNOBJ
*)GDI_HEAP_ADDR( hrgn
))->region
;
74 width
= rect
->right
- rect
->left
;
75 height
= rect
->bottom
- rect
->top
;
76 if ((width
<= 0) || (height
<= 0))
78 region
->type
= NULLREGION
;
80 region
->box
.right
= 0;
82 region
->box
.bottom
= 0;
87 region
->type
= SIMPLEREGION
;
92 if (createXrgn
) /* Create and set the X region */
95 XRectangle xrect
= { region
->box
.left
, region
->box
.top
, width
, height
};
97 if (!(tmprgn
= XCreateRegion())) return FALSE
;
98 if ((region
->xrgn
= XCreateRegion()))
99 XUnionRectWithRegion( &xrect
, tmprgn
, region
->xrgn
);
100 XDestroyRegion( tmprgn
);
101 if (!region
->xrgn
) return FALSE
;
103 else /* Create the pixmap */
105 region
->pixmap
= XCreatePixmap( display
, rootWindow
, width
, height
, 1);
106 if (!region
->pixmap
) return FALSE
;
107 /* Fill the pixmap */
108 XSetFunction( display
, regionGC
, GXclear
);
109 XFillRectangle(display
, region
->pixmap
, regionGC
, 0, 0, width
, height
);
115 /***********************************************************************
116 * REGION_DeleteObject
118 BOOL
REGION_DeleteObject( HRGN hrgn
, RGNOBJ
* obj
)
120 if (obj
->region
.pixmap
) XFreePixmap( display
, obj
->region
.pixmap
);
121 if (obj
->region
.xrgn
) XDestroyRegion( obj
->region
.xrgn
);
122 return GDI_FreeObject( hrgn
);
126 /***********************************************************************
127 * OffsetRgn (GDI.101)
129 int OffsetRgn( HRGN hrgn
, short x
, short y
)
131 RGNOBJ
* obj
= (RGNOBJ
*) GDI_GetObjPtr( hrgn
, REGION_MAGIC
);
132 if (!obj
) return ERROR
;
134 printf( "OffsetRgn: %d %d,%d\n", hrgn
, x
, y
);
136 OffsetRect( &obj
->region
.box
, x
, y
);
137 if (obj
->region
.xrgn
) XOffsetRegion( obj
->region
.xrgn
, x
, y
);
138 return obj
->region
.type
;
142 /***********************************************************************
143 * GetRgnBox (GDI.134)
145 int GetRgnBox( HRGN hrgn
, LPRECT rect
)
147 RGNOBJ
* obj
= (RGNOBJ
*) GDI_GetObjPtr( hrgn
, REGION_MAGIC
);
148 if (!obj
) return ERROR
;
150 printf( "GetRgnBox: %d\n", hrgn
);
152 *rect
= obj
->region
.box
;
153 return obj
->region
.type
;
157 /***********************************************************************
158 * CreateRectRgn (GDI.64)
160 HRGN
CreateRectRgn( short left
, short top
, short right
, short bottom
)
162 RECT rect
= { left
, top
, right
, bottom
};
163 return CreateRectRgnIndirect( &rect
);
167 /***********************************************************************
168 * CreateRectRgnIndirect (GDI.65)
170 HRGN
CreateRectRgnIndirect( LPRECT rect
)
175 printf( "CreateRectRgnIndirect: %d,%d-%d,%d\n",
176 rect
->left
, rect
->top
, rect
->right
, rect
->bottom
);
181 if (!(hrgn
= GDI_AllocObject( sizeof(RGNOBJ
), REGION_MAGIC
))) return 0;
182 if (!REGION_SetRect( hrgn
, rect
, TRUE
))
184 GDI_FreeObject( hrgn
);
191 /***********************************************************************
192 * CreateRoundRectRgn (GDI.444)
194 HRGN
CreateRoundRectRgn( short left
, short top
, short right
, short bottom
,
195 short ellipse_width
, short ellipse_height
)
197 RECT rect
= { left
, top
, right
, bottom
};
202 printf( "CreateRoundRectRgn: %d,%d-%d,%d %dx%d\n",
203 left
, top
, right
, bottom
, ellipse_width
, ellipse_height
);
208 if (!(hrgn
= GDI_AllocObject( sizeof(RGNOBJ
), REGION_MAGIC
))) return 0;
209 if (!REGION_SetRect( hrgn
, &rect
, FALSE
))
211 GDI_FreeObject( hrgn
);
214 rgnObj
= (RGNOBJ
*) GDI_HEAP_ADDR( hrgn
);
218 if (rgnObj
->region
.type
!= NULLREGION
)
220 int width
= rgnObj
->region
.box
.right
- rgnObj
->region
.box
.left
;
221 int height
= rgnObj
->region
.box
.bottom
- rgnObj
->region
.box
.top
;
222 XSetFunction( display
, regionGC
, GXcopy
);
223 XFillRectangle( display
, rgnObj
->region
.pixmap
, regionGC
,
224 0, ellipse_height
/ 2,
225 width
, height
- ellipse_height
);
226 XFillRectangle( display
, rgnObj
->region
.pixmap
, regionGC
,
227 ellipse_width
/ 2, 0,
228 width
- ellipse_width
, height
);
229 XFillArc( display
, rgnObj
->region
.pixmap
, regionGC
,
231 ellipse_width
, ellipse_height
, 0, 360*64 );
232 XFillArc( display
, rgnObj
->region
.pixmap
, regionGC
,
233 width
- ellipse_width
, 0,
234 ellipse_width
, ellipse_height
, 0, 360*64 );
235 XFillArc( display
, rgnObj
->region
.pixmap
, regionGC
,
236 0, height
- ellipse_height
,
237 ellipse_width
, ellipse_height
, 0, 360*64 );
238 XFillArc( display
, rgnObj
->region
.pixmap
, regionGC
,
239 width
- ellipse_width
, height
- ellipse_height
,
240 ellipse_width
, ellipse_height
, 0, 360*64 );
247 /***********************************************************************
248 * SetRectRgn (GDI.172)
250 void SetRectRgn( HRGN hrgn
, short left
, short top
, short right
, short bottom
)
252 RECT rect
= { left
, top
, right
, bottom
};
256 printf( "SetRectRgn: %d %d,%d-%d,%d\n", hrgn
, left
, top
, right
, bottom
);
259 /* Free previous pixmap */
261 if (!(rgnObj
= (RGNOBJ
*) GDI_GetObjPtr( hrgn
, REGION_MAGIC
))) return;
262 if (rgnObj
->region
.pixmap
) XFreePixmap( display
, rgnObj
->region
.pixmap
);
263 if (rgnObj
->region
.xrgn
) XDestroyRegion( rgnObj
->region
.xrgn
);
264 REGION_SetRect( hrgn
, &rect
, TRUE
);
268 /***********************************************************************
269 * CreateEllipticRgn (GDI.54)
271 HRGN
CreateEllipticRgn( short left
, short top
, short right
, short bottom
)
273 RECT rect
= { left
, top
, right
, bottom
};
274 return CreateEllipticRgnIndirect( &rect
);
278 /***********************************************************************
279 * CreateEllipticRgnIndirect (GDI.55)
281 HRGN
CreateEllipticRgnIndirect( LPRECT rect
)
287 printf( "CreateEllipticRgnIndirect: %d,%d-%d,%d\n",
288 rect
->left
, rect
->top
, rect
->right
, rect
->bottom
);
293 if (!(hrgn
= GDI_AllocObject( sizeof(RGNOBJ
), REGION_MAGIC
))) return 0;
294 if (!REGION_SetRect( hrgn
, rect
, FALSE
))
296 GDI_FreeObject( hrgn
);
299 rgnObj
= (RGNOBJ
*) GDI_HEAP_ADDR( hrgn
);
303 if (rgnObj
->region
.type
!= NULLREGION
)
305 int width
= rgnObj
->region
.box
.right
- rgnObj
->region
.box
.left
;
306 int height
= rgnObj
->region
.box
.bottom
- rgnObj
->region
.box
.top
;
307 XSetFunction( display
, regionGC
, GXcopy
);
308 XFillArc( display
, rgnObj
->region
.pixmap
, regionGC
,
309 0, 0, width
, height
, 0, 360*64 );
316 /***********************************************************************
317 * CreatePolygonRgn (GDI.63)
319 HRGN
CreatePolygonRgn( POINT
* points
, short count
, short mode
)
321 return CreatePolyPolygonRgn( points
, &count
, 1, mode
);
325 /***********************************************************************
326 * CreatePolyPolygonRgn (GDI.451)
328 HRGN
CreatePolyPolygonRgn( POINT
* points
, short * count
,
329 short nbpolygons
, short mode
)
334 XPoint
*xpoints
, *pt
;
339 printf( "CreatePolyPolygonRgn: %d polygons\n", nbpolygons
);
342 /* Allocate points array */
344 if (!nbpolygons
) return 0;
345 for (i
= maxPoints
= 0; i
< nbpolygons
; i
++)
346 if (maxPoints
< count
[i
]) maxPoints
= count
[i
];
347 if (!maxPoints
) return 0;
348 if (!(xpoints
= (XPoint
*) malloc( sizeof(XPoint
) * maxPoints
)))
351 /* Allocate region */
353 if (!(hrgn
= GDI_AllocObject( sizeof(RGNOBJ
), REGION_MAGIC
)))
358 rgnObj
= (RGNOBJ
*) GDI_HEAP_ADDR( hrgn
);
359 rgnObj
->region
.type
= SIMPLEREGION
;
360 rgnObj
->region
.pixmap
= 0;
362 /* Create X region */
364 for (i
= 0; i
< nbpolygons
; i
++, count
++)
366 for (j
= *count
, pt
= xpoints
; j
> 0; j
--, points
++, pt
++)
371 xrgn
= XPolygonRegion( xpoints
, *count
,
372 (mode
== WINDING
) ? WindingRule
: EvenOddRule
);
376 Region tmprgn
= XCreateRegion();
377 if (mode
== WINDING
) XUnionRegion(xrgn
,rgnObj
->region
.xrgn
,tmprgn
);
378 else XXorRegion( xrgn
, rgnObj
->region
.xrgn
, tmprgn
);
379 XDestroyRegion( rgnObj
->region
.xrgn
);
380 rgnObj
->region
.xrgn
= tmprgn
;
382 else rgnObj
->region
.xrgn
= xrgn
;
388 GDI_FreeObject( hrgn
);
391 XClipBox( rgnObj
->region
.xrgn
, &rect
);
392 SetRect( &rgnObj
->region
.box
, rect
.x
, rect
.y
,
393 rect
.x
+ rect
.width
, rect
.y
+ rect
.height
);
398 /***********************************************************************
399 * PtInRegion (GDI.161)
401 BOOL
PtInRegion( HRGN hrgn
, short x
, short y
)
407 if (!(obj
= (RGNOBJ
*) GDI_GetObjPtr( hrgn
, REGION_MAGIC
))) return FALSE
;
408 if (!PtInRect( &obj
->region
.box
, pt
)) return FALSE
;
409 if (obj
->region
.xrgn
)
411 return XPointInRegion( obj
->region
.xrgn
, x
, y
);
415 XImage
*image
= XGetImage( display
, obj
->region
.pixmap
,
416 x
- obj
->region
.box
.left
, y
- obj
->region
.box
.top
,
417 1, 1, AllPlanes
, ZPixmap
);
418 if (!image
) return FALSE
;
419 res
= (XGetPixel( image
, 0, 0 ) != 0);
420 XDestroyImage( image
);
426 /***********************************************************************
427 * RectInRegion (GDI.181)
429 BOOL
RectInRegion( HRGN hrgn
, LPRECT rect
)
436 if (!(obj
= (RGNOBJ
*) GDI_GetObjPtr( hrgn
, REGION_MAGIC
))) return FALSE
;
437 if (obj
->region
.xrgn
)
439 return (XRectInRegion( obj
->region
.xrgn
, rect
->left
, rect
->top
,
440 rect
->right
-rect
->left
,
441 rect
->bottom
-rect
->top
) != RectangleOut
);
445 if (!IntersectRect( &intersect
, &obj
->region
.box
, rect
)) return FALSE
;
447 image
= XGetImage( display
, obj
->region
.pixmap
,
448 intersect
.left
- obj
->region
.box
.left
,
449 intersect
.top
- obj
->region
.box
.top
,
450 intersect
.right
- intersect
.left
,
451 intersect
.bottom
- intersect
.top
,
452 AllPlanes
, ZPixmap
);
453 if (!image
) return FALSE
;
454 for (y
= 0; y
< image
->height
; y
++)
455 for (x
= 0; x
< image
->width
; x
++)
456 if (XGetPixel( image
, x
, y
) != 0)
458 XDestroyImage( image
);
462 XDestroyImage( image
);
468 /***********************************************************************
471 BOOL
EqualRgn( HRGN rgn1
, HRGN rgn2
)
474 XImage
*image1
, *image2
;
475 Pixmap pixmap1
, pixmap2
;
476 int width
, height
, x
, y
;
478 /* Compare bounding boxes */
480 if (!(obj1
= (RGNOBJ
*) GDI_GetObjPtr( rgn1
, REGION_MAGIC
))) return FALSE
;
481 if (!(obj2
= (RGNOBJ
*) GDI_GetObjPtr( rgn2
, REGION_MAGIC
))) return FALSE
;
482 if (obj1
->region
.type
== NULLREGION
)
483 return (obj2
->region
.type
== NULLREGION
);
484 else if (obj2
->region
.type
== NULLREGION
) return FALSE
;
485 if (!EqualRect( &obj1
->region
.box
, &obj2
->region
.box
)) return FALSE
;
486 if (obj1
->region
.xrgn
&& obj2
->region
.xrgn
)
488 return XEqualRegion( obj1
->region
.xrgn
, obj2
->region
.xrgn
);
491 /* Get pixmap contents */
493 if (!(pixmap1
= obj1
->region
.pixmap
) &&
494 !REGION_MakePixmap( &obj1
->region
)) return FALSE
;
495 if (!(pixmap2
= obj2
->region
.pixmap
) &&
496 !REGION_MakePixmap( &obj2
->region
)) return FALSE
;
497 width
= obj1
->region
.box
.right
- obj1
->region
.box
.left
;
498 height
= obj1
->region
.box
.bottom
- obj1
->region
.box
.top
;
499 image1
= XGetImage( display
, obj1
->region
.pixmap
,
500 0, 0, width
, height
, AllPlanes
, ZPixmap
);
501 image2
= XGetImage( display
, obj2
->region
.pixmap
,
502 0, 0, width
, height
, AllPlanes
, ZPixmap
);
503 if (!image1
|| !image2
)
505 if (image1
) XDestroyImage( image1
);
506 if (image2
) XDestroyImage( image2
);
510 /* Compare pixmaps */
511 for (y
= 0; y
< height
; y
++)
512 for (x
= 0; x
< width
; x
++)
513 if (XGetPixel( image1
, x
, y
) != XGetPixel( image2
, x
, y
))
515 XDestroyImage( image1
);
516 XDestroyImage( image2
);
520 XDestroyImage( image1
);
521 XDestroyImage( image2
);
526 /***********************************************************************
527 * REGION_CopyIntersection
529 * Copy to dest->pixmap the area of src->pixmap delimited by
530 * the intersection of dest and src regions, using the current GC function.
532 void REGION_CopyIntersection( REGION
* dest
, REGION
* src
)
535 if (!IntersectRect( &inter
, &dest
->box
, &src
->box
)) return;
536 XCopyArea( display
, src
->pixmap
, dest
->pixmap
, regionGC
,
537 inter
.left
- src
->box
.left
, inter
.top
- src
->box
.top
,
538 inter
.right
- inter
.left
, inter
.bottom
- inter
.top
,
539 inter
.left
- dest
->box
.left
, inter
.top
- dest
->box
.top
);
543 /***********************************************************************
544 * CombineRgn (GDI.451)
546 int CombineRgn( HRGN hDest
, HRGN hSrc1
, HRGN hSrc2
, short mode
)
548 RGNOBJ
*destObj
, *src1Obj
, *src2Obj
;
554 printf( "CombineRgn: %d %d %d %d\n", hDest
, hSrc1
, hSrc2
, mode
);
557 if (!(destObj
= (RGNOBJ
*) GDI_GetObjPtr( hDest
, REGION_MAGIC
)))
559 if (!(src1Obj
= (RGNOBJ
*) GDI_GetObjPtr( hSrc1
, REGION_MAGIC
)))
561 if (mode
!= RGN_COPY
)
562 if (!(src2Obj
= (RGNOBJ
*) GDI_GetObjPtr( hSrc2
, REGION_MAGIC
)))
564 region
= &destObj
->region
;
566 if (src1Obj
->region
.xrgn
&& ((mode
== RGN_COPY
) || src2Obj
->region
.xrgn
))
568 /* Perform the operation with X regions */
570 if (region
->pixmap
) XFreePixmap( display
, region
->pixmap
);
572 if (!region
->xrgn
) region
->xrgn
= XCreateRegion();
576 XIntersectRegion( src1Obj
->region
.xrgn
, src2Obj
->region
.xrgn
,
580 XUnionRegion( src1Obj
->region
.xrgn
, src2Obj
->region
.xrgn
,
584 XXorRegion( src1Obj
->region
.xrgn
, src2Obj
->region
.xrgn
,
588 XSubtractRegion( src1Obj
->region
.xrgn
, src2Obj
->region
.xrgn
,
593 Region tmprgn
= XCreateRegion();
594 XUnionRegion( tmprgn
, src1Obj
->region
.xrgn
, region
->xrgn
);
595 XDestroyRegion( tmprgn
);
601 if (XEmptyRegion(region
->xrgn
))
603 region
->type
= NULLREGION
;
610 XClipBox( region
->xrgn
, &rect
);
611 region
->type
= COMPLEXREGION
;
612 region
->box
.left
= rect
.x
;
613 region
->box
.top
= rect
.y
;
614 region
->box
.right
= rect
.x
+ rect
.width
;
615 region
->box
.bottom
= rect
.y
+ rect
.height
;
616 return COMPLEXREGION
;
619 else /* Create pixmaps if needed */
621 if (!src1Obj
->region
.pixmap
)
622 if (!REGION_MakePixmap( &src1Obj
->region
)) return ERROR
;
623 if ((mode
!= RGN_COPY
) && !src2Obj
->region
.pixmap
)
624 if (!REGION_MakePixmap( &src2Obj
->region
)) return ERROR
;
631 res
= IntersectRect( ®ion
->box
, &src1Obj
->region
.box
,
632 &src2Obj
->region
.box
);
633 region
->type
= COMPLEXREGION
;
638 res
= UnionRect( ®ion
->box
, &src1Obj
->region
.box
,
639 &src2Obj
->region
.box
);
640 region
->type
= COMPLEXREGION
;
644 res
= SubtractRect( ®ion
->box
, &src1Obj
->region
.box
,
645 &src2Obj
->region
.box
);
646 region
->type
= COMPLEXREGION
;
650 region
->box
= src1Obj
->region
.box
;
651 region
->type
= src1Obj
->region
.type
;
652 res
= (region
->type
!= NULLREGION
);
659 if (region
->pixmap
) XFreePixmap( display
, region
->pixmap
);
660 if (region
->xrgn
) XDestroyRegion( region
->xrgn
);
663 region
->type
= NULLREGION
;
669 width
= region
->box
.right
- region
->box
.left
;
670 height
= region
->box
.bottom
- region
->box
.top
;
671 if (!width
|| !height
)
673 printf( "CombineRgn: width or height is 0. Please report this.\n" );
674 printf( "src1=%d,%d-%d,%d src2=%d,%d-%d,%d dst=%d,%d-%d,%d op=%d\n",
675 src1Obj
->region
.box
.left
, src1Obj
->region
.box
.top
,
676 src1Obj
->region
.box
.right
, src1Obj
->region
.box
.bottom
,
677 src2Obj
->region
.box
.left
, src2Obj
->region
.box
.top
,
678 src2Obj
->region
.box
.right
, src2Obj
->region
.box
.bottom
,
679 region
->box
.left
, region
->box
.top
,
680 region
->box
.right
, region
->box
.bottom
, mode
);
683 region
->pixmap
= XCreatePixmap( display
, rootWindow
, width
, height
, 1 );
689 XSetFunction( display
, regionGC
, GXcopy
);
690 REGION_CopyIntersection( region
, &src1Obj
->region
);
691 XSetFunction( display
, regionGC
, GXand
);
692 REGION_CopyIntersection( region
, &src2Obj
->region
);
697 XSetFunction( display
, regionGC
, GXclear
);
698 XFillRectangle( display
, region
->pixmap
, regionGC
,
699 0, 0, width
, height
);
700 XSetFunction( display
, regionGC
, (mode
== RGN_OR
) ? GXor
: GXxor
);
701 REGION_CopyIntersection( region
, &src1Obj
->region
);
702 REGION_CopyIntersection( region
, &src2Obj
->region
);
706 XSetFunction( display
, regionGC
, GXclear
);
707 XFillRectangle( display
, region
->pixmap
, regionGC
,
708 0, 0, width
, height
);
709 XSetFunction( display
, regionGC
, GXcopy
);
710 REGION_CopyIntersection( region
, &src1Obj
->region
);
711 XSetFunction( display
, regionGC
, GXandInverted
);
712 REGION_CopyIntersection( region
, &src2Obj
->region
);
716 XSetFunction( display
, regionGC
, GXcopy
);
717 XCopyArea( display
, src1Obj
->region
.pixmap
, region
->pixmap
,
718 regionGC
, 0, 0, width
, height
, 0, 0 );