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