Release 940912
[wine/multimedia.git] / objects / region.c
blob74ec57baea633dd23e0ab25dff0e337e9c26317b
1 /*
2 * GDI region objects
4 * Copyright 1993, 1994 Alexandre Julliard
5 */
7 static char Copyright[] = "Copyright Alexandre Julliard, 1993, 1994";
9 #include <stdlib.h>
10 #include <stdio.h>
12 #include "gdi.h"
14 /* GC used for region operations */
15 static GC regionGC = 0;
17 /***********************************************************************
18 * REGION_Init
20 BOOL REGION_Init()
22 Pixmap tmpPixmap;
24 /* CreateGC needs a drawable */
25 tmpPixmap = XCreatePixmap( display, rootWindow, 1, 1, 1 );
26 if (tmpPixmap)
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 );
33 return TRUE;
35 else return FALSE;
39 /***********************************************************************
40 * REGION_MakePixmap
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 */
57 return TRUE;
61 /***********************************************************************
62 * REGION_SetRect
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 )
69 int width, height;
71 /* Fill region */
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;
79 region->box.left = 0;
80 region->box.right = 0;
81 region->box.top = 0;
82 region->box.bottom = 0;
83 region->pixmap = 0;
84 region->xrgn = 0;
85 return TRUE;
87 region->type = SIMPLEREGION;
88 region->box = *rect;
89 region->xrgn = 0;
90 region->pixmap = 0;
92 if (createXrgn) /* Create and set the X region */
94 Region tmprgn;
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);
111 return TRUE;
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;
133 #ifdef DEBUG_REGION
134 printf( "OffsetRgn: %d %d,%d\n", hrgn, x, y );
135 #endif
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;
149 #ifdef DEBUG_REGION
150 printf( "GetRgnBox: %d\n", hrgn );
151 #endif
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 )
172 HRGN hrgn;
174 #ifdef DEBUG_REGION
175 printf( "CreateRectRgnIndirect: %d,%d-%d,%d\n",
176 rect->left, rect->top, rect->right, rect->bottom );
177 #endif
179 /* Create region */
181 if (!(hrgn = GDI_AllocObject( sizeof(RGNOBJ), REGION_MAGIC ))) return 0;
182 if (!REGION_SetRect( hrgn, rect, TRUE ))
184 GDI_FreeObject( hrgn );
185 return 0;
187 return 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 };
198 RGNOBJ * rgnObj;
199 HRGN hrgn;
201 #ifdef DEBUG_REGION
202 printf( "CreateRoundRectRgn: %d,%d-%d,%d %dx%d\n",
203 left, top, right, bottom, ellipse_width, ellipse_height );
204 #endif
206 /* Create region */
208 if (!(hrgn = GDI_AllocObject( sizeof(RGNOBJ), REGION_MAGIC ))) return 0;
209 if (!REGION_SetRect( hrgn, &rect, FALSE ))
211 GDI_FreeObject( hrgn );
212 return 0;
214 rgnObj = (RGNOBJ *) GDI_HEAP_ADDR( hrgn );
216 /* Fill pixmap */
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,
230 0, 0,
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 );
243 return hrgn;
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 };
253 RGNOBJ * rgnObj;
255 #ifdef DEBUG_REGION
256 printf( "SetRectRgn: %d %d,%d-%d,%d\n", hrgn, left, top, right, bottom );
257 #endif
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 )
283 RGNOBJ * rgnObj;
284 HRGN hrgn;
286 #ifdef DEBUG_REGION
287 printf( "CreateEllipticRgnIndirect: %d,%d-%d,%d\n",
288 rect->left, rect->top, rect->right, rect->bottom );
289 #endif
291 /* Create region */
293 if (!(hrgn = GDI_AllocObject( sizeof(RGNOBJ), REGION_MAGIC ))) return 0;
294 if (!REGION_SetRect( hrgn, rect, FALSE ))
296 GDI_FreeObject( hrgn );
297 return 0;
299 rgnObj = (RGNOBJ *) GDI_HEAP_ADDR( hrgn );
301 /* Fill pixmap */
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 );
312 return hrgn;
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 )
331 RGNOBJ * rgnObj;
332 HRGN hrgn;
333 int i, j, maxPoints;
334 XPoint *xpoints, *pt;
335 XRectangle rect;
336 Region xrgn;
338 #ifdef DEBUG_REGION
339 printf( "CreatePolyPolygonRgn: %d polygons\n", nbpolygons );
340 #endif
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 )))
349 return 0;
351 /* Allocate region */
353 if (!(hrgn = GDI_AllocObject( sizeof(RGNOBJ), REGION_MAGIC )))
355 free( xpoints );
356 return 0;
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++)
368 pt->x = points->x;
369 pt->y = points->y;
371 xrgn = XPolygonRegion( xpoints, *count,
372 (mode == WINDING) ? WindingRule : EvenOddRule );
373 if (!xrgn) break;
374 if (i > 0)
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;
385 free( xpoints );
386 if (!xrgn)
388 GDI_FreeObject( hrgn );
389 return 0;
391 XClipBox( rgnObj->region.xrgn, &rect );
392 SetRect( &rgnObj->region.box, rect.x, rect.y,
393 rect.x + rect.width, rect.y + rect.height);
394 return hrgn;
398 /***********************************************************************
399 * PtInRegion (GDI.161)
401 BOOL PtInRegion( HRGN hrgn, short x, short y )
403 BOOL res;
404 RGNOBJ * obj;
405 POINT pt = { x, 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 );
413 else
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 );
422 return res;
426 /***********************************************************************
427 * RectInRegion (GDI.181)
429 BOOL RectInRegion( HRGN hrgn, LPRECT rect )
431 XImage * image;
432 RGNOBJ * obj;
433 RECT intersect;
434 int x, y;
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);
443 else
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 );
459 return TRUE;
462 XDestroyImage( image );
464 return FALSE;
468 /***********************************************************************
469 * EqualRgn (GDI.72)
471 BOOL EqualRgn( HRGN rgn1, HRGN rgn2 )
473 RGNOBJ *obj1, *obj2;
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 );
507 return FALSE;
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 );
517 return FALSE;
520 XDestroyImage( image1 );
521 XDestroyImage( image2 );
522 return TRUE;
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 )
534 RECT inter;
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;
549 REGION * region;
550 int width, height;
551 BOOL res;
553 #ifdef DEBUG_REGION
554 printf( "CombineRgn: %d %d %d %d\n", hDest, hSrc1, hSrc2, mode );
555 #endif
557 if (!(destObj = (RGNOBJ *) GDI_GetObjPtr( hDest, REGION_MAGIC )))
558 return ERROR;
559 if (!(src1Obj = (RGNOBJ *) GDI_GetObjPtr( hSrc1, REGION_MAGIC )))
560 return ERROR;
561 if (mode != RGN_COPY)
562 if (!(src2Obj = (RGNOBJ *) GDI_GetObjPtr( hSrc2, REGION_MAGIC )))
563 return ERROR;
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 );
571 region->pixmap = 0;
572 if (!region->xrgn) region->xrgn = XCreateRegion();
573 switch(mode)
575 case RGN_AND:
576 XIntersectRegion( src1Obj->region.xrgn, src2Obj->region.xrgn,
577 region->xrgn );
578 break;
579 case RGN_OR:
580 XUnionRegion( src1Obj->region.xrgn, src2Obj->region.xrgn,
581 region->xrgn );
582 break;
583 case RGN_XOR:
584 XXorRegion( src1Obj->region.xrgn, src2Obj->region.xrgn,
585 region->xrgn );
586 break;
587 case RGN_DIFF:
588 XSubtractRegion( src1Obj->region.xrgn, src2Obj->region.xrgn,
589 region->xrgn );
590 break;
591 case RGN_COPY:
593 Region tmprgn = XCreateRegion();
594 XUnionRegion( tmprgn, src1Obj->region.xrgn, region->xrgn );
595 XDestroyRegion( tmprgn );
597 break;
598 default:
599 return ERROR;
601 if (XEmptyRegion(region->xrgn))
603 region->type = NULLREGION;
604 region->xrgn = 0;
605 return NULLREGION;
607 else
609 XRectangle rect;
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;
628 switch(mode)
630 case RGN_AND:
631 res = IntersectRect( &region->box, &src1Obj->region.box,
632 &src2Obj->region.box );
633 region->type = COMPLEXREGION;
634 break;
636 case RGN_OR:
637 case RGN_XOR:
638 res = UnionRect( &region->box, &src1Obj->region.box,
639 &src2Obj->region.box );
640 region->type = COMPLEXREGION;
641 break;
643 case RGN_DIFF:
644 res = SubtractRect( &region->box, &src1Obj->region.box,
645 &src2Obj->region.box );
646 region->type = COMPLEXREGION;
647 break;
649 case RGN_COPY:
650 region->box = src1Obj->region.box;
651 region->type = src1Obj->region.type;
652 res = (region->type != NULLREGION);
653 break;
655 default:
656 return ERROR;
659 if (region->pixmap) XFreePixmap( display, region->pixmap );
660 if (region->xrgn) XDestroyRegion( region->xrgn );
661 if (!res)
663 region->type = NULLREGION;
664 region->pixmap = 0;
665 region->xrgn = 0;
666 return 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 );
681 exit(1);
683 region->pixmap = XCreatePixmap( display, rootWindow, width, height, 1 );
684 region->xrgn = 0;
686 switch(mode)
688 case RGN_AND:
689 XSetFunction( display, regionGC, GXcopy );
690 REGION_CopyIntersection( region, &src1Obj->region );
691 XSetFunction( display, regionGC, GXand );
692 REGION_CopyIntersection( region, &src2Obj->region );
693 break;
695 case RGN_OR:
696 case RGN_XOR:
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 );
703 break;
705 case RGN_DIFF:
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 );
713 break;
715 case RGN_COPY:
716 XSetFunction( display, regionGC, GXcopy );
717 XCopyArea( display, src1Obj->region.pixmap, region->pixmap,
718 regionGC, 0, 0, width, height, 0, 0 );
719 break;
721 return region->type;