summaryrefslogtreecommitdiffstats
path: root/macosx/tkMacOSXImage.c
diff options
context:
space:
mode:
Diffstat (limited to 'macosx/tkMacOSXImage.c')
-rw-r--r--macosx/tkMacOSXImage.c654
1 files changed, 481 insertions, 173 deletions
diff --git a/macosx/tkMacOSXImage.c b/macosx/tkMacOSXImage.c
index 07a20ac..0df23d9 100644
--- a/macosx/tkMacOSXImage.c
+++ b/macosx/tkMacOSXImage.c
@@ -6,7 +6,7 @@
* Copyright (c) 1995-1997 Sun Microsystems, Inc.
* Copyright 2001-2009, Apple Inc.
* Copyright (c) 2005-2009 Daniel A. Steffen <das@users.sourceforge.net>
- * Copyright 2017-2018 Marc Culler.
+ * Copyright (c) 2017-2020 Marc Culler.
*
* See the file "license.terms" for information on usage and redistribution
* of this file, and for a DISCLAIMER OF ALL WARRANTIES.
@@ -15,14 +15,16 @@
#include "tkMacOSXPrivate.h"
#include "xbytes.h"
+static CGImageRef CreateCGImageFromPixmap(Drawable pixmap);
+static CGImageRef CreateCGImageFromDrawableRect( Drawable drawable,
+ int x, int y, unsigned int width, unsigned int height);
+
#pragma mark XImage handling
int
_XInitImageFuncPtrs(
- XImage *image)
+ TCL_UNUSED(XImage *)) /* image */
{
- (void)image;
-
return 0;
}
@@ -43,10 +45,11 @@ _XInitImageFuncPtrs(
*----------------------------------------------------------------------
*/
-static void ReleaseData(void *info, const void *data, size_t size) {
- (void)data;
- (void)size;
-
+static void ReleaseData(
+ void *info,
+ TCL_UNUSED(const void *), /* data */
+ TCL_UNUSED(size_t)) /* size */
+{
ckfree(info);
}
@@ -136,142 +139,6 @@ TkMacOSXCreateCGImageWithXImage(
/*
*----------------------------------------------------------------------
*
- * XGetImage --
- *
- * This function copies data from a pixmap or window into an XImage. It
- * is essentially never used. At one time it was called by
- * pTkImgPhotoDisplay, but that is no longer the case. Currently it is
- * called two places, one of which is requesting an XY image which we do
- * not support. It probably does not work correctly -- see the comments
- * for TkMacOSXBitmapRepFromDrawableRect.
- *
- * Results:
- * Returns a newly allocated XImage containing the data from the given
- * rectangle of the given drawable, or NULL if the XImage could not be
- * constructed. NOTE: If we are copying from a window on a Retina
- * display, the dimensions of the XImage will be 2*width x 2*height.
- *
- * Side effects:
- * None.
- *
- *----------------------------------------------------------------------
- */
-struct pixel_fmt {int r; int g; int b; int a;};
-static struct pixel_fmt bgra = {2, 1, 0, 3};
-static struct pixel_fmt abgr = {3, 2, 1, 0};
-
-XImage *
-XGetImage(
- Display *display,
- Drawable drawable,
- int x,
- int y,
- unsigned int width,
- unsigned int height,
- unsigned long plane_mask,
- int format)
-{
- NSBitmapImageRep* bitmap_rep = NULL;
- NSUInteger bitmap_fmt = 0;
- XImage* imagePtr = NULL;
- char* bitmap = NULL;
- char R, G, B, A;
- int depth = 32, offset = 0, bitmap_pad = 0;
- unsigned int bytes_per_row, size, row, n, m;
- unsigned int scalefactor=1, scaled_height=height, scaled_width=width;
- NSWindow *win = TkMacOSXDrawableWindow(drawable);
- static enum {unknown, no, yes} has_retina = unknown;
- (void)plane_mask;
-
- if (win && has_retina == unknown) {
-#ifdef __clang__
- has_retina = [win respondsToSelector:@selector(backingScaleFactor)] ?
- yes : no;
-#else
- has_retina = no;
-#endif
- }
-
- if (has_retina == yes) {
- /*
- * We only allow scale factors 1 or 2, as Apple currently does.
- */
-
-#ifdef __clang__
- scalefactor = [win backingScaleFactor] == 2.0 ? 2 : 1;
-#endif
- scaled_height *= scalefactor;
- scaled_width *= scalefactor;
- }
-
- if (format == ZPixmap) {
- if (width == 0 || height == 0) {
- return NULL;
- }
-
- bitmap_rep = TkMacOSXBitmapRepFromDrawableRect(drawable,
- x, y, width, height);
- if (!bitmap_rep) {
- TkMacOSXDbgMsg("XGetImage: Failed to construct NSBitmapRep");
- return NULL;
- }
- bitmap_fmt = [bitmap_rep bitmapFormat];
- size = [bitmap_rep bytesPerPlane];
- bytes_per_row = [bitmap_rep bytesPerRow];
- bitmap = (char *)ckalloc(size);
- if (!bitmap
- || (bitmap_fmt != 0 && bitmap_fmt != 1)
- || [bitmap_rep samplesPerPixel] != 4
- || [bitmap_rep isPlanar] != 0
- || bytes_per_row < 4 * scaled_width
- || size != bytes_per_row * scaled_height) {
- TkMacOSXDbgMsg("XGetImage: Unrecognized bitmap format");
- CFRelease(bitmap_rep);
- return NULL;
- }
- memcpy(bitmap, (char *)[bitmap_rep bitmapData], size);
- CFRelease(bitmap_rep);
-
- /*
- * When Apple extracts a bitmap from an NSView, it may be in either
- * BGRA or ABGR format. For an XImage we need RGBA.
- */
-
- struct pixel_fmt pixel = bitmap_fmt == 0 ? bgra : abgr;
-
- for (row = 0, n = 0; row < scaled_height; row++, n += bytes_per_row) {
- for (m = n; m < n + 4*scaled_width; m += 4) {
- R = *(bitmap + m + pixel.r);
- G = *(bitmap + m + pixel.g);
- B = *(bitmap + m + pixel.b);
- A = *(bitmap + m + pixel.a);
-
- *(bitmap + m) = R;
- *(bitmap + m + 1) = G;
- *(bitmap + m + 2) = B;
- *(bitmap + m + 3) = A;
- }
- }
- imagePtr = XCreateImage(display, NULL, depth, format, offset,
- (char*) bitmap, scaled_width, scaled_height,
- bitmap_pad, bytes_per_row);
- if (scalefactor == 2) {
- imagePtr->pixelpower = 1;
- }
- } else {
- /*
- * There are some calls to XGetImage in the generic Tk code which pass
- * an XYPixmap rather than a ZPixmap. XYPixmaps should be handled
- * here.
- */
- TkMacOSXDbgMsg("XGetImage does not handle XYPixmaps at the moment.");
- }
- return imagePtr;
-}
-
-/*
- *----------------------------------------------------------------------
- *
* DestroyImage --
*
* Destroys storage associated with an image.
@@ -306,7 +173,11 @@ DestroyImage(
* Get a single pixel from an image.
*
* Results:
- * Returns the 32 bit pixel value.
+ * The XColor structure contains an unsigned long field named pixel which
+ * identifies the color. This function returns the unsigned long that
+ * would be used as the pixel value of an XColor that has the same red
+ * green and blue components as the XImage pixel at the specified
+ * location.
*
* Side effects:
* None.
@@ -322,13 +193,18 @@ ImageGetPixel(
{
unsigned char r = 0, g = 0, b = 0;
+ /*
+ * Compute 8 bit red green and blue values, which are passed as inputs to
+ * TkMacOSXRGBPixel to produce the pixel value.
+ */
+
if (image && image->data) {
unsigned char *srcPtr = ((unsigned char*) image->data)
+ (y * image->bytes_per_line)
+ (((image->xoffset + x) * image->bits_per_pixel) / NBBY);
switch (image->bits_per_pixel) {
- case 32:
+ case 32: /* 8 bits per channel */
r = (*((unsigned int*) srcPtr) >> 16) & 0xff;
g = (*((unsigned int*) srcPtr) >> 8) & 0xff;
b = (*((unsigned int*) srcPtr) ) & 0xff;
@@ -338,12 +214,12 @@ ImageGetPixel(
r = srcPtr[1]; g = srcPtr[2]; b = srcPtr[3];
}*/
break;
- case 16:
+ case 16: /* 5 bits per channel */
r = (*((unsigned short*) srcPtr) >> 7) & 0xf8;
g = (*((unsigned short*) srcPtr) >> 2) & 0xf8;
b = (*((unsigned short*) srcPtr) << 3) & 0xf8;
break;
- case 8:
+ case 8: /* 2 bits per channel */
r = (*srcPtr << 2) & 0xc0;
g = (*srcPtr << 4) & 0xc0;
b = (*srcPtr << 6) & 0xc0;
@@ -351,7 +227,7 @@ ImageGetPixel(
g |= g >> 2 | g >> 4 | g >> 6;
b |= b >> 2 | b >> 4 | b >> 6;
break;
- case 4: {
+ case 4: { /* 1 bit per channel */
unsigned char c = (x % 2) ? *srcPtr : (*srcPtr >> 4);
r = (c & 0x04) ? 0xff : 0;
@@ -359,12 +235,13 @@ ImageGetPixel(
b = (c & 0x01) ? 0xff : 0;
break;
}
- case 1:
+ case 1: /* Black-white bitmap. */
r = g = b = ((*srcPtr) & (0x80 >> (x % 8))) ? 0xff : 0;
break;
}
}
- return (PIXEL_MAGIC << 24) | (r << 16) | (g << 8) | b;
+
+ return TkMacOSXRGBPixel(r, g, b);
}
/*
@@ -446,7 +323,7 @@ ImagePutPixel(
XImage *
XCreateImage(
Display* display,
- Visual* visual,
+ TCL_UNUSED(Visual*), /* visual */
unsigned int depth,
int format,
int offset,
@@ -457,10 +334,9 @@ XCreateImage(
int bytes_per_line)
{
XImage *ximage;
- (void)visual;
display->request++;
- ximage = (XImage *)ckalloc(sizeof(XImage));
+ ximage = ckalloc(sizeof(XImage));
ximage->height = height;
ximage->width = width;
@@ -470,13 +346,6 @@ XCreateImage(
ximage->data = data;
ximage->obdata = NULL;
- /*
- * The default pixelpower is 0. This must be explicitly set to 1 in the
- * case of an XImage extracted from a Retina display.
- */
-
- ximage->pixelpower = 0;
-
if (format == ZPixmap) {
ximage->bits_per_pixel = 32;
ximage->bitmap_unit = 32;
@@ -552,10 +421,10 @@ XPutImage(
unsigned int height) /* distination and source. */
{
TkMacOSXDrawingContext dc;
- MacDrawable *macDraw = (MacDrawable *) drawable;
+ MacDrawable *macDraw = (MacDrawable *)drawable;
display->request++;
- if (!TkMacOSXSetupDrawingContext(drawable, gc, 1, &dc)) {
+ if (!TkMacOSXSetupDrawingContext(drawable, gc, &dc)) {
return BadDrawable;
}
if (dc.context) {
@@ -571,17 +440,8 @@ XPutImage(
}
if (img) {
- /*
- * If the XImage has big pixels, the source is rescaled to reflect
- * the actual pixel dimensions. This is not currently used, but
- * could arise if the image were copied from a retina monitor and
- * redrawn on an ordinary monitor.
- */
-
- int pp = image->pixelpower;
-
bounds = CGRectMake(0, 0, image->width, image->height);
- srcRect = CGRectMake(src_x<<pp, src_y<<pp, width<<pp, height<<pp);
+ srcRect = CGRectMake(src_x, src_y, width, height);
dstRect = CGRectMake(dest_x, dest_y, width, height);
TkMacOSXDrawCGImage(drawable, gc, dc.context,
img, gc->foreground, gc->background,
@@ -598,6 +458,454 @@ XPutImage(
}
/*
+ *----------------------------------------------------------------------
+ *
+ * CreateCGImageFromDrawableRect
+ *
+ * Extract image data from a MacOSX drawable as a CGImage.
+ *
+ * This is only called by XGetImage and XCopyArea. The Tk core uses
+ * these functions on some platforms, but on macOS the core does not
+ * call them with a source drawable which is a window. Such calls are
+ * used only for double-buffered drawing. Since macOS defines the
+ * macro TK_NO_DOUBLE_BUFFERING, the generic code never calls XGetImage
+ * or XCopyArea on macOS. Nonetheless, these function are in the stubs
+ * table and therefore could be used by extensions.
+ *
+ * This implementation does not work correctly. Originally it relied on
+ * [NSBitmapImageRep initWithFocusedViewRect:view_rect] which was
+ * deprecated by Apple in OSX 10.14 and also required the use of other
+ * deprecated functions such as [NSView lockFocus]. Apple's suggested
+ * replacement is [NSView cacheDisplayInRect: toBitmapImageRep:] and that
+ * is what is being used here. However, that method only works when the
+ * view has a valid CGContext, and a view is only guaranteed to have a
+ * valid context during a call to [NSView drawRect]. To further complicate
+ * matters, cacheDisplayInRect calls [NSView drawRect]. Essentially it is
+ * asking the view to draw a subrectangle of itself using a special
+ * graphics context which is linked to the BitmapImageRep. But our
+ * implementation of [NSView drawRect] does not allow recursive calls. If
+ * called recursively it returns immediately without doing any drawing.
+ * So the bottom line is that this function either returns a NULL pointer
+ * or a black image. To make it useful would require a significant amount
+ * of rewriting of the drawRect method. Perhaps the next release of OSX
+ * will include some more helpful ways of doing this.
+ *
+ * Results:
+ * Returns an NSBitmapRep representing the image of the given rectangle of
+ * the given drawable. This object is retained. The caller is responsible
+ * for releasing it.
+ *
+ * NOTE: The x,y coordinates should be relative to a coordinate system
+ * with origin at the top left, as used by XImage and CGImage, not bottom
+ * left as used by NSView.
+ *
+ * Side effects:
+ * None
+ *
+ *----------------------------------------------------------------------
+ */
+
+static CGImageRef
+CreateCGImageFromDrawableRect(
+ Drawable drawable,
+ int x,
+ int y,
+ unsigned int width,
+ unsigned int height)
+{
+ MacDrawable *mac_drawable = (MacDrawable *)drawable;
+ CGContextRef cg_context = NULL;
+ CGImageRef cg_image = NULL, result = NULL;
+ NSBitmapImageRep *bitmapRep = NULL;
+ NSView *view = NULL;
+ if (mac_drawable->flags & TK_IS_PIXMAP) {
+ /*
+ * This MacDrawable is a bitmap, so its view is NULL.
+ */
+
+ CGRect image_rect = CGRectMake(x, y, width, height);
+
+ cg_context = TkMacOSXGetCGContextForDrawable(drawable);
+ cg_image = CGBitmapContextCreateImage((CGContextRef) cg_context);
+ if (cg_image) {
+ result = CGImageCreateWithImageInRect(cg_image, image_rect);
+ CGImageRelease(cg_image);
+ }
+ } else if (TkMacOSXGetNSViewForDrawable(mac_drawable) != NULL) {
+
+ /*
+ * Convert Tk top-left to NSView bottom-left coordinates.
+ */
+
+ int view_height = [view bounds].size.height;
+ NSRect view_rect = NSMakeRect(x + mac_drawable->xOff,
+ view_height - height - y - mac_drawable->yOff,
+ width, height);
+
+ /*
+ * Attempt to copy from the view to a bitmapImageRep. If the view does
+ * not have a valid CGContext, doing this will silently corrupt memory
+ * and make a big mess. So, in that case, we just return NULL.
+ */
+
+ if (view == [NSView focusView]) {
+ bitmapRep = [view bitmapImageRepForCachingDisplayInRect: view_rect];
+ [view cacheDisplayInRect:view_rect toBitmapImageRep:bitmapRep];
+ result = [bitmapRep CGImage];
+ CFRelease(bitmapRep);
+ } else {
+ TkMacOSXDbgMsg("No CGContext - cannot copy from screen to bitmap.");
+ result = NULL;
+ }
+ } else {
+ TkMacOSXDbgMsg("Invalid source drawable");
+ }
+ return result;
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * CreateCGImageFromPixmap --
+ *
+ * Create a CGImage from an X Pixmap.
+ *
+ * Results:
+ * CGImage, release after use.
+ *
+ * Side effects:
+ * None.
+ *
+ *----------------------------------------------------------------------
+ */
+
+static CGImageRef
+CreateCGImageFromPixmap(
+ Drawable pixmap)
+{
+ CGImageRef img = NULL;
+ CGContextRef context = TkMacOSXGetCGContextForDrawable(pixmap);
+
+ if (context) {
+ img = CGBitmapContextCreateImage(context);
+ }
+ return img;
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * XGetImage --
+ *
+ * This function copies data from a pixmap or window into an XImage. It
+ * is essentially never used. At one time it was called by
+ * pTkImgPhotoDisplay, but that is no longer the case. Currently it is
+ * called two places, one of which is requesting an XY image which we do
+ * not support. It probably does not work correctly -- see the comments
+ * for CGImageFromDrawableRect.
+ *
+ * Results:
+ * Returns a newly allocated XImage containing the data from the given
+ * rectangle of the given drawable, or NULL if the XImage could not be
+ * constructed.
+ *
+ * Side effects:
+ * None.
+ *
+ *----------------------------------------------------------------------
+ */
+struct pixel_fmt {int r; int g; int b; int a;};
+static struct pixel_fmt bgra = {2, 1, 0, 3};
+static struct pixel_fmt abgr = {3, 2, 1, 0};
+
+XImage *
+XGetImage(
+ Display *display,
+ Drawable drawable,
+ int x,
+ int y,
+ unsigned int width,
+ unsigned int height,
+ TCL_UNUSED(unsigned long), /* plane_mask */
+ int format)
+{
+ NSBitmapImageRep* bitmapRep = NULL;
+ NSUInteger bitmap_fmt = 0;
+ XImage* imagePtr = NULL;
+ char* bitmap = NULL;
+ char R, G, B, A;
+ int depth = 32, offset = 0, bitmap_pad = 0;
+ unsigned int bytes_per_row, size, row, n, m;
+
+ if (format == ZPixmap) {
+ CGImageRef cgImage;
+ if (width == 0 || height == 0) {
+ return NULL;
+ }
+
+ cgImage = CreateCGImageFromDrawableRect(drawable, x, y, width, height);
+ if (cgImage) {
+ bitmapRep = [NSBitmapImageRep alloc];
+ [bitmapRep initWithCGImage:cgImage];
+ CFRelease(cgImage);
+ } else {
+ TkMacOSXDbgMsg("XGetImage: Failed to construct CGImage");
+ return NULL;
+ }
+ bitmap_fmt = [bitmapRep bitmapFormat];
+ size = [bitmapRep bytesPerPlane];
+ bytes_per_row = [bitmapRep bytesPerRow];
+ bitmap = ckalloc(size);
+ if (!bitmap
+ || (bitmap_fmt != 0 && bitmap_fmt != 1)
+ || [bitmapRep samplesPerPixel] != 4
+ || [bitmapRep isPlanar] != 0
+ || bytes_per_row < 4 * width
+ || size != bytes_per_row * height) {
+ TkMacOSXDbgMsg("XGetImage: Unrecognized bitmap format");
+ CFRelease(bitmapRep);
+ return NULL;
+ }
+ memcpy(bitmap, (char *)[bitmapRep bitmapData], size);
+ CFRelease(bitmapRep);
+
+ /*
+ * When Apple extracts a bitmap from an NSView, it may be in either
+ * BGRA or ABGR format. For an XImage we need RGBA.
+ */
+
+ struct pixel_fmt pixel = bitmap_fmt == 0 ? bgra : abgr;
+
+ for (row = 0, n = 0; row < height; row++, n += bytes_per_row) {
+ for (m = n; m < n + 4*width; m += 4) {
+ R = *(bitmap + m + pixel.r);
+ G = *(bitmap + m + pixel.g);
+ B = *(bitmap + m + pixel.b);
+ A = *(bitmap + m + pixel.a);
+
+ *(bitmap + m) = R;
+ *(bitmap + m + 1) = G;
+ *(bitmap + m + 2) = B;
+ *(bitmap + m + 3) = A;
+ }
+ }
+ imagePtr = XCreateImage(display, NULL, depth, format, offset,
+ (char*) bitmap, width, height,
+ bitmap_pad, bytes_per_row);
+ } else {
+ /*
+ * There are some calls to XGetImage in the generic Tk code which pass
+ * an XYPixmap rather than a ZPixmap. XYPixmaps should be handled
+ * here.
+ */
+ TkMacOSXDbgMsg("XGetImage does not handle XYPixmaps at the moment.");
+ }
+ return imagePtr;
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * XCopyArea --
+ *
+ * Copies image data from one drawable to another.
+ *
+ * Results:
+ * None.
+ *
+ * Side effects:
+ * Image data is moved from a window or bitmap to a second window or bitmap.
+ *
+ *----------------------------------------------------------------------
+ */
+
+int
+XCopyArea(
+ Display *display, /* Display. */
+ Drawable src, /* Source drawable. */
+ Drawable dst, /* Destination drawable. */
+ GC gc, /* GC to use. */
+ int src_x, /* X & Y, width & height */
+ int src_y, /* define the source rectangle */
+ unsigned int width, /* that will be copied. */
+ unsigned int height,
+ int dest_x, /* Dest X & Y on dest rect. */
+ int dest_y)
+{
+ TkMacOSXDrawingContext dc;
+ MacDrawable *srcDraw = (MacDrawable *)src;
+ CGImageRef img = NULL;
+ CGRect bounds, srcRect, dstRect;
+
+ display->request++;
+ if (!width || !height) {
+ return BadDrawable;
+ }
+
+ if (!TkMacOSXSetupDrawingContext(dst, gc, &dc)) {
+ TkMacOSXDbgMsg("Failed to setup drawing context.");
+ return BadDrawable;
+ }
+
+ if (!dc.context) {
+ TkMacOSXDbgMsg("Invalid destination drawable - no context.");
+ return BadDrawable;
+ }
+
+ if (srcDraw->flags & TK_IS_PIXMAP) {
+ img = CreateCGImageFromPixmap(src);
+ } else if (TkMacOSXGetNSWindowForDrawable(src)) {
+ img = CreateCGImageFromDrawableRect(src, src_x, src_y, width, height);
+ } else {
+ TkMacOSXDbgMsg("Invalid source drawable - neither window nor pixmap.");
+ }
+
+ if (img) {
+ bounds = CGRectMake(0, 0, srcDraw->size.width, srcDraw->size.height);
+ srcRect = CGRectMake(src_x, src_y, width, height);
+ dstRect = CGRectMake(dest_x, dest_y, width, height);
+ TkMacOSXDrawCGImage(dst, gc, dc.context, img,
+ gc->foreground, gc->background, bounds, srcRect, dstRect);
+ CFRelease(img);
+ } else {
+ TkMacOSXDbgMsg("Failed to construct CGImage.");
+ }
+
+ TkMacOSXRestoreDrawingContext(&dc);
+ return Success;
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * XCopyPlane --
+ *
+ * Copies a bitmap from a source drawable to a destination drawable. The
+ * plane argument specifies which bit plane of the source contains the
+ * bitmap. Note that this implementation ignores the gc->function.
+ *
+ * Results:
+ * None.
+ *
+ * Side effects:
+ * Changes the destination drawable.
+ *
+ *----------------------------------------------------------------------
+ */
+
+int
+XCopyPlane(
+ Display *display, /* Display. */
+ Drawable src, /* Source drawable. */
+ Drawable dst, /* Destination drawable. */
+ GC gc, /* GC to use. */
+ int src_x, /* X & Y, width & height */
+ int src_y, /* define the source rectangle */
+ unsigned int width, /* that will be copied. */
+ unsigned int height,
+ int dest_x, /* Dest X & Y on dest rect. */
+ int dest_y,
+ unsigned long plane) /* Which plane to copy. */
+{
+ TkMacOSXDrawingContext dc;
+ MacDrawable *srcDraw = (MacDrawable *)src;
+ MacDrawable *dstDraw = (MacDrawable *)dst;
+ CGRect bounds, srcRect, dstRect;
+ display->request++;
+ if (!width || !height) {
+ /* TkMacOSXDbgMsg("Drawing of empty area requested"); */
+ return BadDrawable;
+ }
+ if (plane != 1) {
+ Tcl_Panic("Unexpected plane specified for XCopyPlane");
+ }
+ if (srcDraw->flags & TK_IS_PIXMAP) {
+ if (!TkMacOSXSetupDrawingContext(dst, gc, &dc)) {
+ return BadDrawable;
+ }
+
+ CGContextRef context = dc.context;
+
+ if (context) {
+ CGImageRef img = CreateCGImageFromPixmap(src);
+
+ if (img) {
+ TkpClipMask *clipPtr = (TkpClipMask *) gc->clip_mask;
+ unsigned long imageBackground = gc->background;
+
+ if (clipPtr && clipPtr->type == TKP_CLIP_PIXMAP) {
+ srcRect = CGRectMake(src_x, src_y, width, height);
+ CGImageRef mask = CreateCGImageFromPixmap(
+ clipPtr->value.pixmap);
+ CGImageRef submask = CGImageCreateWithImageInRect(
+ img, srcRect);
+ CGRect rect = CGRectMake(dest_x, dest_y, width, height);
+
+ rect = CGRectOffset(rect, dstDraw->xOff, dstDraw->yOff);
+ CGContextSaveGState(context);
+
+ /*
+ * Move the origin of the destination to top left.
+ */
+
+ CGContextTranslateCTM(context,
+ 0, rect.origin.y + CGRectGetMaxY(rect));
+ CGContextScaleCTM(context, 1, -1);
+
+ /*
+ * Fill with the background color, clipping to the mask.
+ */
+
+ CGContextClipToMask(context, rect, submask);
+ TkMacOSXSetColorInContext(gc, gc->background, dc.context);
+ CGContextFillRect(context, rect);
+
+ /*
+ * Fill with the foreground color, clipping to the
+ * intersection of img and mask.
+ */
+
+ CGImageRef subimage = CGImageCreateWithImageInRect(
+ img, srcRect);
+ CGContextClipToMask(context, rect, subimage);
+ TkMacOSXSetColorInContext(gc, gc->foreground, context);
+ CGContextFillRect(context, rect);
+ CGContextRestoreGState(context);
+ CGImageRelease(img);
+ CGImageRelease(mask);
+ CGImageRelease(submask);
+ CGImageRelease(subimage);
+ } else {
+ bounds = CGRectMake(0, 0,
+ srcDraw->size.width, srcDraw->size.height);
+ srcRect = CGRectMake(src_x, src_y, width, height);
+ dstRect = CGRectMake(dest_x, dest_y, width, height);
+ TkMacOSXDrawCGImage(dst, gc, dc.context, img,
+ gc->foreground, imageBackground, bounds,
+ srcRect, dstRect);
+ CGImageRelease(img);
+ }
+ } else {
+ /* no image */
+ TkMacOSXDbgMsg("Invalid source drawable");
+ }
+ } else {
+ TkMacOSXDbgMsg("Invalid destination drawable - "
+ "could not get a bitmap context.");
+ }
+ TkMacOSXRestoreDrawingContext(&dc);
+ return Success;
+ } else {
+ /*
+ * Source drawable is a Window, not a Pixmap.
+ */
+
+ return XCopyArea(display, src, dst, gc, src_x, src_y, width, height,
+ dest_x, dest_y);
+ }
+}
+
+/*
* Local Variables:
* mode: objc
* c-basic-offset: 4