From 063222efaf123728ad766529640b4a3e0a9fd895 Mon Sep 17 00:00:00 2001 From: culler Date: Wed, 8 Nov 2017 21:02:50 +0000 Subject: Cleaned up and reworked XGetImage. This seems to eliminate segfaults seen when rapidly resizing the scid window and may also fix [218561bf]. --- macosx/tkMacOSXDraw.c | 19 +++--- macosx/tkMacOSXImage.c | 165 ++++++++++++++++++++++++------------------------- 2 files changed, 90 insertions(+), 94 deletions(-) diff --git a/macosx/tkMacOSXDraw.c b/macosx/tkMacOSXDraw.c index 274a2cd..3d21507 100644 --- a/macosx/tkMacOSXDraw.c +++ b/macosx/tkMacOSXDraw.c @@ -106,8 +106,9 @@ TkMacOSXInitCGDrawing( * Extract bitmap data from a MacOSX drawable as an NSBitmapImageRep. * * Results: - * Returns an autoreleased NSBitmapRep representing the image of the given - * rectangle of the given drawable. + * 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 @@ -133,15 +134,14 @@ TkMacOSXBitmapRepFromDrawableRect( NSView *view=NULL; if ( mac_drawable->flags & TK_IS_PIXMAP ) { /* - This means that the MacDrawable is functioning as a Tk Pixmap, so its view - field is NULL. + * This means that the MacDrawable is functioning as a + * Tk Pixmap, so its view field is NULL. */ cg_context = TkMacOSXGetCGContextForDrawable(drawable); CGRect image_rect = CGRectMake(x, y, width, height); cg_image = CGBitmapContextCreateImage( (CGContextRef) cg_context); sub_cg_image = CGImageCreateWithImageInRect(cg_image, image_rect); if ( sub_cg_image ) { - /*This can be dealloc'ed prematurely if set for autorelease, causing crashes.*/ bitmap_rep = [NSBitmapImageRep alloc]; [bitmap_rep initWithCGImage:sub_cg_image]; } @@ -149,14 +149,15 @@ TkMacOSXBitmapRepFromDrawableRect( CGImageRelease(cg_image); } } else if ( (view = TkMacOSXDrawableView(mac_drawable)) ) { - /* convert top-left coordinates to NSView coordinates */ + /* + * 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); + view_height - height - y - mac_drawable->yOff, + width, height); if ( [view lockFocusIfCanDraw] ) { - /*This can be dealloc'ed prematurely if set for autorelease, causing crashes.*/ bitmap_rep = [NSBitmapImageRep alloc]; bitmap_rep = [bitmap_rep initWithFocusedViewRect:view_rect]; [view unlockFocus]; diff --git a/macosx/tkMacOSXImage.c b/macosx/tkMacOSXImage.c index ac842f9..8269d7a 100644 --- a/macosx/tkMacOSXImage.c +++ b/macosx/tkMacOSXImage.c @@ -136,11 +136,14 @@ TkMacOSXCreateCGImageWithXImage( * *---------------------------------------------------------------------- */ +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 d, + Drawable drawable, int x, int y, unsigned int width, @@ -148,100 +151,84 @@ XGetImage( unsigned long plane_mask, int format) { - NSBitmapImageRep *bitmap_rep; - NSUInteger bitmap_fmt; - 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; - int scalefactor = 1; -#if __MAC_OS_X_VERSION_MAX_ALLOWED >= 1070 - NSWindow *win = TkMacOSXDrawableWindow(d); - /* This code assumes that backing scale factors are integers. Currently - * Retina displays use a scale factor of 2.0 and normal displays use 1.0. - * We do not support any other values here. - */ - if (win && [win respondsToSelector:@selector(backingScaleFactor)]) { - scalefactor = ([win backingScaleFactor] == 2.0) ? 2 : 1; + NSBitmapImageRep* bitmap_rep = NULL; + NSUInteger bitmap_fmt = 0; + XImage* imagePtr = NULL; + char* bitmap = NULL; + char* image_data = NULL; + char* image_ptr = NULL; + int depth = 32, offset = 0, bitmap_pad = 0; + int bytes_per_row, size, row, n, m; + char R, G, B, A; + unsigned int scalefactor=1, scaled_height=height, scaled_width=width; + NSWindow *win = TkMacOSXDrawableWindow(drawable); + static enum {unknown, no, yes} supports_retina = unknown; + + if (win && supports_retina == unknown) { + supports_retina = [win respondsToSelector: + @selector(backingScaleFactor)]? yes: no; + } + + if (supports_retina == yes) { + /* + * We only allow scale factors 1 or 2, as Apple currently does. + */ + scalefactor = [win backingScaleFactor] == 2.0 ? 2 : 1; + scaled_height *= scalefactor; + scaled_width *= scalefactor; } -#endif - int scaled_height = height * scalefactor; - int scaled_width = width * scalefactor; if (format == ZPixmap) { if (width == 0 || height == 0) { - /* This happens all the time. - TkMacOSXDbgMsg("XGetImage: empty image requested"); - */ return NULL; } - - bitmap_rep = TkMacOSXBitmapRepFromDrawableRect(d, x, y, width, height); - bitmap_fmt = [bitmap_rep bitmapFormat]; - - if ( bitmap_rep == Nil || - (bitmap_fmt != 0 && bitmap_fmt != 1) || - [bitmap_rep samplesPerPixel] != 4 || - [bitmap_rep isPlanar] != 0 ) { + bitmap_rep = TkMacOSXBitmapRepFromDrawableRect(drawable, + x, y, width, height); + if (!bitmap_rep) { TkMacOSXDbgMsg("XGetImage: Failed to construct NSBitmapRep"); return NULL; } - - 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.*/ - if ( [bitmap_rep isPlanar ] == 0 && - [bitmap_rep samplesPerPixel] == 4 ) { - bytes_per_row = [bitmap_rep bytesPerRow]; - assert(bytes_per_row == 4 * scaled_width); - assert([bitmap_rep bytesPerPlane] == bytes_per_row * scaled_height); - size = bytes_per_row*scaled_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 or ABGR format. - */ - if (bitmap_fmt == 0) { - /* BGRA */ - for (row=0, n=0; rowpixelpower = 1; - } - [ns_image removeRepresentation:bitmap_rep]; /*releases the rep*/ - [ns_image release]; + 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 { TkMacOSXDbgMsg("Could not extract image from drawable."); @@ -556,4 +543,12 @@ TkPutImage( TkMacOSXRestoreDrawingContext(&dc); return Success; } - + +/* + * Local Variables: + * mode: objc + * c-basic-offset: 4 + * fill-column: 79 + * coding: utf-8 + * End: + */ -- cgit v0.12