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