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