1 /*
2  * tkMacOSXRegion.c --
3  *
4  *	Implements X window calls for manipulating regions
5  *
6  * Copyright © 1995-1996 Sun Microsystems, Inc.
7  * Copyright © 2001-2009, Apple Inc.
8  * Copyright © 2006-2009 Daniel A. Steffen <das@users.sourceforge.net>
9  *
10  * See the file "license.terms" for information on usage and redistribution
11  * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
12  */
13 
14 #include "tkMacOSXPrivate.h"
15 static void RetainRegion(TkRegion r);
16 static void ReleaseRegion(TkRegion r);
17 
18 #ifdef DEBUG
19 static int totalRegions = 0;
20 static int totalRegionRetainCount = 0;
21 #define DebugLog(msg, ...) fprintf(stderr, (msg), ##__VA_ARGS__)
22 #else
23 #define DebugLog(msg, ...)
24 #endif
25 
26 
27 /*
28  *----------------------------------------------------------------------
29  *
30  * XCreateRegion --
31  *
32  *	Implements the equivelent of the X window function XCreateRegion. See
33  *	Xwindow documentation for more details.
34  *
35  * Results:
36  *	Returns an allocated region handle.
37  *
38  * Side effects:
39  *	None.
40  *
41  *----------------------------------------------------------------------
42  */
43 
44 Region
XCreateRegion(void)45 XCreateRegion(void)
46 {
47     Region region = (Region) HIShapeCreateMutable();
48     DebugLog("Created region: total regions = %d\n", ++totalRegions);
49     RetainRegion(region);
50     return region;
51 }
52 
53 /*
54  *----------------------------------------------------------------------
55  *
56  * XDestroyRegion --
57  *
58  *	Implements the equivelent of the X window function XDestroyRegion. See
59  *	Xwindow documentation for more details.
60  *
61  * Results:
62  *	None.
63  *
64  * Side effects:
65  *	Memory is freed.
66  *
67  *----------------------------------------------------------------------
68  */
69 
70 int
XDestroyRegion(Region r)71 XDestroyRegion(
72     Region r)
73 {
74     if (r) {
75 	DebugLog("Destroyed region: total regions = %d\n", --totalRegions);
76 	ReleaseRegion(r);
77     }
78     return Success;
79 }
80 
81 /*
82  *----------------------------------------------------------------------
83  *
84  * XIntersectRegion --
85  *
86  *	Implements the equivalent of the X window function XIntersectRegion.
87  *	See Xwindow documentation for more details.
88  *
89  * Results:
90  *	None.
91  *
92  * Side effects:
93  *	None.
94  *
95  *----------------------------------------------------------------------
96  */
97 
98 int
XIntersectRegion(Region sra,Region srb,Region dr_return)99 XIntersectRegion(
100     Region sra,
101     Region srb,
102     Region dr_return)
103 {
104     ChkErr(HIShapeIntersect, (HIShapeRef) sra, (HIShapeRef) srb,
105 	   (HIMutableShapeRef) dr_return);
106     return Success;
107 }
108 
109 /*
110  *----------------------------------------------------------------------
111  *
112  * XSubtractRegion --
113  *
114  *	Implements the equivalent of the X window function XSubtractRegion.
115  *	See X window documentation for more details.
116  *
117  * Results:
118  *	None.
119  *
120  * Side effects:
121  *	None.
122  *
123  *----------------------------------------------------------------------
124  */
125 
126 int
XSubtractRegion(Region sra,Region srb,Region dr_return)127 XSubtractRegion(
128     Region sra,
129     Region srb,
130     Region dr_return)
131 {
132     ChkErr(HIShapeDifference, (HIShapeRef) sra, (HIShapeRef) srb,
133 	   (HIMutableShapeRef) dr_return);
134     return Success;
135 }
136 
137 /*
138  *----------------------------------------------------------------------
139  *
140  * XUnionRectWithRegion --
141  *
142  *	Implements the equivelent of the X window function
143  *	XUnionRectWithRegion. See Xwindow documentation for more details.
144  *
145  * Results:
146  *	None.
147  *
148  * Side effects:
149  *	None.
150  *
151  *----------------------------------------------------------------------
152  */
153 
154 int
XUnionRectWithRegion(XRectangle * rectangle,Region src_region,Region dest_region_return)155 XUnionRectWithRegion(
156     XRectangle* rectangle,
157     Region src_region,
158     Region dest_region_return)
159 {
160     const CGRect r = CGRectMake(rectangle->x, rectangle->y,
161 	    rectangle->width, rectangle->height);
162 
163     if (src_region == dest_region_return) {
164 	ChkErr(TkMacOSHIShapeUnionWithRect,
165 		(HIMutableShapeRef) dest_region_return, &r);
166     } else {
167 	HIShapeRef rectRgn = HIShapeCreateWithRect(&r);
168 
169 	ChkErr(TkMacOSHIShapeUnion, rectRgn, (HIShapeRef) src_region,
170 		(HIMutableShapeRef) dest_region_return);
171 	CFRelease(rectRgn);
172     }
173     return Success;
174 }
175 
176 /*
177  *----------------------------------------------------------------------
178  *
179  * TkMacOSXIsEmptyRegion --
180  *
181  *	Return native region for given tk region.
182  *
183  * Results:
184  *	1 if empty, 0 otherwise.
185  *
186  * Side effects:
187  *	None.
188  *
189  *----------------------------------------------------------------------
190  */
191 
192 static int
TkMacOSXIsEmptyRegion(Region r)193 TkMacOSXIsEmptyRegion(
194     Region r)
195 {
196     return HIShapeIsEmpty((HIMutableShapeRef) r) ? 1 : 0;
197 }
198 
199 /*
200  *----------------------------------------------------------------------
201  *
202  * XRectInRegion --
203  *
204  *	Implements the equivelent of the X window function XRectInRegion. See
205  *	Xwindow documentation for more details.
206  *
207  * Results:
208  *	Returns RectanglePart or RectangleOut. Note that this is not a complete
209  *	implementation since it doesn't test for RectangleIn.
210  *
211  * Side effects:
212  *	None.
213  *
214  *----------------------------------------------------------------------
215  */
216 
217 int
XRectInRegion(Region region,int x,int y,unsigned int width,unsigned int height)218 XRectInRegion(
219     Region region,
220     int x,
221     int y,
222     unsigned int width,
223     unsigned int height)
224 {
225     if (TkMacOSXIsEmptyRegion(region)) {
226 	return RectangleOut;
227     } else {
228 	const CGRect r = CGRectMake(x, y, width, height);
229 
230 	return HIShapeIntersectsRect((HIShapeRef) region, &r) ?
231 		RectanglePart : RectangleOut;
232     }
233 }
234 
235 /*
236  *----------------------------------------------------------------------
237  *
238  * XClipBox --
239  *
240  *	Implements the equivelent of the X window function XClipBox. See
241  *	Xwindow documentation for more details.
242  *
243  * Results:
244  *	None.
245  *
246  * Side effects:
247  *	None.
248  *
249  *----------------------------------------------------------------------
250  */
251 
252 int
XClipBox(Region r,XRectangle * rect_return)253 XClipBox(
254     Region r,
255     XRectangle *rect_return)
256 {
257     CGRect rect;
258 
259     HIShapeGetBounds((HIShapeRef) r, &rect);
260     rect_return->x = rect.origin.x;
261     rect_return->y = rect.origin.y;
262     rect_return->width = rect.size.width;
263     rect_return->height = rect.size.height;
264     return Success;
265 }
266 
267 /*
268  *----------------------------------------------------------------------
269  *
270  * TkpBuildRegionFromAlphaData --
271  *
272  *	Set up a rectangle of the given region based on the supplied alpha
273  *	data.
274  *
275  * Results:
276  *	None
277  *
278  * Side effects:
279  *	The region is updated, with extra pixels added to it.
280  *
281  *----------------------------------------------------------------------
282  */
283 
284 void
TkpBuildRegionFromAlphaData(Region region,unsigned int x,unsigned int y,unsigned int width,unsigned int height,unsigned char * dataPtr,unsigned int pixelStride,unsigned int lineStride)285 TkpBuildRegionFromAlphaData(
286     Region region,			/* Region to update. */
287     unsigned int x,			/* Where in region to update. */
288     unsigned int y,			/* Where in region to update. */
289     unsigned int width,			/* Size of rectangle to update. */
290     unsigned int height,		/* Size of rectangle to update. */
291     unsigned char *dataPtr,		/* Data to read from. */
292     unsigned int pixelStride,		/* num bytes from one piece of alpha
293 					 * data to the next in the line. */
294     unsigned int lineStride)		/* num bytes from one line of alpha
295 					 * data to the next line. */
296 {
297     unsigned char *lineDataPtr;
298     unsigned int x1, y1, end;
299     XRectangle rect;
300 
301     for (y1 = 0; y1 < height; y1++) {
302 	lineDataPtr = dataPtr;
303 	for (x1 = 0; x1 < width; x1 = end) {
304 	    /*
305 	     * Search for first non-transparent pixel.
306 	     */
307 
308 	    while ((x1 < width) && !*lineDataPtr) {
309 		x1++;
310 		lineDataPtr += pixelStride;
311 	    }
312 	    end = x1;
313 
314 	    /*
315 	     * Search for first transparent pixel.
316 	     */
317 
318 	    while ((end < width) && *lineDataPtr) {
319 		end++;
320 		lineDataPtr += pixelStride;
321 	    }
322 	    if (end > x1) {
323 		rect.x = x + x1;
324 		rect.y = y + y1;
325 		rect.width = end - x1;
326 		rect.height = 1;
327 		XUnionRectWithRegion(&rect, region, region);
328 	    }
329 	}
330 	dataPtr += lineStride;
331     }
332 }
333 
334 /*
335  *----------------------------------------------------------------------
336  *
337  * RetainRegion --
338  *
339  *	Increases reference count of region.
340  *
341  * Results:
342  *	None.
343  *
344  * Side effects:
345  *	None.
346  *
347  *----------------------------------------------------------------------
348  */
349 
350 static void
RetainRegion(Region r)351 RetainRegion(
352     Region r)
353 {
354     CFRetain(r);
355     DebugLog("Retained region: total count is %d\n", ++totalRegionRetainCount);
356 }
357 
358 /*
359  *----------------------------------------------------------------------
360  *
361  * ReleaseRegion --
362  *
363  *	Decreases reference count of region.
364  *
365  * Results:
366  *	None.
367  *
368  * Side effects:
369  *	May free memory.
370  *
371  *----------------------------------------------------------------------
372  */
373 
374 static void
ReleaseRegion(Region r)375 ReleaseRegion(
376     Region r)
377 {
378     CFRelease(r);
379     DebugLog("Released region: total count is %d\n", --totalRegionRetainCount);
380 }
381 
382 /*
383  *----------------------------------------------------------------------
384  *
385  * TkMacOSXSetEmptyRegion --
386  *
387  *	Set region to emtpy.
388  *
389  * Results:
390  *	None.
391  *
392  * Side effects:
393  *	None.
394  *
395  *----------------------------------------------------------------------
396  */
397 
398 void
TkMacOSXSetEmptyRegion(Region r)399 TkMacOSXSetEmptyRegion(
400     Region r)
401 {
402     ChkErr(HIShapeSetEmpty, (HIMutableShapeRef) r);
403 }
404 
405 /*
406  *----------------------------------------------------------------------
407  *
408  * TkMacOSXGetNativeRegion --
409  *
410  *	Return native region for given tk region.
411  *
412  * Results:
413  *	Native region, CFRelease when done.
414  *
415  * Side effects:
416  *	None.
417  *
418  *----------------------------------------------------------------------
419  */
420 
421 HIShapeRef
TkMacOSXGetNativeRegion(Region r)422 TkMacOSXGetNativeRegion(
423     Region r)
424 {
425     return (HIShapeRef) CFRetain(r);
426 }
427 
428 /*
429  *----------------------------------------------------------------------
430  *
431  * TkMacOSXSetWithNativeRegion --
432  *
433  *	Set region to the native region.
434  *
435  * Results:
436  *	None.
437  *
438  * Side effects:
439  *	None.
440  *
441  *----------------------------------------------------------------------
442  */
443 
444 void
TkMacOSXSetWithNativeRegion(Region r,HIShapeRef rgn)445 TkMacOSXSetWithNativeRegion(
446     Region r,
447     HIShapeRef rgn)
448 {
449     ChkErr(TkMacOSXHIShapeSetWithShape, (HIMutableShapeRef) r, rgn);
450 }
451 
452 /*
453  *----------------------------------------------------------------------
454  *
455  * XOffsetRegion --
456  *
457  *	Offsets region by given distances.
458  *
459  * Results:
460  *	None.
461  *
462  * Side effects:
463  *	None.
464  *
465  *----------------------------------------------------------------------
466  */
467 
468 int
XOffsetRegion(Region r,int dx,int dy)469 XOffsetRegion(
470     Region r,
471     int dx,
472     int dy)
473 {
474     ChkErr(HIShapeOffset, (HIMutableShapeRef) r, dx, dy);
475     return Success;
476 }
477 
478 /*
479  *----------------------------------------------------------------------
480  *
481  * TkMacOSXHIShapeCreateEmpty, TkMacOSXHIShapeCreateMutableWithRect,
482  * TkMacOSXHIShapeSetWithShape,
483  * TkMacOSHIShapeDifferenceWithRect, TkMacOSHIShapeUnionWithRect,
484  * TkMacOSHIShapeUnion --
485  *
486  *	Wrapper functions for missing/buggy HIShape API
487  *
488  *----------------------------------------------------------------------
489  */
490 
491 HIShapeRef
TkMacOSXHIShapeCreateEmpty(void)492 TkMacOSXHIShapeCreateEmpty(void)
493 {
494     HIShapeRef result;
495 
496     result = HIShapeCreateEmpty();
497     return result;
498 }
499 
500 HIMutableShapeRef
TkMacOSXHIShapeCreateMutableWithRect(const CGRect * inRect)501 TkMacOSXHIShapeCreateMutableWithRect(
502     const CGRect *inRect)
503 {
504     HIMutableShapeRef result;
505 
506     result = HIShapeCreateMutableWithRect(inRect);
507     return result;
508 }
509 
510 OSStatus
TkMacOSXHIShapeSetWithShape(HIMutableShapeRef inDestShape,HIShapeRef inSrcShape)511 TkMacOSXHIShapeSetWithShape(
512     HIMutableShapeRef inDestShape,
513     HIShapeRef inSrcShape)
514 {
515     OSStatus result;
516 
517     result = HIShapeSetWithShape(inDestShape, inSrcShape);
518     return result;
519 }
520 
521 OSStatus
TkMacOSHIShapeDifferenceWithRect(HIMutableShapeRef inShape,const CGRect * inRect)522 TkMacOSHIShapeDifferenceWithRect(
523     HIMutableShapeRef inShape,
524     const CGRect *inRect)
525 {
526     OSStatus result;
527     HIShapeRef rgn = HIShapeCreateWithRect(inRect);
528 
529     result = HIShapeDifference(inShape, rgn, inShape);
530     CFRelease(rgn);
531 
532     return result;
533 }
534 
535 OSStatus
TkMacOSHIShapeUnionWithRect(HIMutableShapeRef inShape,const CGRect * inRect)536 TkMacOSHIShapeUnionWithRect(
537     HIMutableShapeRef inShape,
538     const CGRect *inRect)
539 {
540     OSStatus result;
541 
542     result = HIShapeUnionWithRect(inShape, inRect);
543     return result;
544 }
545 
546 OSStatus
TkMacOSHIShapeUnion(HIShapeRef inShape1,HIShapeRef inShape2,HIMutableShapeRef outResult)547 TkMacOSHIShapeUnion(
548     HIShapeRef inShape1,
549     HIShapeRef inShape2,
550     HIMutableShapeRef outResult)
551 {
552     OSStatus result;
553 
554     result = HIShapeUnion(inShape1, inShape2, outResult);
555     return result;
556 }
557 
558 static OSStatus
rectCounter(TCL_UNUSED (int),TCL_UNUSED (HIShapeRef),TCL_UNUSED (const CGRect *),void * ref)559 rectCounter(
560     TCL_UNUSED(int),
561     TCL_UNUSED(HIShapeRef),
562     TCL_UNUSED(const CGRect *),
563     void *ref)
564 {
565     int *count = (int *)ref;
566     (*count)++;
567     return noErr;
568 }
569 
570 static OSStatus
rectPrinter(TCL_UNUSED (int),TCL_UNUSED (HIShapeRef),const CGRect * rect,TCL_UNUSED (void *))571 rectPrinter(
572     TCL_UNUSED(int),
573     TCL_UNUSED(HIShapeRef),
574     const CGRect *rect,
575     TCL_UNUSED(void *))
576 {
577     if (rect) {
578 	fprintf(stderr, "    %s\n", NSStringFromRect(*rect).UTF8String);
579     }
580     return noErr;
581 }
582 
583 int
TkMacOSXCountRectsInRegion(HIShapeRef shape)584 TkMacOSXCountRectsInRegion(
585     HIShapeRef shape)
586 {
587     int rect_count = 0;
588     if (!HIShapeIsEmpty(shape)) {
589 	ChkErr(HIShapeEnumerate, shape,
590 		kHIShapeParseFromBottom|kHIShapeParseFromLeft,
591 		rectCounter, &rect_count);
592     }
593     return rect_count;
594 }
595 
596 void
TkMacOSXPrintRectsInRegion(HIShapeRef shape)597 TkMacOSXPrintRectsInRegion(
598     HIShapeRef shape)
599 {
600     if (!HIShapeIsEmpty(shape)) {
601 	ChkErr(HIShapeEnumerate, shape,
602 		kHIShapeParseFromBottom|kHIShapeParseFromLeft,
603 		rectPrinter, NULL);
604     }
605 }
606 
607 /*
608  * Local Variables:
609  * mode: objc
610  * c-basic-offset: 4
611  * fill-column: 79
612  * coding: utf-8
613  * End:
614  */
615