1 /*
2  * tkMacOSXDraw.c --
3  *
4  *	This file contains functions that perform drawing to
5  *	Xlib windows. Most of the functions simple emulate
6  *	Xlib functions.
7  *
8  * Copyright (c) 1995-1997 Sun Microsystems, Inc.
9  * Copyright 2001-2009, Apple Inc.
10  * Copyright (c) 2006-2009 Daniel A. Steffen <das@users.sourceforge.net>
11  * Copyright 2014 Marc Culler.
12  *
13  * See the file "license.terms" for information on usage and redistribution
14  * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
15  */
16 
17 #include "tkMacOSXPrivate.h"
18 #include "tkMacOSXDebug.h"
19 #include "xbytes.h"
20 #include "tkButton.h"
21 
22 /*
23 #ifdef TK_MAC_DEBUG
24 #define TK_MAC_DEBUG_DRAWING
25 #define TK_MAC_DEBUG_IMAGE_DRAWING
26 #endif
27 */
28 
29 #define radians(d) ((d) * (M_PI/180.0))
30 
31 /*
32  * Non-antialiased CG drawing looks better and more like X11 drawing when using
33  * very fine lines, so decrease all linewidths by the following constant.
34  */
35 #define NON_AA_CG_OFFSET .999
36 
37 static int cgAntiAliasLimit = 0;
38 #define notAA(w) ((w) < cgAntiAliasLimit)
39 
40 static int useThemedToplevel = 0;
41 static int useThemedFrame = 0;
42 
43 /*
44  * Prototypes for functions used only in this file.
45  */
46 
47 static void ClipToGC(Drawable d, GC gc, HIShapeRef *clipRgnPtr);
48 static CGImageRef CreateCGImageWithXImage(XImage *ximage);
49 static CGContextRef GetCGContextForDrawable(Drawable d);
50 static void DrawCGImage(Drawable d, GC gc, CGContextRef context, CGImageRef image,
51 	unsigned long imageForeground, unsigned long imageBackground,
52 	CGRect imageBounds, CGRect srcBounds, CGRect dstBounds);
53 
54 
55 /*
56  *----------------------------------------------------------------------
57  *
58  * TkMacOSXInitCGDrawing --
59  *
60  *	Initializes link vars that control CG drawing.
61  *
62  * Results:
63  *	None.
64  *
65  * Side effects:
66  *	None.
67  *
68  *----------------------------------------------------------------------
69  */
70 
71 MODULE_SCOPE int
TkMacOSXInitCGDrawing(Tcl_Interp * interp,int enable,int limit)72 TkMacOSXInitCGDrawing(
73     Tcl_Interp *interp,
74     int enable,
75     int limit)
76 {
77     static Boolean initialized = FALSE;
78 
79     if (!initialized) {
80 	initialized = TRUE;
81 
82 	if (Tcl_CreateNamespace(interp, "::tk::mac", NULL, NULL) == NULL) {
83 	    Tcl_ResetResult(interp);
84 	}
85 
86 	if (Tcl_LinkVar(interp, "::tk::mac::CGAntialiasLimit",
87 		(char *) &cgAntiAliasLimit, TCL_LINK_INT) != TCL_OK) {
88 	    Tcl_ResetResult(interp);
89 	}
90 	cgAntiAliasLimit = limit;
91 
92 	/*
93 	 * Piggy-back the themed drawing var init here.
94 	 */
95 
96 	if (Tcl_LinkVar(interp, "::tk::mac::useThemedToplevel",
97 		(char *) &useThemedToplevel, TCL_LINK_BOOLEAN) != TCL_OK) {
98 	    Tcl_ResetResult(interp);
99 	}
100 	if (Tcl_LinkVar(interp, "::tk::mac::useThemedFrame",
101 		(char *) &useThemedFrame, TCL_LINK_BOOLEAN) != TCL_OK) {
102 	    Tcl_ResetResult(interp);
103 	}
104     }
105     return TCL_OK;
106 }
107 
108 /*
109  *----------------------------------------------------------------------
110  *
111  * BitmapRepFromDrawableRect
112  *
113  *	Extract bitmap data from a MacOSX drawable as an NSBitmapImageRep.
114  *
115  * Results:
116  *	Returns an autoreleased NSBitmapRep representing the image of the given
117  *      rectangle of the given drawable.
118  *
119  *      NOTE: The x,y coordinates should be relative to a coordinate system with
120  *      origin at the top left, as used by XImage and CGImage, not bottom
121  *      left as used by NSView.
122  *
123  * Side effects:
124  *     None
125  *
126  *----------------------------------------------------------------------
127  */
128 NSBitmapImageRep*
BitmapRepFromDrawableRect(Drawable drawable,int x,int y,unsigned int width,unsigned int height)129 BitmapRepFromDrawableRect(
130         Drawable drawable,
131 	int x,
132 	int y,
133 	unsigned int width,
134 	unsigned int height)
135 {
136     MacDrawable *mac_drawable = (MacDrawable *) drawable;
137     CGContextRef cg_context=NULL;
138     CGImageRef cg_image=NULL, sub_cg_image=NULL;
139     NSBitmapImageRep *bitmap_rep=NULL;
140     NSView *view=NULL;
141     if ( mac_drawable->flags & TK_IS_PIXMAP ) {
142 	/*
143 	   This means that the MacDrawable is functioning as a Tk Pixmap, so its view
144 	   field is NULL.
145 	*/
146 	cg_context = GetCGContextForDrawable(drawable);
147 	CGRect image_rect = CGRectMake(x, y, width, height);
148 	cg_image = CGBitmapContextCreateImage( (CGContextRef) cg_context);
149 	sub_cg_image = CGImageCreateWithImageInRect(cg_image, image_rect);
150 	if ( sub_cg_image ) {
151 	  /*This can be dealloc'ed prematurely if set for autorelease, causing crashes.*/
152 	    bitmap_rep = [NSBitmapImageRep alloc];
153 	    [bitmap_rep initWithCGImage:sub_cg_image];
154 	}
155 	if ( cg_image ) {
156 	    CGImageRelease(cg_image);
157 	}
158     } else if ( (view = TkMacOSXDrawableView(mac_drawable)) ) {
159 	/* convert top-left coordinates to NSView coordinates */
160 	int view_height = [view bounds].size.height;
161 	NSRect view_rect = NSMakeRect(x + mac_drawable->xOff,
162 				      view_height - height - y - mac_drawable->yOff,
163 				      width,height);
164 
165 	if ( [view lockFocusIfCanDraw] ) {
166 	     /*This can be dealloc'ed prematurely if set for autorelease, causing crashes.*/
167 	    bitmap_rep = [NSBitmapImageRep alloc];
168 	    bitmap_rep = [bitmap_rep initWithFocusedViewRect:view_rect];
169 	    [view unlockFocus];
170 	} else {
171 	    TkMacOSXDbgMsg("Could not lock focus on view.");
172 	}
173 
174     } else {
175 	TkMacOSXDbgMsg("Invalid source drawable");
176     }
177     return bitmap_rep;
178 }
179 
180 /*
181  *----------------------------------------------------------------------
182  *
183  * XCopyArea --
184  *
185  *	Copies data from one drawable to another.
186  *
187  * Results:
188  *	None.
189  *
190  * Side effects:
191  *	Data is moved from a window or bitmap to a second window or
192  *	bitmap.
193  *
194  *----------------------------------------------------------------------
195  */
196 
197 void
XCopyArea(Display * display,Drawable src,Drawable dst,GC gc,int src_x,int src_y,unsigned int width,unsigned int height,int dest_x,int dest_y)198 XCopyArea(
199     Display *display,		/* Display. */
200     Drawable src,		/* Source drawable. */
201     Drawable dst,		/* Destination drawable. */
202     GC gc,				/* GC to use. */
203     int src_x,			/* X & Y, width & height */
204     int src_y,			/* define the source rectangle */
205     unsigned int width,	/* that will be copied. */
206     unsigned int height,
207     int dest_x,			/* Dest X & Y on dest rect. */
208     int dest_y)
209 {
210     TkMacOSXDrawingContext dc;
211     MacDrawable *srcDraw = (MacDrawable *) src;
212     NSBitmapImageRep *bitmap_rep = NULL;
213     CGImageRef img = NULL;
214 
215     display->request++;
216 
217     if (!width || !height) {
218 	/* This happens all the time.
219 	TkMacOSXDbgMsg("Drawing of empty area requested");
220 	*/
221 	return;
222     }
223 
224     if (!TkMacOSXSetupDrawingContext(dst, gc, 1, &dc)) {
225 	return;
226 	/*TkMacOSXDbgMsg("Failed to setup drawing context.");*/
227     }
228 
229     if ( dc.context ) {
230 	if (srcDraw->flags & TK_IS_PIXMAP) {
231 	    img = TkMacOSXCreateCGImageWithDrawable(src);
232 	}else if (TkMacOSXDrawableWindow(src)) {
233 	    bitmap_rep =  BitmapRepFromDrawableRect(src, src_x, src_y, width, height);
234 	    if ( bitmap_rep ) {
235 		img = [bitmap_rep CGImage];
236 	    }
237 	} else {
238 	    TkMacOSXDbgMsg("Invalid source drawable - neither window nor pixmap.");
239 	}
240 
241 	if (img) {
242 	    DrawCGImage(dst, gc, dc.context, img, gc->foreground, gc->background,
243 			CGRectMake(0, 0, srcDraw->size.width, srcDraw->size.height),
244 			CGRectMake(src_x, src_y, width, height),
245 			CGRectMake(dest_x, dest_y, width, height));
246 	    CFRelease(img);
247 
248 
249 	} else {
250 	    TkMacOSXDbgMsg("Failed to construct CGImage.");
251 	}
252 
253     } else {
254 	TkMacOSXDbgMsg("Invalid destination drawable - no context.");
255 	return;
256     }
257 
258     TkMacOSXRestoreDrawingContext(&dc);
259 }
260 
261 /*
262  *----------------------------------------------------------------------
263  *
264  * XCopyPlane --
265  *
266  *	Copies a bitmap from a source drawable to a destination
267  *	drawable. The plane argument specifies which bit plane of
268  *	the source contains the bitmap. Note that this implementation
269  *	ignores the gc->function.
270  *
271  * Results:
272  *	None.
273  *
274  * Side effects:
275  *	Changes the destination drawable.
276  *
277  *----------------------------------------------------------------------
278  */
279 
280 void
XCopyPlane(Display * display,Drawable src,Drawable dst,GC gc,int src_x,int src_y,unsigned int width,unsigned int height,int dest_x,int dest_y,unsigned long plane)281 XCopyPlane(
282     Display *display,		/* Display. */
283     Drawable src,		/* Source drawable. */
284     Drawable dst,		/* Destination drawable. */
285     GC gc,				/* GC to use. */
286     int src_x,			/* X & Y, width & height */
287     int src_y,			/* define the source rectangle */
288     unsigned int width,	/* that will be copied. */
289     unsigned int height,
290     int dest_x,			/* Dest X & Y on dest rect. */
291     int dest_y,
292     unsigned long plane)	/* Which plane to copy. */
293 {
294     TkMacOSXDrawingContext dc;
295     MacDrawable *srcDraw = (MacDrawable *) src;
296     MacDrawable *dstDraw = (MacDrawable *) dst;
297 
298     display->request++;
299     if (!width || !height) {
300 	/* TkMacOSXDbgMsg("Drawing of empty area requested"); */
301 	return;
302     }
303     if (plane != 1) {
304 	Tcl_Panic("Unexpected plane specified for XCopyPlane");
305     }
306     if (srcDraw->flags & TK_IS_PIXMAP) {
307 	if (!TkMacOSXSetupDrawingContext(dst, gc, 1, &dc)) {
308 	    return;
309 	}
310 	CGContextRef context = dc.context;
311 	if (context) {
312 	    CGImageRef img = TkMacOSXCreateCGImageWithDrawable(src);
313 	    if (img) {
314 		TkpClipMask *clipPtr = (TkpClipMask *) gc->clip_mask;
315 		unsigned long imageBackground  = gc->background;
316                 if (clipPtr && clipPtr->type == TKP_CLIP_PIXMAP){
317 			CGImageRef mask = TkMacOSXCreateCGImageWithDrawable(clipPtr->value.pixmap);
318 			CGRect rect = CGRectMake(dest_x, dest_y, width, height);
319 			rect = CGRectOffset(rect, dstDraw->xOff, dstDraw->yOff);
320 			CGContextSaveGState(context);
321 			/* Move the origin of the destination to top left. */
322 			CGContextTranslateCTM(context, 0, rect.origin.y + CGRectGetMaxY(rect));
323 			CGContextScaleCTM(context, 1, -1);
324 			/* Fill with the background color, clipping to the mask. */
325 			CGContextClipToMask(context, rect, mask);
326 			TkMacOSXSetColorInContext(gc, gc->background, dc.context);
327 			CGContextFillRect(dc.context, rect);
328 			/* Fill with the foreground color, clipping to the intersection of img and mask. */
329 			CGContextClipToMask(context, rect, img);
330 			TkMacOSXSetColorInContext(gc, gc->foreground, context);
331 			CGContextFillRect(context, rect);
332 			CGContextRestoreGState(context);
333 			CGImageRelease(mask);
334 			CGImageRelease(img);
335 		} else {
336 		    DrawCGImage(dst, gc, dc.context, img, gc->foreground, imageBackground,
337 				CGRectMake(0, 0, srcDraw->size.width, srcDraw->size.height),
338 			    CGRectMake(src_x, src_y, width, height),
339 			    CGRectMake(dest_x, dest_y, width, height));
340 		    CGImageRelease(img);
341 		}
342 	    } else { /* no image */
343 		TkMacOSXDbgMsg("Invalid source drawable");
344 	    }
345 	} else {
346 	    TkMacOSXDbgMsg("Invalid destination drawable - could not get a bitmap context.");
347 	}
348 	TkMacOSXRestoreDrawingContext(&dc);
349     } else { /* source drawable is a window, not a Pixmap */
350 	XCopyArea(display, src, dst, gc, src_x, src_y, width, height, dest_x, dest_y);
351     }
352 }
353 
354 /*
355  *----------------------------------------------------------------------
356  *
357  * TkPutImage --
358  *
359  *	Copies a subimage from an in-memory image to a rectangle of
360  *	of the specified drawable.
361  *
362  * Results:
363  *	None.
364  *
365  * Side effects:
366  *	Draws the image on the specified drawable.
367  *
368  *----------------------------------------------------------------------
369  */
370 
371 int
TkPutImage(unsigned long * colors,int ncolors,Display * display,Drawable d,GC gc,XImage * image,int src_x,int src_y,int dest_x,int dest_y,unsigned int width,unsigned int height)372 TkPutImage(
373     unsigned long *colors,	/* Unused on Macintosh. */
374     int ncolors,			/* Unused on Macintosh. */
375     Display* display,		/* Display. */
376     Drawable d,			/* Drawable to place image on. */
377     GC gc,				/* GC to use. */
378     XImage* image,		/* Image to place. */
379     int src_x,			/* Source X & Y. */
380     int src_y,
381     int dest_x,			/* Destination X & Y. */
382     int dest_y,
383     unsigned int width,	/* Same width & height for both */
384     unsigned int height)	/* distination and source. */
385 {
386     TkMacOSXDrawingContext dc;
387 
388     display->request++;
389     if (!TkMacOSXSetupDrawingContext(d, gc, 1, &dc)) {
390 	return BadDrawable;
391     }
392     if (dc.context) {
393 	CGImageRef img = CreateCGImageWithXImage(image);
394 
395 	if (img) {
396 	    DrawCGImage(d, gc, dc.context, img, gc->foreground, gc->background,
397 		    CGRectMake(0, 0, image->width, image->height),
398 		    CGRectMake(src_x, src_y, width, height),
399 		    CGRectMake(dest_x, dest_y, width, height));
400 	    CFRelease(img);
401 	} else {
402 	    TkMacOSXDbgMsg("Invalid source drawable");
403 	}
404     } else {
405 	TkMacOSXDbgMsg("Invalid destination drawable");
406     }
407     TkMacOSXRestoreDrawingContext(&dc);
408     return Success;
409 }
410 
411 /*
412  *----------------------------------------------------------------------
413  *
414  * CreateCGImageWithXImage --
415  *
416  *	Create CGImage from XImage, copying the image data.
417  *
418  * Results:
419  *	CGImage, release after use.
420  *
421  * Side effects:
422  *	None.
423  *
424  *----------------------------------------------------------------------
425  */
426 
ReleaseData(void * info,const void * data,size_t size)427 static void ReleaseData(void *info, const void *data, size_t size) {
428     ckfree(info);
429 }
430 
431 CGImageRef
CreateCGImageWithXImage(XImage * image)432 CreateCGImageWithXImage(
433     XImage *image)
434 {
435     CGImageRef img = NULL;
436     size_t bitsPerComponent, bitsPerPixel;
437     size_t len = image->bytes_per_line * image->height;
438     const CGFloat *decode = NULL;
439     CGBitmapInfo bitmapInfo;
440     CGDataProviderRef provider = NULL;
441     char *data = NULL;
442     CGDataProviderReleaseDataCallback releaseData = ReleaseData;
443 
444     if (image->bits_per_pixel == 1) {
445 	/*
446 	 * BW image
447 	 */
448 
449 	/* Reverses the sense of the bits */
450 	static const CGFloat decodeWB[2] = {1, 0};
451 	decode = decodeWB;
452 
453 	bitsPerComponent = 1;
454 	bitsPerPixel = 1;
455 	if (image->bitmap_bit_order != MSBFirst) {
456 	    char *srcPtr = image->data + image->xoffset;
457 	    char *endPtr = srcPtr + len;
458 	    char *destPtr = (data = ckalloc(len));
459 
460 	    while (srcPtr < endPtr) {
461 		*destPtr++ = xBitReverseTable[(unsigned char)(*(srcPtr++))];
462 	    }
463 	} else {
464 	    data = memcpy(ckalloc(len), image->data + image->xoffset, len);
465 	}
466 	if (data) {
467 	    provider = CGDataProviderCreateWithData(data, data, len, releaseData);
468 	}
469 	if (provider) {
470 	    img = CGImageMaskCreate(image->width, image->height, bitsPerComponent,
471 				    bitsPerPixel, image->bytes_per_line, provider, decode, 0);
472 	}
473     } else if (image->format == ZPixmap && image->bits_per_pixel == 32) {
474 	/*
475 	 * Color image
476 	 */
477 
478 	CGColorSpaceRef colorspace = CGColorSpaceCreateWithName(kCGColorSpaceSRGB);
479 
480 	bitsPerComponent = 8;
481 	bitsPerPixel = 32;
482 	bitmapInfo = (image->byte_order == MSBFirst ?
483 		kCGBitmapByteOrder32Big : kCGBitmapByteOrder32Little) |
484 	    kCGImageAlphaNoneSkipFirst;
485 	data = memcpy(ckalloc(len), image->data + image->xoffset, len);
486 	if (data) {
487 	    provider = CGDataProviderCreateWithData(data, data, len, releaseData);
488 	}
489 	if (provider) {
490 	    img = CGImageCreate(image->width, image->height, bitsPerComponent,
491 		    bitsPerPixel, image->bytes_per_line, colorspace, bitmapInfo,
492 		    provider, decode, 0, kCGRenderingIntentDefault);
493 	    CFRelease(provider);
494 	}
495 	if (colorspace) {
496 	    CFRelease(colorspace);
497 	}
498     } else {
499 	TkMacOSXDbgMsg("Unsupported image type");
500     }
501     return img;
502 }
503 
504 /*
505  *----------------------------------------------------------------------
506  *
507  * TkMacOSXCreateCGImageWithDrawable --
508  *
509  *	Create a CGImage from the given Drawable.
510  *
511  * Results:
512  *	CGImage, release after use.
513  *
514  * Side effects:
515  *	None.
516  *
517  *----------------------------------------------------------------------
518  */
519 
520 CGImageRef
TkMacOSXCreateCGImageWithDrawable(Drawable drawable)521 TkMacOSXCreateCGImageWithDrawable(
522     Drawable drawable)
523 {
524     CGImageRef img = NULL;
525     CGContextRef context = GetCGContextForDrawable(drawable);
526 
527     if (context) {
528 	img = CGBitmapContextCreateImage(context);
529     }
530     return img;
531 }
532 
533 /*
534  *----------------------------------------------------------------------
535  *
536  * CreateNSImageWithPixmap --
537  *
538  *	Create NSImage for Pixmap.
539  *
540  * Results:
541  *	NSImage.
542  *
543  * Side effects:
544  *	None.
545  *
546  *----------------------------------------------------------------------
547  */
548 
549 static NSImage*
CreateNSImageWithPixmap(Pixmap pixmap,int width,int height)550 CreateNSImageWithPixmap(
551     Pixmap pixmap,
552     int width,
553     int height)
554 {
555     CGImageRef cgImage;
556     NSImage *nsImage;
557     NSBitmapImageRep *bitmapImageRep;
558 
559     cgImage = TkMacOSXCreateCGImageWithDrawable(pixmap);
560     nsImage = [[NSImage alloc] initWithSize:NSMakeSize(width, height)];
561     bitmapImageRep = [[NSBitmapImageRep alloc] initWithCGImage:cgImage];
562     [nsImage addRepresentation:bitmapImageRep];
563     [bitmapImageRep release];
564     CFRelease(cgImage);
565 
566     return nsImage;
567 }
568 
569 /*
570  *----------------------------------------------------------------------
571  *
572  * TkMacOSXGetNSImageWithTkImage --
573  *
574  *	Get autoreleased NSImage for Tk_Image.
575  *
576  * Results:
577  *	NSImage.
578  *
579  * Side effects:
580  *	None.
581  *
582  *----------------------------------------------------------------------
583  */
584 
585 NSImage*
TkMacOSXGetNSImageWithTkImage(Display * display,Tk_Image image,int width,int height)586 TkMacOSXGetNSImageWithTkImage(
587     Display *display,
588     Tk_Image image,
589     int width,
590     int height)
591 {
592     Pixmap pixmap = Tk_GetPixmap(display, None, width, height, 0);
593     NSImage *nsImage;
594 
595     Tk_RedrawImage(image, 0, 0, width, height, pixmap, 0, 0);
596     nsImage = CreateNSImageWithPixmap(pixmap, width, height);
597     Tk_FreePixmap(display, pixmap);
598 
599     return [nsImage autorelease];
600 }
601 
602 /*
603  *----------------------------------------------------------------------
604  *
605  * TkMacOSXGetNSImageWithBitmap --
606  *
607  *	Get autoreleased NSImage for Bitmap.
608  *
609  * Results:
610  *	NSImage.
611  *
612  * Side effects:
613  *	None.
614  *
615  *----------------------------------------------------------------------
616  */
617 
618 NSImage*
TkMacOSXGetNSImageWithBitmap(Display * display,Pixmap bitmap,GC gc,int width,int height)619 TkMacOSXGetNSImageWithBitmap(
620     Display *display,
621     Pixmap bitmap,
622     GC gc,
623     int width,
624     int height)
625 {
626     Pixmap pixmap = Tk_GetPixmap(display, None, width, height, 0);
627     NSImage *nsImage;
628 
629     unsigned long origBackground = gc->background;
630 
631     gc->background = TRANSPARENT_PIXEL << 24;
632     XSetClipOrigin(display, gc, 0, 0);
633     XCopyPlane(display, bitmap, pixmap, gc, 0, 0, width, height, 0, 0, 1);
634     gc->background = origBackground;
635     nsImage = CreateNSImageWithPixmap(pixmap, width, height);
636     Tk_FreePixmap(display, pixmap);
637 
638     return [nsImage autorelease];
639 }
640 
641 /*
642  *----------------------------------------------------------------------
643  *
644  * GetCGContextForDrawable --
645  *
646  *	Get CGContext for given Drawable, creating one if necessary.
647  *
648  * Results:
649  *	CGContext.
650  *
651  * Side effects:
652  *	None.
653  *
654  *----------------------------------------------------------------------
655  */
656 
657 CGContextRef
GetCGContextForDrawable(Drawable d)658 GetCGContextForDrawable(
659     Drawable d)
660 {
661     MacDrawable *macDraw = (MacDrawable *) d;
662 
663     if (macDraw && (macDraw->flags & TK_IS_PIXMAP) && !macDraw->context) {
664 	const size_t bitsPerComponent = 8;
665 	size_t bitsPerPixel, bytesPerRow, len;
666 	CGColorSpaceRef colorspace = NULL;
667 	CGBitmapInfo bitmapInfo =
668 #ifdef __LITTLE_ENDIAN__
669 	kCGBitmapByteOrder32Host;
670 #else
671 	kCGBitmapByteOrderDefault;
672 #endif
673 	char *data;
674 	CGRect bounds = CGRectMake(0, 0, macDraw->size.width, macDraw->size.height);
675 
676 	if (macDraw->flags & TK_IS_BW_PIXMAP) {
677 	    bitsPerPixel = 8;
678 	    bitmapInfo = (CGBitmapInfo)kCGImageAlphaOnly;
679 	} else {
680 	    colorspace = CGColorSpaceCreateWithName(kCGColorSpaceGenericRGB);
681 	    bitsPerPixel = 32;
682 	    bitmapInfo |= kCGImageAlphaPremultipliedFirst;
683 	}
684 	bytesPerRow = ((size_t) macDraw->size.width * bitsPerPixel + 127) >> 3
685 		& ~15;
686 	len = macDraw->size.height * bytesPerRow;
687 	data = ckalloc(len);
688 	bzero(data, len);
689 	macDraw->context = CGBitmapContextCreate(data, macDraw->size.width,
690 		macDraw->size.height, bitsPerComponent, bytesPerRow,
691 		colorspace, bitmapInfo);
692 	if (macDraw->context) {
693 	    CGContextClearRect(macDraw->context, bounds);
694 	}
695 	if (colorspace) {
696 	    CFRelease(colorspace);
697 	}
698     }
699 
700     return (macDraw ? macDraw->context : NULL);
701 }
702 
703 /*
704  *----------------------------------------------------------------------
705  *
706  * DrawCGImage --
707  *
708  *	Draw CG image into drawable.
709  *
710  * Results:
711  *	None.
712  *
713  * Side effects:
714  *	None.
715  *
716  *----------------------------------------------------------------------
717  */
718 
719 void
DrawCGImage(Drawable d,GC gc,CGContextRef context,CGImageRef image,unsigned long imageForeground,unsigned long imageBackground,CGRect imageBounds,CGRect srcBounds,CGRect dstBounds)720 DrawCGImage(
721     Drawable d,
722     GC gc,
723     CGContextRef context,
724     CGImageRef image,
725     unsigned long imageForeground,
726     unsigned long imageBackground,
727     CGRect imageBounds,
728     CGRect srcBounds,
729     CGRect dstBounds)
730 {
731     MacDrawable *macDraw = (MacDrawable *) d;
732 
733     if (macDraw && context && image) {
734 	CGImageRef subImage = NULL;
735 
736 	if (!CGRectEqualToRect(imageBounds, srcBounds)) {
737 	    if (!CGRectContainsRect(imageBounds, srcBounds)) {
738 		TkMacOSXDbgMsg("Mismatch of sub CGImage bounds");
739 	    }
740 	    subImage = CGImageCreateWithImageInRect(image, CGRectOffset(
741 		    srcBounds, -imageBounds.origin.x, -imageBounds.origin.y));
742 	    if (subImage) {
743 		image = subImage;
744 	    }
745 	}
746 	dstBounds = CGRectOffset(dstBounds, macDraw->xOff, macDraw->yOff);
747 
748 	if (CGImageIsMask(image)) {
749 	    /*CGContextSaveGState(context);*/
750 	    if (macDraw->flags & TK_IS_BW_PIXMAP) {
751 		/* Set fill color to black, background comes from the context, or is transparent. */
752 		if (imageBackground != TRANSPARENT_PIXEL << 24) {
753 		    CGContextClearRect(context, dstBounds);
754 		}
755 		CGContextSetRGBFillColor(context, 0.0, 0.0, 0.0, 1.0);
756 	    } else {
757 		if (imageBackground != TRANSPARENT_PIXEL << 24) {
758 		    TkMacOSXSetColorInContext(gc, imageBackground, context);
759 		    CGContextFillRect(context, dstBounds);
760 		}
761 		TkMacOSXSetColorInContext(gc, imageForeground, context);
762 	    }
763 	}
764 
765 #ifdef TK_MAC_DEBUG_IMAGE_DRAWING
766 	CGContextSaveGState(context);
767 	CGContextSetLineWidth(context, 1.0);
768 	CGContextSetRGBStrokeColor(context, 0, 0, 0, 0.1);
769 	CGContextSetRGBFillColor(context, 0, 1, 0, 0.1);
770 	CGContextFillRect(context, dstBounds);
771 	CGContextStrokeRect(context, dstBounds);
772 	CGPoint p[4] = {dstBounds.origin,
773 	    CGPointMake(CGRectGetMaxX(dstBounds), CGRectGetMaxY(dstBounds)),
774 	    CGPointMake(CGRectGetMinX(dstBounds), CGRectGetMaxY(dstBounds)),
775 	    CGPointMake(CGRectGetMaxX(dstBounds), CGRectGetMinY(dstBounds))
776 	};
777 	CGContextStrokeLineSegments(context, p, 4);
778 	CGContextRestoreGState(context);
779 	TkMacOSXDbgMsg("Drawing CGImage at (x=%f, y=%f), (w=%f, h=%f)",
780 		dstBounds.origin.x, dstBounds.origin.y,
781 		dstBounds.size.width, dstBounds.size.height);
782 #else /* TK_MAC_DEBUG_IMAGE_DRAWING */
783 	CGContextSaveGState(context);
784 	CGContextTranslateCTM(context, 0, dstBounds.origin.y + CGRectGetMaxY(dstBounds));
785 	CGContextScaleCTM(context, 1, -1);
786 	CGContextDrawImage(context, dstBounds, image);
787 	CGContextRestoreGState(context);
788 #endif /* TK_MAC_DEBUG_IMAGE_DRAWING */
789 	/*if (CGImageIsMask(image)) {
790 	    CGContextRestoreGState(context);
791 	}*/
792 	if (subImage) {
793 	    CFRelease(subImage);
794 	}
795     } else {
796 	TkMacOSXDbgMsg("Drawing of empty CGImage requested");
797     }
798 }
799 
800 /*
801  *----------------------------------------------------------------------
802  *
803  * XDrawLines --
804  *
805  *	Draw connected lines.
806  *
807  * Results:
808  *	None.
809  *
810  * Side effects:
811  *	Renders a series of connected lines.
812  *
813  *----------------------------------------------------------------------
814  */
815 
816 int
XDrawLines(Display * display,Drawable d,GC gc,XPoint * points,int npoints,int mode)817 XDrawLines(
818     Display *display,		/* Display. */
819     Drawable d,			/* Draw on this. */
820     GC gc,			/* Use this GC. */
821     XPoint *points,		/* Array of points. */
822     int npoints,		/* Number of points. */
823     int mode)			/* Line drawing mode. */
824 {
825     MacDrawable *macWin = (MacDrawable *) d;
826     TkMacOSXDrawingContext dc;
827     int i, lw = gc->line_width;
828 
829     if (npoints < 2) {
830 	return BadValue;
831     }
832 
833     display->request++;
834     if (!TkMacOSXSetupDrawingContext(d, gc, 1, &dc)) {
835 	return BadDrawable;
836     }
837     if (dc.context) {
838 	double prevx, prevy;
839 	double o = (lw % 2) ? .5 : 0;
840 
841 	CGContextBeginPath(dc.context);
842 	prevx = macWin->xOff + points[0].x + o;
843 	prevy = macWin->yOff + points[0].y + o;
844 	CGContextMoveToPoint(dc.context, prevx, prevy);
845 	for (i = 1; i < npoints; i++) {
846 	    if (mode == CoordModeOrigin) {
847 		CGContextAddLineToPoint(dc.context,
848 			macWin->xOff + points[i].x + o,
849 			macWin->yOff + points[i].y + o);
850 	    } else {
851 		prevx += points[i].x;
852 		prevy += points[i].y;
853 		CGContextAddLineToPoint(dc.context, prevx, prevy);
854 	    }
855 	}
856 	CGContextStrokePath(dc.context);
857     }
858     TkMacOSXRestoreDrawingContext(&dc);
859     return Success;
860 }
861 
862 /*
863  *----------------------------------------------------------------------
864  *
865  * XDrawSegments --
866  *
867  *	Draw unconnected lines.
868  *
869  * Results:
870  *	None.
871  *
872  * Side effects:
873  *	Renders a series of unconnected lines.
874  *
875  *----------------------------------------------------------------------
876  */
877 
878 void
XDrawSegments(Display * display,Drawable d,GC gc,XSegment * segments,int nsegments)879 XDrawSegments(
880     Display *display,
881     Drawable d,
882     GC gc,
883     XSegment *segments,
884     int nsegments)
885 {
886     MacDrawable *macWin = (MacDrawable *) d;
887     TkMacOSXDrawingContext dc;
888     int i, lw = gc->line_width;
889 
890     display->request++;
891     if (!TkMacOSXSetupDrawingContext(d, gc, 1, &dc)) {
892 	return;
893     }
894     if (dc.context) {
895 	double o = (lw % 2) ? .5 : 0;
896 
897 	for (i = 0; i < nsegments; i++) {
898 	    CGContextBeginPath(dc.context);
899 	    CGContextMoveToPoint(dc.context,
900 		    macWin->xOff + segments[i].x1 + o,
901 		    macWin->yOff + segments[i].y1 + o);
902 	    CGContextAddLineToPoint(dc.context,
903 		    macWin->xOff + segments[i].x2 + o,
904 		    macWin->yOff + segments[i].y2 + o);
905 	    CGContextStrokePath(dc.context);
906 	}
907     }
908     TkMacOSXRestoreDrawingContext(&dc);
909 }
910 
911 /*
912  *----------------------------------------------------------------------
913  *
914  * XFillPolygon --
915  *
916  *	Draws a filled polygon.
917  *
918  * Results:
919  *	None.
920  *
921  * Side effects:
922  *	Draws a filled polygon on the specified drawable.
923  *
924  *----------------------------------------------------------------------
925  */
926 
927 void
XFillPolygon(Display * display,Drawable d,GC gc,XPoint * points,int npoints,int shape,int mode)928 XFillPolygon(
929     Display* display,		/* Display. */
930     Drawable d,			/* Draw on this. */
931     GC gc,			/* Use this GC. */
932     XPoint* points,		/* Array of points. */
933     int npoints,		/* Number of points. */
934     int shape,			/* Shape to draw. */
935     int mode)			/* Drawing mode. */
936 {
937     MacDrawable *macWin = (MacDrawable *) d;
938     TkMacOSXDrawingContext dc;
939     int i;
940 
941     display->request++;
942     if (!TkMacOSXSetupDrawingContext(d, gc, 1, &dc)) {
943 	return;
944     }
945     if (dc.context) {
946 	double prevx, prevy;
947 	double o = (gc->line_width % 2) ? .5 : 0;
948 
949 	CGContextBeginPath(dc.context);
950 	prevx = macWin->xOff + points[0].x + o;
951 	prevy = macWin->yOff + points[0].y + o;
952 	CGContextMoveToPoint(dc.context, prevx, prevy);
953 	for (i = 1; i < npoints; i++) {
954 	    if (mode == CoordModeOrigin) {
955 		CGContextAddLineToPoint(dc.context,
956 			macWin->xOff + points[i].x + o,
957 			macWin->yOff + points[i].y + o);
958 	    } else {
959 		prevx += points[i].x;
960 		prevy += points[i].y;
961 		CGContextAddLineToPoint(dc.context, prevx, prevy);
962 	    }
963 	}
964 	CGContextEOFillPath(dc.context);
965     }
966     TkMacOSXRestoreDrawingContext(&dc);
967 }
968 
969 /*
970  *----------------------------------------------------------------------
971  *
972  * XDrawRectangle --
973  *
974  *	Draws a rectangle.
975  *
976  * Results:
977  *	None.
978  *
979  * Side effects:
980  *	Draws a rectangle on the specified drawable.
981  *
982  *----------------------------------------------------------------------
983  */
984 
985 void
XDrawRectangle(Display * display,Drawable d,GC gc,int x,int y,unsigned int width,unsigned int height)986 XDrawRectangle(
987     Display *display,		/* Display. */
988     Drawable d,			/* Draw on this. */
989     GC gc,			/* Use this GC. */
990     int x, int y,		/* Upper left corner. */
991     unsigned int width,		/* Width & height of rect. */
992     unsigned int height)
993 {
994     MacDrawable *macWin = (MacDrawable *) d;
995     TkMacOSXDrawingContext dc;
996     int lw = gc->line_width;
997 
998     if (width == 0 || height == 0) {
999 	return;
1000     }
1001 
1002     display->request++;
1003     if (!TkMacOSXSetupDrawingContext(d, gc, 1, &dc)) {
1004 	return;
1005     }
1006     if (dc.context) {
1007 	CGRect rect;
1008 	double o = (lw % 2) ? .5 : 0;
1009 
1010 	rect = CGRectMake(
1011 		macWin->xOff + x + o,
1012 		macWin->yOff + y + o,
1013 		width, height);
1014 	CGContextStrokeRect(dc.context, rect);
1015     }
1016     TkMacOSXRestoreDrawingContext(&dc);
1017 }
1018 
1019 #ifdef TK_MACOSXDRAW_UNUSED
1020 /*
1021  *----------------------------------------------------------------------
1022  *
1023  * XDrawRectangles --
1024  *
1025  *	Draws the outlines of the specified rectangles as if a
1026  *	five-point PolyLine protocol request were specified for each
1027  *	rectangle:
1028  *
1029  *	    [x,y] [x+width,y] [x+width,y+height] [x,y+height] [x,y]
1030  *
1031  *	For the specified rectangles, these functions do not draw a
1032  *	pixel more than once. XDrawRectangles draws the rectangles in
1033  *	the order listed in the array. If rectangles intersect, the
1034  *	intersecting pixels are drawn multiple times. Draws a
1035  *	rectangle.
1036  *
1037  * Results:
1038  *	None.
1039  *
1040  * Side effects:
1041  *	Draws rectangles on the specified drawable.
1042  *
1043  *----------------------------------------------------------------------
1044  */
1045 
1046 void
XDrawRectangles(Display * display,Drawable drawable,GC gc,XRectangle * rectArr,int nRects)1047 XDrawRectangles(
1048     Display *display,
1049     Drawable drawable,
1050     GC gc,
1051     XRectangle *rectArr,
1052     int nRects)
1053 {
1054     MacDrawable *macWin = (MacDrawable *) drawable;
1055     TkMacOSXDrawingContext dc;
1056     XRectangle * rectPtr;
1057     int i, lw = gc->line_width;
1058 
1059     display->request++;
1060     if (!TkMacOSXSetupDrawingContext(d, gc, 1, &dc)) {
1061 	return;
1062     }
1063     if (dc.context) {
1064 	CGRect rect;
1065 	double o = (lw % 2) ? .5 : 0;
1066 
1067 	for (i = 0, rectPtr = rectArr; i < nRects; i++, rectPtr++) {
1068 	    if (rectPtr->width == 0 || rectPtr->height == 0) {
1069 		continue;
1070 	    }
1071 	    rect = CGRectMake(
1072 		    macWin->xOff + rectPtr->x + o,
1073 		    macWin->yOff + rectPtr->y + o,
1074 		    rectPtr->width, rectPtr->height);
1075 	    CGContextStrokeRect(dc.context, rect);
1076 	}
1077     }
1078     TkMacOSXRestoreDrawingContext(&dc);
1079 }
1080 #endif
1081 
1082 /*
1083  *----------------------------------------------------------------------
1084  *
1085  * XFillRectangles --
1086  *
1087  *	Fill multiple rectangular areas in the given drawable.
1088  *
1089  * Results:
1090  *	None.
1091  *
1092  * Side effects:
1093  *	Draws onto the specified drawable.
1094  *
1095  *----------------------------------------------------------------------
1096  */
1097 
1098 int
XFillRectangles(Display * display,Drawable d,GC gc,XRectangle * rectangles,int n_rectangles)1099 XFillRectangles(
1100     Display* display,		/* Display. */
1101     Drawable d,			/* Draw on this. */
1102     GC gc,			/* Use this GC. */
1103     XRectangle *rectangles,	/* Rectangle array. */
1104     int n_rectangles)		/* Number of rectangles. */
1105 {
1106     MacDrawable *macWin = (MacDrawable *) d;
1107     TkMacOSXDrawingContext dc;
1108     XRectangle * rectPtr;
1109     int i;
1110 
1111     display->request++;
1112     if (!TkMacOSXSetupDrawingContext(d, gc, 1, &dc)) {
1113 	return BadDrawable;
1114     }
1115     if (dc.context) {
1116 	CGRect rect;
1117 
1118 	for (i = 0, rectPtr = rectangles; i < n_rectangles; i++, rectPtr++) {
1119 	    if (rectPtr->width == 0 || rectPtr->height == 0) {
1120 		continue;
1121 	    }
1122 	    rect = CGRectMake(
1123 		    macWin->xOff + rectPtr->x,
1124 		    macWin->yOff + rectPtr->y,
1125 		    rectPtr->width, rectPtr->height);
1126 	    CGContextFillRect(dc.context, rect);
1127 	}
1128     }
1129     TkMacOSXRestoreDrawingContext(&dc);
1130     return Success;
1131 }
1132 
1133 /*
1134  *----------------------------------------------------------------------
1135  *
1136  * XDrawArc --
1137  *
1138  *	Draw an arc.
1139  *
1140  * Results:
1141  *	None.
1142  *
1143  * Side effects:
1144  *	Draws an arc on the specified drawable.
1145  *
1146  *----------------------------------------------------------------------
1147  */
1148 
1149 void
XDrawArc(Display * display,Drawable d,GC gc,int x,int y,unsigned int width,unsigned int height,int angle1,int angle2)1150 XDrawArc(
1151     Display* display,		/* Display. */
1152     Drawable d,			/* Draw on this. */
1153     GC gc,			/* Use this GC. */
1154     int x, int y,		/* Upper left of bounding rect. */
1155     unsigned int width,		/* Width & height. */
1156     unsigned int height,
1157     int angle1,			/* Staring angle of arc. */
1158     int angle2)			/* Extent of arc. */
1159 {
1160     MacDrawable *macWin = (MacDrawable *) d;
1161     TkMacOSXDrawingContext dc;
1162     int lw = gc->line_width;
1163 
1164     if (width == 0 || height == 0 || angle2 == 0) {
1165 	return;
1166     }
1167 
1168     display->request++;
1169     if (!TkMacOSXSetupDrawingContext(d, gc, 1, &dc)) {
1170 	return;
1171     }
1172     if (dc.context) {
1173 	CGRect rect;
1174 	double o = (lw % 2) ? .5 : 0;
1175 
1176 	rect = CGRectMake(
1177 		macWin->xOff + x + o,
1178 		macWin->yOff + y + o,
1179 		width, height);
1180 	if (angle1 == 0 && angle2 == 23040) {
1181 	    CGContextStrokeEllipseInRect(dc.context, rect);
1182 	} else {
1183 	    CGMutablePathRef p = CGPathCreateMutable();
1184 	    CGAffineTransform t = CGAffineTransformIdentity;
1185 	    CGPoint c = CGPointMake(CGRectGetMidX(rect), CGRectGetMidY(rect));
1186 	    double w = CGRectGetWidth(rect);
1187 
1188 	    if (width != height) {
1189 		t = CGAffineTransformMakeScale(1.0, CGRectGetHeight(rect)/w);
1190 		c = CGPointApplyAffineTransform(c, CGAffineTransformInvert(t));
1191 	    }
1192 	    CGPathAddArc(p, &t, c.x, c.y, w/2, radians(-angle1/64.0),
1193 		    radians(-(angle1 + angle2)/64.0), angle2 > 0);
1194 	    CGContextAddPath(dc.context, p);
1195 	    CGPathRelease(p);
1196 	    CGContextStrokePath(dc.context);
1197 	}
1198     }
1199     TkMacOSXRestoreDrawingContext(&dc);
1200 }
1201 
1202 #ifdef TK_MACOSXDRAW_UNUSED
1203 /*
1204  *----------------------------------------------------------------------
1205  *
1206  * XDrawArcs --
1207  *
1208  *	Draws multiple circular or elliptical arcs. Each arc is
1209  *	specified by a rectangle and two angles. The center of the
1210  *	circle or ellipse is the center of the rect- angle, and the
1211  *	major and minor axes are specified by the width and height.
1212  *	Positive angles indicate counterclock- wise motion, and
1213  *	negative angles indicate clockwise motion. If the magnitude
1214  *	of angle2 is greater than 360 degrees, XDrawArcs truncates it
1215  *	to 360 degrees.
1216  *
1217  * Results:
1218  *	None.
1219  *
1220  * Side effects:
1221  *	Draws an arc for each array element on the specified drawable.
1222  *
1223  *----------------------------------------------------------------------
1224  */
1225 
1226 void
XDrawArcs(Display * display,Drawable d,GC gc,XArc * arcArr,int nArcs)1227 XDrawArcs(
1228     Display *display,
1229     Drawable d,
1230     GC gc,
1231     XArc *arcArr,
1232     int nArcs)
1233 {
1234 
1235     MacDrawable *macWin = (MacDrawable *) d;
1236     TkMacOSXDrawingContext dc;
1237     XArc *arcPtr;
1238     int i, lw = gc->line_width;
1239 
1240     display->request++;
1241     if (!TkMacOSXSetupDrawingContext(d, gc, 1, &dc)) {
1242 	return;
1243     }
1244     if (dc.context) {
1245 	CGRect rect;
1246 	double o = (lw % 2) ? .5 : 0;
1247 
1248 	for (i=0, arcPtr = arcArr; i < nArcs; i++, arcPtr++) {
1249 	    if (arcPtr->width == 0 || arcPtr->height == 0
1250 		    || arcPtr->angle2 == 0) {
1251 		continue;
1252 	    }
1253 	    rect = CGRectMake(
1254 		    macWin->xOff + arcPtr->x + o,
1255 		    macWin->yOff + arcPtr->y + o,
1256 		    arcPtr->width, arcPtr->height);
1257 
1258 	    if (arcPtr->angle1 == 0 && arcPtr->angle2 == 23040) {
1259 		CGContextStrokeEllipseInRect(dc.context, rect);
1260 	    } else {
1261 		CGMutablePathRef p = CGPathCreateMutable();
1262 		CGAffineTransform t = CGAffineTransformIdentity;
1263 		CGPoint c = CGPointMake(CGRectGetMidX(rect),
1264 			CGRectGetMidY(rect));
1265 		double w = CGRectGetWidth(rect);
1266 
1267 		if (arcPtr->width != arcPtr->height) {
1268 		    t = CGAffineTransformMakeScale(1, CGRectGetHeight(rect)/w);
1269 		    c = CGPointApplyAffineTransform(c,
1270 			    CGAffineTransformInvert(t));
1271 		}
1272 		CGPathAddArc(p, &t, c.x, c.y, w/2,
1273 			radians(-arcPtr->angle1/64.0),
1274 			radians(-(arcPtr->angle1 + arcPtr->angle2)/64.0),
1275 			arcPtr->angle2 > 0);
1276 		CGContextAddPath(dc.context, p);
1277 		CGPathRelease(p);
1278 		CGContextStrokePath(dc.context);
1279 	    }
1280 	}
1281     }
1282     TkMacOSXRestoreDrawingContext(&dc);
1283 }
1284 #endif
1285 
1286 /*
1287  *----------------------------------------------------------------------
1288  *
1289  * XFillArc --
1290  *
1291  *	Draw a filled arc.
1292  *
1293  * Results:
1294  *	None.
1295  *
1296  * Side effects:
1297  *	Draws a filled arc on the specified drawable.
1298  *
1299  *----------------------------------------------------------------------
1300  */
1301 
1302 void
XFillArc(Display * display,Drawable d,GC gc,int x,int y,unsigned int width,unsigned int height,int angle1,int angle2)1303 XFillArc(
1304     Display* display,		/* Display. */
1305     Drawable d,			/* Draw on this. */
1306     GC gc,			/* Use this GC. */
1307     int x, int y,		/* Upper left of bounding rect. */
1308     unsigned int width,		/* Width & height. */
1309     unsigned int height,
1310     int angle1,			/* Staring angle of arc. */
1311     int angle2)			/* Extent of arc. */
1312 {
1313     MacDrawable *macWin = (MacDrawable *) d;
1314     TkMacOSXDrawingContext dc;
1315     int lw = gc->line_width;
1316 
1317     if (width == 0 || height == 0 || angle2 == 0) {
1318 	return;
1319     }
1320 
1321     display->request++;
1322     if (!TkMacOSXSetupDrawingContext(d, gc, 1, &dc)) {
1323 	return;
1324     }
1325     if (dc.context) {
1326 	CGRect rect;
1327 	double o = (lw % 2) ? .5 : 0, u = 0;
1328 
1329 	if (notAA(lw)) {
1330 	    o += NON_AA_CG_OFFSET/2;
1331 	    u += NON_AA_CG_OFFSET;
1332 	}
1333 	rect = CGRectMake(
1334 		macWin->xOff + x + o,
1335 		macWin->yOff + y + o,
1336 		width - u, height - u);
1337 
1338 	if (angle1 == 0 && angle2 == 23040) {
1339 	    CGContextFillEllipseInRect(dc.context, rect);
1340 	} else {
1341 	    CGMutablePathRef p = CGPathCreateMutable();
1342 	    CGAffineTransform t = CGAffineTransformIdentity;
1343 	    CGPoint c = CGPointMake(CGRectGetMidX(rect), CGRectGetMidY(rect));
1344 	    double w = CGRectGetWidth(rect);
1345 
1346 	    if (width != height) {
1347 		t = CGAffineTransformMakeScale(1, CGRectGetHeight(rect)/w);
1348 		c = CGPointApplyAffineTransform(c, CGAffineTransformInvert(t));
1349 	    }
1350 	    if (gc->arc_mode == ArcPieSlice) {
1351 		CGPathMoveToPoint(p, &t, c.x, c.y);
1352 	    }
1353 	    CGPathAddArc(p, &t, c.x, c.y, w/2, radians(-angle1/64.0),
1354 		    radians(-(angle1 + angle2)/64.0), angle2 > 0);
1355 	    CGPathCloseSubpath(p);
1356 	    CGContextAddPath(dc.context, p);
1357 	    CGPathRelease(p);
1358 	    CGContextFillPath(dc.context);
1359 	}
1360     }
1361     TkMacOSXRestoreDrawingContext(&dc);
1362 }
1363 
1364 #ifdef TK_MACOSXDRAW_UNUSED
1365 /*
1366  *----------------------------------------------------------------------
1367  *
1368  * XFillArcs --
1369  *
1370  *	Draw a filled arc.
1371  *
1372  * Results:
1373  *	None.
1374  *
1375  * Side effects:
1376  *	Draws a filled arc for each array element on the specified drawable.
1377  *
1378  *----------------------------------------------------------------------
1379  */
1380 
1381 void
XFillArcs(Display * display,Drawable d,GC gc,XArc * arcArr,int nArcs)1382 XFillArcs(
1383     Display *display,
1384     Drawable d,
1385     GC gc,
1386     XArc *arcArr,
1387     int nArcs)
1388 {
1389     MacDrawable *macWin = (MacDrawable *) d;
1390     TkMacOSXDrawingContext dc;
1391     XArc * arcPtr;
1392     int i, lw = gc->line_width;
1393 
1394     display->request++;
1395     if (!TkMacOSXSetupDrawingContext(d, gc, 1, &dc)) {
1396 	return;
1397     }
1398     if (dc.context) {
1399 	CGRect rect;
1400 	double o = (lw % 2) ? .5 : 0, u = 0;
1401 
1402 	if (notAA(lw)) {
1403 	    o += NON_AA_CG_OFFSET/2;
1404 	    u += NON_AA_CG_OFFSET;
1405 	}
1406 	for (i = 0, arcPtr = arcArr; i < nArcs; i++, arcPtr++) {
1407 	    if (arcPtr->width == 0 || arcPtr->height == 0
1408 		    || arcPtr->angle2 == 0) {
1409 		continue;
1410 	    }
1411 	    rect = CGRectMake(
1412 		    macWin->xOff + arcPtr->x + o,
1413 		    macWin->yOff + arcPtr->y + o,
1414 		    arcPtr->width - u, arcPtr->height - u);
1415 	    if (arcPtr->angle1 == 0 && arcPtr->angle2 == 23040) {
1416 		CGContextFillEllipseInRect(dc.context, rect);
1417 	    } else {
1418 		CGMutablePathRef p = CGPathCreateMutable();
1419 		CGAffineTransform t = CGAffineTransformIdentity;
1420 		CGPoint c = CGPointMake(CGRectGetMidX(rect),
1421 			CGRectGetMidY(rect));
1422 		double w = CGRectGetWidth(rect);
1423 
1424 		if (arcPtr->width != arcPtr->height) {
1425 		    t = CGAffineTransformMakeScale(1, CGRectGetHeight(rect)/w);
1426 		    c = CGPointApplyAffineTransform(c,
1427 			    CGAffineTransformInvert(t));
1428 		}
1429 		if (gc->arc_mode == ArcPieSlice) {
1430 		    CGPathMoveToPoint(p, &t, c.x, c.y);
1431 		}
1432 		CGPathAddArc(p, &t, c.x, c.y, w/2,
1433 			radians(-arcPtr->angle1/64.0),
1434 			radians(-(arcPtr->angle1 + arcPtr->angle2)/64.0),
1435 			arcPtr->angle2 > 0);
1436 		CGPathCloseSubpath(p);
1437 		CGContextAddPath(dc.context, p);
1438 		CGPathRelease(p);
1439 		CGContextFillPath(dc.context);
1440 	    }
1441 	}
1442     }
1443     TkMacOSXRestoreDrawingContext(&dc);
1444 }
1445 #endif
1446 
1447 #ifdef TK_MACOSXDRAW_UNUSED
1448 /*
1449  *----------------------------------------------------------------------
1450  *
1451  * XMaxRequestSize --
1452  *
1453  *----------------------------------------------------------------------
1454  */
1455 
1456 long
XMaxRequestSize(Display * display)1457 XMaxRequestSize(
1458     Display *display)
1459 {
1460     return (SHRT_MAX / 4);
1461 }
1462 #endif
1463 
1464 /*
1465  *----------------------------------------------------------------------
1466  *
1467  * TkScrollWindow --
1468  *
1469  *	Scroll a rectangle of the specified window and accumulate
1470  *	a damage region.
1471  *
1472  * Results:
1473  *	Returns 0 if the scroll genereated no additional damage.
1474  *	Otherwise, sets the region that needs to be repainted after
1475  *	scrolling and returns 1.
1476  *
1477  * Side effects:
1478  *	Scrolls the bits in the window.
1479  *
1480  *----------------------------------------------------------------------
1481  */
1482 
1483 int
TkScrollWindow(Tk_Window tkwin,GC gc,int x,int y,int width,int height,int dx,int dy,TkRegion damageRgn)1484 TkScrollWindow(
1485     Tk_Window tkwin,		/* The window to be scrolled. */
1486     GC gc,			/* GC for window to be scrolled. */
1487     int x, int y,		/* Position rectangle to be scrolled. */
1488     int width, int height,
1489     int dx, int dy,		/* Distance rectangle should be moved. */
1490     TkRegion damageRgn)		/* Region to accumulate damage in. */
1491 {
1492     Drawable drawable = Tk_WindowId(tkwin);
1493     MacDrawable *macDraw = (MacDrawable *) drawable;
1494     TKContentView *view = (TKContentView *)TkMacOSXDrawableView(macDraw);
1495     CGRect srcRect, dstRect;
1496     HIShapeRef dmgRgn = NULL, extraRgn = NULL;
1497     NSRect bounds, visRect, scrollSrc, scrollDst;
1498     int result = 0;
1499 
1500     if ( view ) {
1501   	/*  Get the scroll area in NSView coordinates (origin at bottom left). */
1502   	bounds = [view bounds];
1503  	scrollSrc = NSMakeRect(
1504 			       macDraw->xOff + x,
1505 			       bounds.size.height - height - (macDraw->yOff + y),
1506 			       width, height);
1507  	scrollDst = NSOffsetRect(scrollSrc, dx, -dy);
1508 
1509   	/* Limit scrolling to the window content area. */
1510  	visRect = [view visibleRect];
1511  	scrollSrc = NSIntersectionRect(scrollSrc, visRect);
1512  	scrollDst = NSIntersectionRect(scrollDst, visRect);
1513  	if ( !NSIsEmptyRect(scrollSrc) && !NSIsEmptyRect(scrollDst) ) {
1514 
1515   	    /*
1516   	     * Mark the difference between source and destination as damaged.
1517 	     * This region is described in NSView coordinates (y=0 at the bottom)
1518 	     * and converted to Tk coordinates later.
1519   	     */
1520 
1521 	    srcRect = CGRectMake(x, y, width, height);
1522 	    dstRect = CGRectOffset(srcRect, dx, dy);
1523 
1524 	    /* Expand the rectangles slightly to avoid degeneracies. */
1525 	    srcRect.origin.y -= 1;
1526 	    srcRect.size.height += 2;
1527 	    dstRect.origin.y += 1;
1528 	    dstRect.size.height -= 2;
1529 
1530 	    /* Compute the damage. */
1531   	    dmgRgn = HIShapeCreateMutableWithRect(&srcRect);
1532  	    extraRgn = HIShapeCreateWithRect(&dstRect);
1533  	    ChkErr(HIShapeDifference, dmgRgn, extraRgn, (HIMutableShapeRef) dmgRgn);
1534 	    result = HIShapeIsEmpty(dmgRgn) ? 0 : 1;
1535 
1536 	    /* Convert to Tk coordinates. */
1537 	    TkMacOSXSetWithNativeRegion(damageRgn, dmgRgn);
1538 	    if (extraRgn) {
1539 		CFRelease(extraRgn);
1540 	    }
1541 
1542  	    /* Scroll the rectangle. */
1543  	    [view scrollRect:scrollSrc by:NSMakeSize(dx, -dy)];
1544 
1545 	    /* Shift the Tk children which meet the source rectangle. */
1546 	    TkWindow *winPtr = (TkWindow *)tkwin;
1547 	    TkWindow *childPtr;
1548 	    CGRect childBounds;
1549 	    for (childPtr = winPtr->childList; childPtr != NULL; childPtr = childPtr->nextPtr) {
1550 		if (Tk_IsMapped(childPtr) && !Tk_IsTopLevel(childPtr)) {
1551 		    TkMacOSXWinCGBounds(childPtr, &childBounds);
1552 		    if (CGRectIntersectsRect(srcRect, childBounds)) {
1553 			MacDrawable *macChild = childPtr->privatePtr;
1554 			if (macChild) {
1555 			    macChild->yOff += dy;
1556 			    macChild->xOff += dx;
1557 			    childPtr->changes.y = macChild->yOff;
1558 			    childPtr->changes.x = macChild->xOff;
1559 			}
1560 		    }
1561 		}
1562 	    }
1563 
1564 	    /* Queue up Expose events for the damage region. */
1565 	    int oldMode = Tcl_SetServiceMode(TCL_SERVICE_NONE);
1566 	    [view generateExposeEvents:dmgRgn childrenOnly:1];
1567 	    Tcl_SetServiceMode(oldMode);
1568 
1569 	    /* Belt and suspenders: make the AppKit request a redraw
1570 	       when it gets control again. */
1571   	}
1572     } else {
1573 	dmgRgn = HIShapeCreateEmpty();
1574 	TkMacOSXSetWithNativeRegion(damageRgn, dmgRgn);
1575     }
1576 
1577     if (dmgRgn) {
1578 	CFRelease(dmgRgn);
1579     }
1580     return result;
1581 }
1582 
1583 /*
1584  *----------------------------------------------------------------------
1585  *
1586  * TkMacOSXSetUpGraphicsPort --
1587  *
1588  *	Set up the graphics port from the given GC.
1589  *
1590  * Results:
1591  *	None.
1592  *
1593  * Side effects:
1594  *	None.
1595  *
1596  *----------------------------------------------------------------------
1597  */
1598 
1599 void
TkMacOSXSetUpGraphicsPort(GC gc,void * destPort)1600 TkMacOSXSetUpGraphicsPort(
1601     GC gc,			/* GC to apply to current port. */
1602     void *destPort)
1603 {
1604     Tcl_Panic("TkMacOSXSetUpGraphicsPort: Obsolete, no more QD!");
1605 }
1606 
1607 
1608 /*
1609  *----------------------------------------------------------------------
1610  *
1611  * TkMacOSXSetUpDrawingContext --
1612  *
1613  *	Set up a drawing context for the given drawable and GC.
1614  *
1615  * Results:
1616  *	Boolean indicating whether it is ok to draw; if false, drawing
1617  *	context was not setup, so do not attempt to draw and do not call
1618  *	TkMacOSXRestoreDrawingContext().
1619  *
1620  * Side effects:
1621  *	None.
1622  *
1623  *----------------------------------------------------------------------
1624  */
1625 
1626 int
TkMacOSXSetupDrawingContext(Drawable d,GC gc,int useCG,TkMacOSXDrawingContext * dcPtr)1627 TkMacOSXSetupDrawingContext(
1628     Drawable d,
1629     GC gc,
1630     int useCG, /* advisory only ! */
1631     TkMacOSXDrawingContext *dcPtr)
1632 {
1633     MacDrawable *macDraw = ((MacDrawable*)d);
1634     int dontDraw = 0, isWin = 0;
1635     TkMacOSXDrawingContext dc = {};
1636     CGRect clipBounds;
1637 
1638     dc.clipRgn = TkMacOSXGetClipRgn(d);
1639     if (!dontDraw) {
1640 	ClipToGC(d, gc, &dc.clipRgn);
1641 	dontDraw = dc.clipRgn ? HIShapeIsEmpty(dc.clipRgn) : 0;
1642     }
1643     if (dontDraw) {
1644 	goto end;
1645     }
1646     if (useCG) {
1647 	dc.context = GetCGContextForDrawable(d);
1648     }
1649     if (!dc.context || !(macDraw->flags & TK_IS_PIXMAP)) {
1650 	isWin = (TkMacOSXDrawableWindow(d) != nil);
1651     }
1652     if (dc.context) {
1653 	dc.portBounds = clipBounds = CGContextGetClipBoundingBox(dc.context);
1654     } else if (isWin) {
1655 	NSView *view = TkMacOSXDrawableView(macDraw);
1656 	if (view) {
1657 	    if (view != [NSView focusView]) {
1658 		dc.focusLocked = [view lockFocusIfCanDraw];
1659 		dontDraw = !dc.focusLocked;
1660 	    } else {
1661 		dontDraw = ![view canDraw];
1662 	    }
1663 	    if (dontDraw) {
1664 		goto end;
1665 	    }
1666 	    [[view window] disableFlushWindow];
1667 	    dc.view = view;
1668 	    dc.context = [[NSGraphicsContext currentContext] graphicsPort];
1669 	    dc.portBounds = NSRectToCGRect([view bounds]);
1670 	    if (dc.clipRgn) {
1671 		clipBounds = CGContextGetClipBoundingBox(dc.context);
1672 	    }
1673 	} else {
1674 	    Tcl_Panic("TkMacOSXSetupDrawingContext(): "
1675 		    "no NSView to draw into !");
1676 	}
1677     } else {
1678 	Tcl_Panic("TkMacOSXSetupDrawingContext(): "
1679 		"no context to draw into !");
1680     }
1681     if (dc.context) {
1682 	CGAffineTransform t = { .a = 1, .b = 0, .c = 0, .d = -1, .tx = 0,
1683 		.ty = dc.portBounds.size.height};
1684 	dc.portBounds.origin.x += macDraw->xOff;
1685 	dc.portBounds.origin.y += macDraw->yOff;
1686 	if (!dc.focusLocked) {
1687 	    CGContextSaveGState(dc.context);
1688 	}
1689 	CGContextSetTextDrawingMode(dc.context, kCGTextFill);
1690 	CGContextConcatCTM(dc.context, t);
1691 	if (dc.clipRgn) {
1692 #ifdef TK_MAC_DEBUG_DRAWING
1693 	    CGContextSaveGState(dc.context);
1694 	    ChkErr(HIShapeReplacePathInCGContext, dc.clipRgn, dc.context);
1695 	    CGContextSetRGBFillColor(dc.context, 1.0, 0.0, 0.0, 0.1);
1696 	    CGContextEOFillPath(dc.context);
1697 	    CGContextRestoreGState(dc.context);
1698 #endif /* TK_MAC_DEBUG_DRAWING */
1699 	    CGRect r;
1700 	    if (!HIShapeIsRectangular(dc.clipRgn) || !CGRectContainsRect(
1701 		    *HIShapeGetBounds(dc.clipRgn, &r),
1702 		    CGRectApplyAffineTransform(clipBounds, t))) {
1703 		ChkErr(HIShapeReplacePathInCGContext, dc.clipRgn, dc.context);
1704 		CGContextEOClip(dc.context);
1705 	    }
1706 	}
1707 	if (gc) {
1708 	    static const CGLineCap cgCap[] = {
1709 		[CapNotLast] = kCGLineCapButt,
1710 		[CapButt] = kCGLineCapButt,
1711 		[CapRound] = kCGLineCapRound,
1712 		[CapProjecting] = kCGLineCapSquare,
1713 	    };
1714 	    static const CGLineJoin cgJoin[] = {
1715 		[JoinMiter] = kCGLineJoinMiter,
1716 		[JoinRound] = kCGLineJoinRound,
1717 		[JoinBevel] = kCGLineJoinBevel,
1718 	    };
1719 	    bool shouldAntialias;
1720 	    double w = gc->line_width;
1721 
1722 	    TkMacOSXSetColorInContext(gc, gc->foreground, dc.context);
1723 	    if (isWin) {
1724 		CGContextSetPatternPhase(dc.context, CGSizeMake(
1725 			dc.portBounds.size.width, dc.portBounds.size.height));
1726 	    }
1727 	    if(gc->function != GXcopy) {
1728 		TkMacOSXDbgMsg("Logical functions other than GXcopy are "
1729 			"not supported for CG drawing!");
1730 	    }
1731 	    /* When should we antialias? */
1732 	    shouldAntialias = !notAA(gc->line_width);
1733 	    if (!shouldAntialias) {
1734 		/* Make non-antialiased CG drawing look more like X11 */
1735 		w -= (gc->line_width ? NON_AA_CG_OFFSET : 0);
1736 	    }
1737 	    CGContextSetShouldAntialias(dc.context, shouldAntialias);
1738 	    CGContextSetLineWidth(dc.context, w);
1739 	    if (gc->line_style != LineSolid) {
1740 		int num = 0;
1741 		char *p = &(gc->dashes);
1742 		CGFloat dashOffset = gc->dash_offset;
1743 		CGFloat lengths[10];
1744 
1745 		while (p[num] != '\0' && num < 10) {
1746 		    lengths[num] = p[num];
1747 		    num++;
1748 		}
1749 		CGContextSetLineDash(dc.context, dashOffset, lengths, num);
1750 	    }
1751 	    if ((unsigned)gc->cap_style < sizeof(cgCap)/sizeof(CGLineCap)) {
1752 		CGContextSetLineCap(dc.context,
1753 			cgCap[(unsigned)gc->cap_style]);
1754 	    }
1755 	    if ((unsigned)gc->join_style < sizeof(cgJoin)/sizeof(CGLineJoin)) {
1756 		CGContextSetLineJoin(dc.context,
1757 			cgJoin[(unsigned)gc->join_style]);
1758 	    }
1759 	}
1760     }
1761 end:
1762     if (dontDraw && dc.clipRgn) {
1763 	CFRelease(dc.clipRgn);
1764 	dc.clipRgn = NULL;
1765     }
1766     *dcPtr = dc;
1767     return !dontDraw;
1768 }
1769 
1770 /*
1771  *----------------------------------------------------------------------
1772  *
1773  * TkMacOSXRestoreDrawingContext --
1774  *
1775  *	Restore drawing context.
1776  *
1777  * Results:
1778  *	None.
1779  *
1780  * Side effects:
1781  *	None.
1782  *
1783  *----------------------------------------------------------------------
1784  */
1785 
1786 void
TkMacOSXRestoreDrawingContext(TkMacOSXDrawingContext * dcPtr)1787 TkMacOSXRestoreDrawingContext(
1788     TkMacOSXDrawingContext *dcPtr)
1789 {
1790     if (dcPtr->context) {
1791 	CGContextSynchronize(dcPtr->context);
1792 	[[dcPtr->view window] setViewsNeedDisplay:YES];
1793 	[[dcPtr->view window] enableFlushWindow];
1794 	if (dcPtr->focusLocked) {
1795 	    [dcPtr->view unlockFocus];
1796 	} else {
1797 	    CGContextRestoreGState(dcPtr->context);
1798 	}
1799     }
1800     if (dcPtr->clipRgn) {
1801 	CFRelease(dcPtr->clipRgn);
1802     }
1803 #ifdef TK_MAC_DEBUG
1804     bzero(dcPtr, sizeof(TkMacOSXDrawingContext));
1805 #endif /* TK_MAC_DEBUG */
1806 }
1807 
1808 /*
1809  *----------------------------------------------------------------------
1810  *
1811  * TkMacOSXGetClipRgn --
1812  *
1813  *	Get the clipping region needed to restrict drawing to the given
1814  *	drawable.
1815  *
1816  * Results:
1817  *	Clipping region. If non-NULL, CFRelease it when done.
1818  *
1819  * Side effects:
1820  *	None.
1821  *
1822  *----------------------------------------------------------------------
1823  */
1824 
1825 HIShapeRef
TkMacOSXGetClipRgn(Drawable drawable)1826 TkMacOSXGetClipRgn(
1827     Drawable drawable)		/* Drawable. */
1828 {
1829     MacDrawable *macDraw = (MacDrawable *) drawable;
1830     HIShapeRef clipRgn = NULL;
1831 
1832     if (macDraw->winPtr && macDraw->flags & TK_CLIP_INVALID) {
1833 	TkMacOSXUpdateClipRgn(macDraw->winPtr);
1834 #ifdef TK_MAC_DEBUG_DRAWING
1835 	TkMacOSXDbgMsg("%s", macDraw->winPtr->pathName);
1836 	NSView *view = TkMacOSXDrawableView(macDraw);
1837 	if ([view lockFocusIfCanDraw]) {
1838 	    CGContextRef context = [[NSGraphicsContext currentContext] graphicsPort];
1839 	    CGContextSaveGState(context);
1840 	    CGContextConcatCTM(context, CGAffineTransformMake(1.0, 0.0, 0.0,
1841 		    -1.0, 0.0, [view bounds].size.height));
1842 	    ChkErr(HIShapeReplacePathInCGContext, macDraw->visRgn, context);
1843 	    CGContextSetRGBFillColor(context, 0.0, 1.0, 0.0, 0.1);
1844 	    CGContextEOFillPath(context);
1845 	    CGContextRestoreGState(context);
1846 	    [view unlockFocus];
1847 	}
1848 #endif /* TK_MAC_DEBUG_DRAWING */
1849     }
1850 
1851     if (macDraw->drawRgn) {
1852 	clipRgn = HIShapeCreateCopy(macDraw->drawRgn);
1853     } else if (macDraw->visRgn) {
1854 	clipRgn = HIShapeCreateCopy(macDraw->visRgn);
1855     }
1856     return clipRgn;
1857 }
1858 
1859 /*
1860  *----------------------------------------------------------------------
1861  *
1862  * TkMacOSXSetUpClippingRgn --
1863  *
1864  *	Set up the clipping region so that drawing only occurs on the
1865  *	specified X subwindow.
1866  *
1867  * Results:
1868  *	None.
1869  *
1870  * Side effects:
1871  *	None.
1872  *
1873  *----------------------------------------------------------------------
1874  */
1875 
1876 void
TkMacOSXSetUpClippingRgn(Drawable drawable)1877 TkMacOSXSetUpClippingRgn(
1878     Drawable drawable)		/* Drawable to update. */
1879 {
1880 }
1881 
1882 /*
1883  *----------------------------------------------------------------------
1884  *
1885  * TkpClipDrawableToRect --
1886  *
1887  *	Clip all drawing into the drawable d to the given rectangle.
1888  *	If width or height are negative, reset to no clipping.
1889  *
1890  * Results:
1891  *	None.
1892  *
1893  * Side effects:
1894  *	Subsequent drawing into d is offset and clipped as specified.
1895  *
1896  *----------------------------------------------------------------------
1897  */
1898 
1899 void
TkpClipDrawableToRect(Display * display,Drawable d,int x,int y,int width,int height)1900 TkpClipDrawableToRect(
1901     Display *display,
1902     Drawable d,
1903     int x, int y,
1904     int width, int height)
1905 {
1906     MacDrawable *macDraw = (MacDrawable *) d;
1907     NSView *view = TkMacOSXDrawableView(macDraw);
1908 
1909     if (macDraw->drawRgn) {
1910 	CFRelease(macDraw->drawRgn);
1911 	macDraw->drawRgn = NULL;
1912     }
1913 
1914     if (width >= 0 && height >= 0) {
1915 	CGRect clipRect = CGRectMake(x + macDraw->xOff, y + macDraw->yOff,
1916 		width, height);
1917 	HIShapeRef drawRgn = HIShapeCreateWithRect(&clipRect);
1918 
1919 	if (macDraw->winPtr && macDraw->flags & TK_CLIP_INVALID) {
1920 	    TkMacOSXUpdateClipRgn(macDraw->winPtr);
1921 	}
1922 	if (macDraw->visRgn) {
1923 	    macDraw->drawRgn = HIShapeCreateIntersection(macDraw->visRgn,
1924 		    drawRgn);
1925 	    CFRelease(drawRgn);
1926 	} else {
1927 	    macDraw->drawRgn = drawRgn;
1928 	}
1929 	if (view && view != [NSView focusView] && [view lockFocusIfCanDraw]) {
1930 	    clipRect.origin.y = [view bounds].size.height -
1931 		    (clipRect.origin.y + clipRect.size.height);
1932 	    NSRectClip(NSRectFromCGRect(clipRect));
1933 	    macDraw->flags |= TK_FOCUSED_VIEW;
1934 	}
1935     } else {
1936 	if (view && (macDraw->flags & TK_FOCUSED_VIEW)) {
1937 	    [view unlockFocus];
1938 	    macDraw->flags &= ~TK_FOCUSED_VIEW;
1939 	}
1940     }
1941 }
1942 
1943 /*
1944  *----------------------------------------------------------------------
1945  *
1946  * ClipToGC --
1947  *
1948  *	Helper function to intersect given region with gc clip region.
1949  *
1950  * Results:
1951  *	None.
1952  *
1953  * Side effects:
1954  *	None.
1955  *
1956  *----------------------------------------------------------------------
1957  */
1958 
1959 static void
ClipToGC(Drawable d,GC gc,HIShapeRef * clipRgnPtr)1960 ClipToGC(
1961     Drawable d,
1962     GC gc,
1963     HIShapeRef *clipRgnPtr) /* must point to initialized variable */
1964 {
1965     if (gc && gc->clip_mask &&
1966 	    ((TkpClipMask*)gc->clip_mask)->type == TKP_CLIP_REGION) {
1967 	TkRegion gcClip = ((TkpClipMask*)gc->clip_mask)->value.region;
1968 	int xOffset = ((MacDrawable *) d)->xOff + gc->clip_x_origin;
1969 	int yOffset = ((MacDrawable *) d)->yOff + gc->clip_y_origin;
1970 	HIShapeRef clipRgn = *clipRgnPtr, gcClipRgn;
1971 
1972 	TkMacOSXOffsetRegion(gcClip, xOffset, yOffset);
1973 	gcClipRgn = TkMacOSXGetNativeRegion(gcClip);
1974 	if (clipRgn) {
1975 	    *clipRgnPtr = HIShapeCreateIntersection(gcClipRgn, clipRgn);
1976 	    CFRelease(clipRgn);
1977 	} else {
1978 	    *clipRgnPtr = HIShapeCreateCopy(gcClipRgn);
1979 	}
1980 	CFRelease(gcClipRgn);
1981 	TkMacOSXOffsetRegion(gcClip, -xOffset, -yOffset);
1982     }
1983 }
1984 
1985 /*
1986  *----------------------------------------------------------------------
1987  *
1988  * TkMacOSXMakeStippleMap --
1989  *
1990  *	Given a drawable and a stipple pattern this function draws the
1991  *	pattern repeatedly over the drawable. The drawable can then
1992  *	be used as a mask for bit-bliting a stipple pattern over an
1993  *	object.
1994  *
1995  * Results:
1996  *	A BitMap data structure.
1997  *
1998  * Side effects:
1999  *	None.
2000  *
2001  *----------------------------------------------------------------------
2002  */
2003 
2004 void *
TkMacOSXMakeStippleMap(Drawable drawable,Drawable stipple)2005 TkMacOSXMakeStippleMap(
2006     Drawable drawable,		/* Window to apply stipple. */
2007     Drawable stipple)		/* The stipple pattern. */
2008 {
2009     return NULL;
2010 }
2011 
2012 /*
2013  *----------------------------------------------------------------------
2014  *
2015  * TkpDrawHighlightBorder --
2016  *
2017  *	This procedure draws a rectangular ring around the outside of
2018  *	a widget to indicate that it has received the input focus.
2019  *
2020  *	On the Macintosh, this puts a 1 pixel border in the bgGC color
2021  *	between the widget and the focus ring, except in the case where
2022  *	highlightWidth is 1, in which case the border is left out.
2023  *
2024  *	For proper Mac L&F, use highlightWidth of 3.
2025  *
2026  * Results:
2027  *	None.
2028  *
2029  * Side effects:
2030  *	A rectangle "width" pixels wide is drawn in "drawable",
2031  *	corresponding to the outer area of "tkwin".
2032  *
2033  *----------------------------------------------------------------------
2034  */
2035 
2036 void
TkpDrawHighlightBorder(Tk_Window tkwin,GC fgGC,GC bgGC,int highlightWidth,Drawable drawable)2037 TkpDrawHighlightBorder (
2038     Tk_Window tkwin,
2039     GC fgGC,
2040     GC bgGC,
2041     int highlightWidth,
2042     Drawable drawable)
2043 {
2044     if (highlightWidth == 1) {
2045 	TkDrawInsetFocusHighlight (tkwin, fgGC, highlightWidth, drawable, 0);
2046     } else {
2047 	TkDrawInsetFocusHighlight (tkwin, bgGC, highlightWidth, drawable, 0);
2048 	if (fgGC != bgGC) {
2049 	    TkDrawInsetFocusHighlight (tkwin, fgGC, highlightWidth - 1,
2050 		    drawable, 0);
2051 	}
2052     }
2053 }
2054 
2055 /*
2056  *----------------------------------------------------------------------
2057  *
2058  * TkpDrawFrame --
2059  *
2060  *	This procedure draws the rectangular frame area. If the user
2061  *	has requested themeing, it draws with the background theme.
2062  *
2063  * Results:
2064  *	None.
2065  *
2066  * Side effects:
2067  *	Draws inside the tkwin area.
2068  *
2069  *----------------------------------------------------------------------
2070  */
2071 
2072 void
TkpDrawFrame(Tk_Window tkwin,Tk_3DBorder border,int highlightWidth,int borderWidth,int relief)2073 TkpDrawFrame(
2074     Tk_Window tkwin,
2075     Tk_3DBorder border,
2076     int highlightWidth,
2077     int borderWidth,
2078     int relief)
2079 {
2080     if (useThemedToplevel && Tk_IsTopLevel(tkwin)) {
2081 	static Tk_3DBorder themedBorder = NULL;
2082 
2083 	if (!themedBorder) {
2084 	    themedBorder = Tk_Get3DBorder(NULL, tkwin,
2085 		    "systemWindowHeaderBackground");
2086 	}
2087 	if (themedBorder) {
2088 	    border = themedBorder;
2089 	}
2090     }
2091 
2092     Tk_Fill3DRectangle(tkwin, Tk_WindowId(tkwin),
2093 	    border, highlightWidth, highlightWidth,
2094 	    Tk_Width(tkwin) - 2 * highlightWidth,
2095 	    Tk_Height(tkwin) - 2 * highlightWidth,
2096 	    borderWidth, relief);
2097 }
2098 
2099 /*
2100  * Local Variables:
2101  * mode: objc
2102  * c-basic-offset: 4
2103  * fill-column: 79
2104  * coding: utf-8
2105  * End:
2106  */
2107