summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorKevin Walzer <kw@codebykevin.com>2014-06-22 01:34:07 (GMT)
committerKevin Walzer <kw@codebykevin.com>2014-06-22 01:34:07 (GMT)
commit023d39bb38c487ec29fd83e4dd664adb16880fa3 (patch)
tree28154d1f034fddfd3feafa8f1a046b48a5440e7d
parent07f1821ced9ccf739badabbba75ae09f5bdb7521 (diff)
downloadtk-023d39bb38c487ec29fd83e4dd664adb16880fa3.zip
tk-023d39bb38c487ec29fd83e4dd664adb16880fa3.tar.gz
tk-023d39bb38c487ec29fd83e4dd664adb16880fa3.tar.bz2
Fix for images with alpha channel data on Mavericks; thanks to Mark Culler for the patch.
-rw-r--r--macosx/tkMacOSXDraw.c153
-rw-r--r--macosx/tkMacOSXPrivate.h2
-rw-r--r--macosx/tkMacOSXSubwindows.c4
-rw-r--r--macosx/tkMacOSXXStubs.c90
4 files changed, 136 insertions, 113 deletions
diff --git a/macosx/tkMacOSXDraw.c b/macosx/tkMacOSXDraw.c
index 0727b26..1589e43 100644
--- a/macosx/tkMacOSXDraw.c
+++ b/macosx/tkMacOSXDraw.c
@@ -114,6 +114,70 @@ TkMacOSXInitCGDrawing(
/*
*----------------------------------------------------------------------
*
+ * BitmapRepFromDrawableRect
+ *
+ * Extract bitmap data from a MacOSX drawable as an NSBitmapImageRep.
+ *
+ * Results:
+ * Returns an NSBitmapRep representing the image of the given rectangle of
+ * the given drawable.
+ *
+ * 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:
+ * Allocates an NSBitmapImageRep, which must be released.
+ *
+ *----------------------------------------------------------------------
+ */
+NSBitmapImageRep*
+BitmapRepFromDrawableRect(
+ MacDrawable *drawable,
+ int x,
+ int y,
+ unsigned int width,
+ unsigned int height)
+{
+ CGImageRef cg_image=NULL, sub_cg_image=NULL;
+ NSBitmapImageRep *bitmap_rep=NULL;
+ NSView *view=NULL;
+
+ if ( drawable->flags & TK_IS_PIXMAP && drawable->context) {
+ /* This means that the MacDrawable is functioning as a Tk Pixmap, so its view
+ field is NULL and its context field points to a CGBitmapContext.
+ */
+ CGRect image_rect = CGRectMake(x, y, width, height);
+ cg_image = CGBitmapContextCreateImage( (CGContextRef) drawable->context);
+ sub_cg_image = CGImageCreateWithImageInRect(cg_image, image_rect);
+ if ( sub_cg_image ) {
+ bitmap_rep = [NSBitmapImageRep alloc];
+ [bitmap_rep initWithCGImage:sub_cg_image];
+ CGImageRelease(sub_cg_image);
+ }
+ if ( cg_image ) {
+ CGImageRelease(cg_image);
+ }
+ } else if ( (view = TkMacOSXDrawableView(drawable)) ) {
+ /* convert top-left coordinates to NSView coordinates */
+ int view_height = [view bounds].size.height;
+ NSRect view_rect = NSMakeRect(x + drawable->xOff,
+ view_height - height - y - drawable->yOff,
+ width,height);
+ bitmap_rep = [NSBitmapImageRep alloc];
+ [view lockFocus];
+ [bitmap_rep initWithFocusedViewRect:view_rect];
+ [view unlockFocus];
+ } else {
+ TkMacOSXDbgMsg("Invalid source drawable");
+ }
+
+ return bitmap_rep;
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
* XCopyArea --
*
* Copies data from one drawable to another using block transfer
@@ -134,86 +198,45 @@ XCopyArea(
Display *display, /* Display. */
Drawable src, /* Source drawable. */
Drawable dst, /* Destination drawable. */
- GC gc, /* GC to use. */
+ 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 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;
+ NSBitmapImageRep *bitmap_rep = NULL;
display->request++;
if (!width || !height) {
- /* TkMacOSXDbgMsg("Drawing of emtpy area requested"); */
+ /* TkMacOSXDbgMsg("Drawing of empty area requested"); */
return;
}
- if (srcDraw->flags & TK_IS_PIXMAP) {
- if (!TkMacOSXSetupDrawingContext(dst, gc, 1, &dc)) {
- return;
- }
- if (dc.context) {
- CGImageRef img = TkMacOSXCreateCGImageWithDrawable(src);
-
- if (img) {
- DrawCGImage(dst, gc, dc.context, img, gc->foreground,
- gc->background, CGRectMake(0, 0,
- srcDraw->size.width, srcDraw->size.height),
- CGRectMake(src_x, src_y, width, height),
- CGRectMake(dest_x, dest_y, width, height));
- CFRelease(img);
- } else {
- TkMacOSXDbgMsg("Invalid source drawable");
- }
- } else {
- TkMacOSXDbgMsg("Invalid destination drawable");
- }
- TkMacOSXRestoreDrawingContext(&dc);
- } else if (TkMacOSXDrawableWindow(src)) {
- NSView *view = TkMacOSXDrawableView(srcDraw);
- NSWindow *w = [view window];
- NSInteger gs = [w windowNumber] > 0 ? [w gState] : 0;
- /* // alternative using per-view gState:
- NSInteger gs = [view gState];
- if (!gs) {
- [view allocateGState];
- if ([view lockFocusIfCanDraw]) {
- [view unlockFocus];
- }
- gs = [view gState];
- }
- */
- if (!gs || !TkMacOSXSetupDrawingContext(dst, gc, 1, &dc)) {
- return;
- }
- if (dc.context) {
- NSGraphicsContext *gc = nil;
- CGFloat boundsH = [view bounds].size.height;
- NSRect srcRect = NSMakeRect(srcDraw->xOff + src_x, boundsH -
- height - (srcDraw->yOff + src_y), width, height);
-
- if (((MacDrawable *) dst)->flags & TK_IS_PIXMAP) {
- gc = [NSGraphicsContext graphicsContextWithGraphicsPort:
- dc.context flipped:NO];
- if (gc) {
- [NSGraphicsContext saveGraphicsState];
- [NSGraphicsContext setCurrentContext:gc];
+ if (!TkMacOSXSetupDrawingContext(dst, gc, 1, &dc)) {
+ TkMacOSXDbgMsg("Invalid destination drawable");
+ }
+ if (dc.context) {
+ bitmap_rep = BitmapRepFromDrawableRect(srcDraw, src_x, src_y, width, height);
+ if ( bitmap_rep ) {
+ CGImageRef img = [bitmap_rep CGImage];
+ CGRect image_rect = CGRectMake(0, 0,
+ srcDraw->size.width, srcDraw->size.height);
+ if (img) {
+ DrawCGImage(dst, gc, dc.context, img, gc->foreground,
+ gc->background, image_rect,
+ CGRectMake(src_x, src_y, width, height),
+ CGRectMake(dest_x, dest_y, width, height));
+ CFRelease(img);
}
- }
- NSCopyBits(gs, srcRect, NSMakePoint(dest_x,
- dc.portBounds.size.height - dest_y));
- if (gc) {
- [NSGraphicsContext restoreGraphicsState];
- }
- } else {
- TkMacOSXDbgMsg("Invalid destination drawable");
+ [bitmap_rep release];
+ } else {
+ TkMacOSXDbgMsg("Invalid source drawable");
}
- TkMacOSXRestoreDrawingContext(&dc);
- } else {
- TkMacOSXDbgMsg("Invalid source drawable");
}
+ TkMacOSXRestoreDrawingContext(&dc);
}
/*
@@ -254,7 +277,7 @@ XCopyPlane(
display->request++;
if (!width || !height) {
- /* TkMacOSXDbgMsg("Drawing of emtpy area requested"); */
+ /* TkMacOSXDbgMsg("Drawing of empty area requested"); */
return;
}
if (plane != 1) {
diff --git a/macosx/tkMacOSXPrivate.h b/macosx/tkMacOSXPrivate.h
index 034c450..9220397 100644
--- a/macosx/tkMacOSXPrivate.h
+++ b/macosx/tkMacOSXPrivate.h
@@ -230,6 +230,8 @@ MODULE_SCOPE WindowClass TkMacOSXWindowClass(TkWindow *winPtr);
MODULE_SCOPE int TkMacOSXIsWindowZoomed(TkWindow *winPtr);
MODULE_SCOPE int TkGenerateButtonEventForXPointer(Window window);
MODULE_SCOPE EventModifiers TkMacOSXModifierState(void);
+MODULE_SCOPE NSBitmapImageRep* BitmapRepFromDrawableRect(MacDrawable *drawable,
+ int x, int y, unsigned int width, unsigned int height);
MODULE_SCOPE int TkMacOSXSetupDrawingContext(Drawable d, GC gc,
int useCG, TkMacOSXDrawingContext *dcPtr);
MODULE_SCOPE void TkMacOSXRestoreDrawingContext(
diff --git a/macosx/tkMacOSXSubwindows.c b/macosx/tkMacOSXSubwindows.c
index 18276fb..29bc4a3 100644
--- a/macosx/tkMacOSXSubwindows.c
+++ b/macosx/tkMacOSXSubwindows.c
@@ -1277,7 +1277,7 @@ UpdateOffsets(
* Returns a handle to a new pixmap.
*
* Side effects:
- * Allocates a new Macintosh GWorld.
+ * Allocates a new CGBitmapContext.
*
*----------------------------------------------------------------------
*/
@@ -1323,7 +1323,7 @@ Tk_GetPixmap(
* None.
*
* Side effects:
- * Deletes the Macintosh GWorld created by Tk_GetPixmap.
+ * Deletes the CGBitmapContext created by Tk_GetPixmap.
*
*----------------------------------------------------------------------
*/
diff --git a/macosx/tkMacOSXXStubs.c b/macosx/tkMacOSXXStubs.c
index 848b49c..f009b52 100644
--- a/macosx/tkMacOSXXStubs.c
+++ b/macosx/tkMacOSXXStubs.c
@@ -842,7 +842,7 @@ XCreateImage(
* This function copies data from a pixmap or window into an XImage.
*
* Results:
- * Returns a newly allocated image containing the data from the given
+ * Returns a newly allocated XImage containing the data from the given
* rectangle of the given drawable.
*
* Side effects:
@@ -863,59 +863,57 @@ XGetImage(
int format)
{
MacDrawable *macDraw = (MacDrawable *) d;
- XImage * imagePtr = NULL;
- Pixmap pixmap = (Pixmap) NULL;
- Tk_Window win = (Tk_Window) macDraw->winPtr;
- GC gc;
- char * data = NULL;
- int depth = 32;
- int offset = 0;
- int bitmap_pad = 0;
- int bytes_per_line = 0;
-
+ NSBitmapImageRep *bitmap_rep;
+ XImage * imagePtr = NULL;
+ char * bitmap = NULL;
+ char * image_data=NULL;
+ int depth = 32;
+ int offset = 0;
+ int bitmap_pad = 0;
+ int bytes_per_row = 4*width;
+ int size;
if (format == ZPixmap) {
- if (width > 0 && height > 0) {
- /*
- * Tk_GetPixmap fails for zero width or height.
- */
-
- pixmap = Tk_GetPixmap(display, d, width, height, depth);
+ if (width == 0 || height == 0) {
+ return NULL;
}
- if (win) {
- XGCValues values;
- gc = Tk_GetGC(win, 0, &values);
- } else {
- gc = XCreateGC(display, pixmap, 0, NULL);
- }
- if (pixmap) {
- CGContextRef context;
-
- XCopyArea(display, d, pixmap, gc, x, y, width, height, 0, 0);
- context = ((MacDrawable *) pixmap)->context;
- if (context) {
- data = CGBitmapContextGetData(context);
- bytes_per_line = CGBitmapContextGetBytesPerRow(context);
+ bitmap_rep = BitmapRepFromDrawableRect(macDraw, x, y,width, height);
+ NSSize image_size = NSMakeSize(width, height);
+ NSImage* ns_image = [[NSImage alloc]initWithSize:image_size];
+ [ns_image addRepresentation:bitmap_rep];
+
+ /* Assume premultiplied nonplanar data with 4 bytes per pixel and alpha last.*/
+ if ( [bitmap_rep bitmapFormat] == 0 &&
+ [bitmap_rep isPlanar ] == 0 &&
+ [bitmap_rep samplesPerPixel] == 4 ) {
+ bytes_per_row = [bitmap_rep bytesPerRow];
+ size = bytes_per_row*height;
+ image_data = (char*)[bitmap_rep bitmapData];
+ if ( image_data ) {
+ int row, n, m;
+ bitmap = ckalloc(size);
+ /*
+ Oddly enough, the bitmap has the top row at the beginning,
+ and the pixels are in BGRA format.
+ */
+ for (row=0, n=0; row<height; row++, n+=bytes_per_row) {
+ for (m=n; m<n+bytes_per_row; m+=4) {
+ *(bitmap+m) = *(image_data+m+2);
+ *(bitmap+m+1) = *(image_data+m+1);
+ *(bitmap+m+2) = *(image_data+m);
+ *(bitmap+m+3) = *(image_data+m+3);
+ }
+ }
}
}
- if (data) {
+ if (bitmap) {
imagePtr = XCreateImage(display, NULL, depth, format, offset,
- data, width, height, bitmap_pad, bytes_per_line);
-
- /*
- * Track Pixmap underlying the XImage in the unused obdata field
- * so that we can treat XImages coming from XGetImage specially.
- */
-
- imagePtr->obdata = (XPointer) pixmap;
- } else if (pixmap) {
- Tk_FreePixmap(display, pixmap);
- }
- if (!win) {
- XFreeGC(display, gc);
+ (char*)bitmap, width, height, bitmap_pad, bytes_per_row);
+ [ns_image removeRepresentation:bitmap_rep]; /*releases the rep*/
+ [ns_image release];
}
} else {
- TkMacOSXDbgMsg("Invalid image format");
+ TkMacOSXDbgMsg("Could not extract image from drawable.");
}
return imagePtr;
}