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