Import Tk 8.6.12
This commit is contained in:
@@ -4,9 +4,9 @@
|
||||
* The code in this file provides an interface for XImages,
|
||||
*
|
||||
* Copyright (c) 1995-1997 Sun Microsystems, Inc.
|
||||
* Copyright 2001-2009, Apple Inc.
|
||||
* Copyright (c) 2001-2009, Apple Inc.
|
||||
* Copyright (c) 2005-2009 Daniel A. Steffen <das@users.sourceforge.net>
|
||||
* Copyright (c) 2017-2020 Marc Culler.
|
||||
* Copyright (c) 2017-2021 Marc Culler.
|
||||
*
|
||||
* See the file "license.terms" for information on usage and redistribution
|
||||
* of this file, and for a DISCLAIMER OF ALL WARRANTIES.
|
||||
@@ -19,11 +19,76 @@ static CGImageRef CreateCGImageFromPixmap(Drawable pixmap);
|
||||
static CGImageRef CreateCGImageFromDrawableRect( Drawable drawable,
|
||||
int x, int y, unsigned int width, unsigned int height);
|
||||
|
||||
/* Pixel formats
|
||||
*
|
||||
* Tk uses the XImage structure defined in Xlib.h for storing images. The
|
||||
* image data in an XImage is a 32-bit aligned array of bytes. Interpretation
|
||||
* of that data is not specified, but the structure includes parameters which
|
||||
* provide interpretation hints so that an application can use a family of
|
||||
* different data structures.
|
||||
*
|
||||
* The possible values for the XImage format field are XYBitmap, XYPixmap and
|
||||
* ZPixmap. The macOS port does not support the XYPixmap format. This means
|
||||
* that bitmap images are stored as a single bit plane (XYBitmap) and that
|
||||
* color images are stored as a sequence of pixel values (ZPixmap).
|
||||
*
|
||||
* For a ZPixmap, the number of bits allocated to each pixel is specified by
|
||||
* the bits_per_pixel field of the XImage structure. The functions in this
|
||||
* module which convert between XImage and native CGImage or NSImage structures
|
||||
* only support XImages with 32 bits per pixel. The ImageGetPixel and PutPixel
|
||||
* implementations in this file allow 1, 4, 8, 16 or 32 bits per pixel, however.
|
||||
*
|
||||
* In tkImgPhInstance.c the layout used for pixels is determined by the values
|
||||
* of the red_mask, blue_mask and green_mask fields in the XImage structure.
|
||||
* The Aqua port always sets red_mask = 0xFF0000, green_mask = 0xFF00, and
|
||||
* blue_mask = 0xFF. This means that a 32bpp ZPixmap XImage uses ARGB32 pixels,
|
||||
* with small-endian byte order BGRA. The data array for such an XImage can be
|
||||
* passed directly to construct a CGBitmapImageRep if one specifies the
|
||||
* bitmapInfo as kCGBitmapByteOrder32Big | kCGImageAlphaLast.
|
||||
*
|
||||
* The structures below describe the bitfields in two common 32 bpp pixel
|
||||
* layouts. Note that bit field layouts are compiler dependent. The layouts
|
||||
* shown in the comments are those produced by clang and gcc. Also note
|
||||
* that kCGBitmapByteOrder32Big is consistently set when creating CGImages or
|
||||
* CGImageBitmapReps.
|
||||
*/
|
||||
|
||||
/* RGBA32 0xRRGGBBAA (Byte order is RGBA on big-endian systems.)
|
||||
* This is used by NSBitmapImageRep when the bitmapFormat property is 0,
|
||||
* the default value.
|
||||
*/
|
||||
|
||||
typedef struct RGBA32pixel_t {
|
||||
unsigned red: 8;
|
||||
unsigned green: 8;
|
||||
unsigned blue: 8;
|
||||
unsigned alpha: 8;
|
||||
} RGBA32pixel;
|
||||
|
||||
/*
|
||||
* ARGB32 0xAARRGGBB (Byte order is ARGB on big-endian systems.)
|
||||
* This is used by Aqua Tk for XImages and by NSBitmapImageReps whose
|
||||
* bitmapFormat property is NSBitmapFormatAlphaFirst.
|
||||
*/
|
||||
|
||||
typedef struct ARGB32pixel_t {
|
||||
unsigned blue: 8;
|
||||
unsigned green: 8;
|
||||
unsigned red: 8;
|
||||
unsigned alpha: 8;
|
||||
} ARGB32pixel;
|
||||
|
||||
typedef union pixel32_t {
|
||||
unsigned int uint;
|
||||
RGBA32pixel rgba;
|
||||
ARGB32pixel argb;
|
||||
} pixel32;
|
||||
|
||||
#pragma mark XImage handling
|
||||
|
||||
int
|
||||
_XInitImageFuncPtrs(
|
||||
XImage *image)
|
||||
TCL_UNUSED(XImage *)) /* image */
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
@@ -45,13 +110,18 @@ _XInitImageFuncPtrs(
|
||||
*----------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
static void ReleaseData(void *info, const void *data, size_t size) {
|
||||
static void ReleaseData(
|
||||
void *info,
|
||||
TCL_UNUSED(const void *), /* data */
|
||||
TCL_UNUSED(size_t)) /* size */
|
||||
{
|
||||
ckfree(info);
|
||||
}
|
||||
|
||||
CGImageRef
|
||||
TkMacOSXCreateCGImageWithXImage(
|
||||
XImage *image)
|
||||
XImage *image,
|
||||
uint32_t alphaInfo)
|
||||
{
|
||||
CGImageRef img = NULL;
|
||||
size_t bitsPerComponent, bitsPerPixel;
|
||||
@@ -76,13 +146,13 @@ TkMacOSXCreateCGImageWithXImage(
|
||||
if (image->bitmap_bit_order != MSBFirst) {
|
||||
char *srcPtr = image->data + image->xoffset;
|
||||
char *endPtr = srcPtr + len;
|
||||
char *destPtr = (data = ckalloc(len));
|
||||
char *destPtr = (data = (char *)ckalloc(len));
|
||||
|
||||
while (srcPtr < endPtr) {
|
||||
*destPtr++ = xBitReverseTable[(unsigned char)(*(srcPtr++))];
|
||||
}
|
||||
} else {
|
||||
data = memcpy(ckalloc(len), image->data + image->xoffset, len);
|
||||
data = (char *)memcpy(ckalloc(len), image->data + image->xoffset, len);
|
||||
}
|
||||
if (data) {
|
||||
provider = CGDataProviderCreateWithData(data, data, len,
|
||||
@@ -94,6 +164,7 @@ TkMacOSXCreateCGImageWithXImage(
|
||||
provider, decode, 0);
|
||||
}
|
||||
} else if ((image->format == ZPixmap) && (image->bits_per_pixel == 32)) {
|
||||
|
||||
/*
|
||||
* Color image
|
||||
*/
|
||||
@@ -101,6 +172,7 @@ TkMacOSXCreateCGImageWithXImage(
|
||||
CGColorSpaceRef colorspace = CGColorSpaceCreateDeviceRGB();
|
||||
|
||||
if (image->width == 0 && image->height == 0) {
|
||||
|
||||
/*
|
||||
* CGCreateImage complains on early macOS releases.
|
||||
*/
|
||||
@@ -109,10 +181,8 @@ TkMacOSXCreateCGImageWithXImage(
|
||||
}
|
||||
bitsPerComponent = 8;
|
||||
bitsPerPixel = 32;
|
||||
bitmapInfo = (image->byte_order == MSBFirst ?
|
||||
kCGBitmapByteOrder32Little : kCGBitmapByteOrder32Big);
|
||||
bitmapInfo |= kCGImageAlphaLast;
|
||||
data = memcpy(ckalloc(len), image->data + image->xoffset, len);
|
||||
bitmapInfo = kCGBitmapByteOrder32Big | alphaInfo;
|
||||
data = (char *)memcpy(ckalloc(len), image->data + image->xoffset, len);
|
||||
if (data) {
|
||||
provider = CGDataProviderCreateWithData(data, data, len,
|
||||
releaseData);
|
||||
@@ -201,14 +271,12 @@ ImageGetPixel(
|
||||
|
||||
switch (image->bits_per_pixel) {
|
||||
case 32: /* 8 bits per channel */
|
||||
r = (*((unsigned int*) srcPtr) >> 16) & 0xff;
|
||||
g = (*((unsigned int*) srcPtr) >> 8) & 0xff;
|
||||
b = (*((unsigned int*) srcPtr) ) & 0xff;
|
||||
/*if (image->byte_order == LSBFirst) {
|
||||
r = srcPtr[2]; g = srcPtr[1]; b = srcPtr[0];
|
||||
} else {
|
||||
r = srcPtr[1]; g = srcPtr[2]; b = srcPtr[3];
|
||||
}*/
|
||||
{
|
||||
ARGB32pixel *pixel = (ARGB32pixel *)srcPtr;
|
||||
r = pixel->red;
|
||||
g = pixel->green;
|
||||
b = pixel->blue;
|
||||
}
|
||||
break;
|
||||
case 16: /* 5 bits per channel */
|
||||
r = (*((unsigned short*) srcPtr) >> 7) & 0xf8;
|
||||
@@ -245,7 +313,10 @@ ImageGetPixel(
|
||||
*
|
||||
* ImagePutPixel --
|
||||
*
|
||||
* Set a single pixel in an image.
|
||||
* Set a single pixel in an image. The pixel is provided as an unsigned
|
||||
* 32-bit integer. The value of that integer is interpreted by assuming
|
||||
* that its low-order N bits have the format specified by the XImage,
|
||||
* where N is equal to the bits_per_pixel field of the XImage.
|
||||
*
|
||||
* Results:
|
||||
* None.
|
||||
@@ -271,27 +342,20 @@ ImagePutPixel(
|
||||
if (image->bits_per_pixel == 32) {
|
||||
*((unsigned int*) dstPtr) = pixel;
|
||||
} else {
|
||||
unsigned char r = ((pixel & image->red_mask) >> 16) & 0xff;
|
||||
unsigned char g = ((pixel & image->green_mask) >> 8) & 0xff;
|
||||
unsigned char b = ((pixel & image->blue_mask) ) & 0xff;
|
||||
switch (image->bits_per_pixel) {
|
||||
case 16:
|
||||
*((unsigned short*) dstPtr) = ((r & 0xf8) << 7) |
|
||||
((g & 0xf8) << 2) | ((b & 0xf8) >> 3);
|
||||
*((unsigned short*) dstPtr) = pixel & 0xffff;
|
||||
break;
|
||||
case 8:
|
||||
*dstPtr = ((r & 0xc0) >> 2) | ((g & 0xc0) >> 4) |
|
||||
((b & 0xc0) >> 6);
|
||||
*dstPtr = pixel & 0xff;
|
||||
break;
|
||||
case 4: {
|
||||
unsigned char c = ((r & 0x80) >> 5) | ((g & 0x80) >> 6) |
|
||||
((b & 0x80) >> 7);
|
||||
*dstPtr = (x % 2) ? ((*dstPtr & 0xf0) | (c & 0x0f)) :
|
||||
((*dstPtr & 0x0f) | ((c << 4) & 0xf0));
|
||||
*dstPtr = (x % 2) ? ((*dstPtr & 0xf0) | (pixel & 0x0f)) :
|
||||
((*dstPtr & 0x0f) | ((pixel << 4) & 0xf0));
|
||||
break;
|
||||
}
|
||||
case 1:
|
||||
*dstPtr = ((r|g|b) & 0x80) ? (*dstPtr | (0x80 >> (x % 8))) :
|
||||
*dstPtr = pixel ? (*dstPtr | (0x80 >> (x % 8))) :
|
||||
(*dstPtr & ~(0x80 >> (x % 8)));
|
||||
break;
|
||||
}
|
||||
@@ -319,7 +383,7 @@ ImagePutPixel(
|
||||
XImage *
|
||||
XCreateImage(
|
||||
Display* display,
|
||||
Visual* visual,
|
||||
TCL_UNUSED(Visual*), /* visual */
|
||||
unsigned int depth,
|
||||
int format,
|
||||
int offset,
|
||||
@@ -332,7 +396,7 @@ XCreateImage(
|
||||
XImage *ximage;
|
||||
|
||||
display->request++;
|
||||
ximage = ckalloc(sizeof(XImage));
|
||||
ximage = (XImage *)ckalloc(sizeof(XImage));
|
||||
|
||||
ximage->height = height;
|
||||
ximage->width = width;
|
||||
@@ -388,14 +452,25 @@ XCreateImage(
|
||||
/*
|
||||
*----------------------------------------------------------------------
|
||||
*
|
||||
* TkPutImage, XPutImage --
|
||||
* TkPutImage, XPutImage, TkpPutRGBAImage --
|
||||
*
|
||||
* Copies a rectangular subimage of an XImage into a drawable. Currently
|
||||
* this is only called by TkImgPhotoDisplay, using a Window as the
|
||||
* drawable.
|
||||
* These functions, which all have the same signature, copy a rectangular
|
||||
* subimage of an XImage into a drawable. The first two are identical on
|
||||
* macOS. They assume that the XImage data has the structure of a 32bpp
|
||||
* ZPixmap in which the image data is an array of 32bit integers packed
|
||||
* with 8 bit values for the Red Green and Blue channels. They ignore the
|
||||
* fourth byte. The function TkpPutRGBAImage assumes that the XImage data
|
||||
* has been extended by using the fourth byte to store an 8-bit Alpha
|
||||
* value. (The Alpha data is assumed not to pre-multiplied). The image
|
||||
* is then drawn into the drawable using standard Porter-Duff Source Atop
|
||||
* Composition (kCGBlendModeSourceAtop in Apple's Core Graphics).
|
||||
*
|
||||
* The TkpPutRGBAImage function is used by TkImgPhotoDisplay to render photo
|
||||
* images if the compile-time variable TK_CAN_RENDER_RGBA is defined in
|
||||
* a platform's tkXXXXPort.h header, as is the case for the macOS Aqua port.
|
||||
*
|
||||
* Results:
|
||||
* None.
|
||||
* These functions return either BadDrawable or Success.
|
||||
*
|
||||
* Side effects:
|
||||
* Draws the image on the specified drawable.
|
||||
@@ -403,8 +478,12 @@ XCreateImage(
|
||||
*----------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
int
|
||||
XPutImage(
|
||||
#define USE_ALPHA kCGImageAlphaLast
|
||||
#define IGNORE_ALPHA kCGImageAlphaNoneSkipLast
|
||||
|
||||
static int
|
||||
TkMacOSXPutImage(
|
||||
uint32_t pixelFormat,
|
||||
Display* display, /* Display. */
|
||||
Drawable drawable, /* Drawable to place image on. */
|
||||
GC gc, /* GC to use. */
|
||||
@@ -418,14 +497,14 @@ XPutImage(
|
||||
{
|
||||
TkMacOSXDrawingContext dc;
|
||||
MacDrawable *macDraw = (MacDrawable *)drawable;
|
||||
|
||||
int result = Success;
|
||||
display->request++;
|
||||
if (!TkMacOSXSetupDrawingContext(drawable, gc, &dc)) {
|
||||
return BadDrawable;
|
||||
}
|
||||
if (dc.context) {
|
||||
CGRect bounds, srcRect, dstRect;
|
||||
CGImageRef img = TkMacOSXCreateCGImageWithXImage(image);
|
||||
CGImageRef img = TkMacOSXCreateCGImageWithXImage(image, pixelFormat);
|
||||
|
||||
/*
|
||||
* The CGContext for a pixmap is RGB only, with A = 0.
|
||||
@@ -435,7 +514,6 @@ XPutImage(
|
||||
CGContextSetBlendMode(dc.context, kCGBlendModeSourceAtop);
|
||||
}
|
||||
if (img) {
|
||||
|
||||
bounds = CGRectMake(0, 0, image->width, image->height);
|
||||
srcRect = CGRectMake(src_x, src_y, width, height);
|
||||
dstRect = CGRectMake(dest_x, dest_y, width, height);
|
||||
@@ -445,63 +523,103 @@ XPutImage(
|
||||
CFRelease(img);
|
||||
} else {
|
||||
TkMacOSXDbgMsg("Invalid source drawable");
|
||||
result = BadDrawable;
|
||||
}
|
||||
} else {
|
||||
TkMacOSXDbgMsg("Invalid destination drawable");
|
||||
result = BadDrawable;
|
||||
}
|
||||
TkMacOSXRestoreDrawingContext(&dc);
|
||||
return Success;
|
||||
return result;
|
||||
}
|
||||
|
||||
int
|
||||
TkPutImage(
|
||||
unsigned long *colors, /* Array of pixel values used by this image.
|
||||
* May be NULL. */
|
||||
int ncolors, /* Number of colors used, or 0. */
|
||||
Display *display,
|
||||
Drawable d, /* Destination drawable. */
|
||||
int XPutImage(
|
||||
Display* display,
|
||||
Drawable drawable,
|
||||
GC gc,
|
||||
XImage *image, /* Source image. */
|
||||
int src_x, int src_y, /* Offset of subimage. */
|
||||
int dest_x, int dest_y, /* Position of subimage origin in drawable. */
|
||||
unsigned int width, unsigned int height)
|
||||
/* Dimensions of subimage. */
|
||||
{
|
||||
return XPutImage(display, d, gc, image, src_x, src_y, dest_x, dest_y, width, height);
|
||||
XImage* image,
|
||||
int src_x,
|
||||
int src_y,
|
||||
int dest_x,
|
||||
int dest_y,
|
||||
unsigned int width,
|
||||
unsigned int height) {
|
||||
return TkMacOSXPutImage(IGNORE_ALPHA, display, drawable, gc, image,
|
||||
src_x, src_y, dest_x, dest_y, width, height);
|
||||
}
|
||||
|
||||
int TkPutImage(
|
||||
TCL_UNUSED(unsigned long *),
|
||||
TCL_UNUSED(int),
|
||||
Display* display,
|
||||
Drawable drawable,
|
||||
GC gc,
|
||||
XImage* image,
|
||||
int src_x,
|
||||
int src_y,
|
||||
int dest_x,
|
||||
int dest_y,
|
||||
unsigned int width,
|
||||
unsigned int height) {
|
||||
return TkMacOSXPutImage(IGNORE_ALPHA, display, drawable, gc, image,
|
||||
src_x, src_y, dest_x, dest_y, width, height);
|
||||
}
|
||||
|
||||
int TkpPutRGBAImage(
|
||||
Display* display,
|
||||
Drawable drawable,
|
||||
GC gc,
|
||||
XImage* image,
|
||||
int src_x,
|
||||
int src_y,
|
||||
int dest_x,
|
||||
int dest_y,
|
||||
unsigned int width,
|
||||
unsigned int height) {
|
||||
return TkMacOSXPutImage(USE_ALPHA, display, drawable, gc, image,
|
||||
src_x, src_y, dest_x, dest_y, width, height);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
*----------------------------------------------------------------------
|
||||
*
|
||||
* CreateCGImageFromDrawableRect
|
||||
*
|
||||
* Extract image data from a MacOSX drawable as a CGImage.
|
||||
* Extract image data from a MacOSX drawable as a CGImage. The drawable
|
||||
* may be either a pixmap or a window, but there issues in the case of
|
||||
* a window.
|
||||
*
|
||||
* 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.
|
||||
* CreateCGImageFromDrawableRect is called by XGetImage and XCopyArea.
|
||||
* The Tk core uses these two functions on some platforms in order to
|
||||
* implement explicit double-buffered drawing -- a pixmap is copied from a
|
||||
* window, modified using CPU-based graphics composition, and then copied
|
||||
* back to the window. Platforms, such as macOS, on which the system
|
||||
* provides double-buffered drawing and GPU-based composition operations
|
||||
* can avoid calls to XGetImage and XCopyArea from the core by defining
|
||||
* the compile-time variable TK_NO_DOUBLE_BUFFERING. Nonetheless, these
|
||||
* two functions are in the stubs table and therefore could be used by
|
||||
* extensions.
|
||||
*
|
||||
* This implementation does not work correctly. Originally it relied on
|
||||
* The implementation here does not always work correctly when the source
|
||||
* is a window. The original version of this function 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.
|
||||
* is being used here. However, cacheDisplayInRect works by calling
|
||||
* [NSView drawRect] after setting the current graphics context to be one
|
||||
* which draws to a bitmap. There are situations in which this can be
|
||||
* used, e.g. when taking a screenshot of a window. But it cannot be used
|
||||
* as part of a normal display procedure, using the copy-modify-paste
|
||||
* paradigm that is the basis of the explicit double-buffering. Since the
|
||||
* copy operation will call the same display procedure that is calling
|
||||
* this function via XGetImage or XCopyArea, this would create an infinite
|
||||
* recursion.
|
||||
*
|
||||
* An alternative to the copy-modify-paste paradigm is to use GPU-based
|
||||
* graphics composition, clipping to the specified rectangle. That is
|
||||
* the approach that must be followed by display procedures on macOS.
|
||||
*
|
||||
* Results:
|
||||
* Returns an NSBitmapRep representing the image of the given rectangle of
|
||||
@@ -528,51 +646,43 @@ CreateCGImageFromDrawableRect(
|
||||
{
|
||||
MacDrawable *mac_drawable = (MacDrawable *)drawable;
|
||||
CGContextRef cg_context = NULL;
|
||||
CGRect image_rect = CGRectMake(x, y, width, height);
|
||||
CGImageRef cg_image = NULL, result = NULL;
|
||||
NSBitmapImageRep *bitmapRep = nil;
|
||||
NSView *view = nil;
|
||||
unsigned char *imageData = 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) != nil) {
|
||||
|
||||
/*
|
||||
* 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;
|
||||
if (cg_context) {
|
||||
cg_image = CGBitmapContextCreateImage((CGContextRef) cg_context);
|
||||
}
|
||||
} else {
|
||||
TkMacOSXDbgMsg("Invalid source drawable");
|
||||
NSView *view = TkMacOSXGetNSViewForDrawable(mac_drawable);
|
||||
if (view == nil) {
|
||||
TkMacOSXDbgMsg("Invalid source drawable");
|
||||
return NULL;
|
||||
}
|
||||
NSSize size = view.frame.size;
|
||||
NSUInteger view_width = size.width, view_height = size.height;
|
||||
NSUInteger bytesPerPixel = 4,
|
||||
bytesPerRow = bytesPerPixel * view_width,
|
||||
bitsPerComponent = 8;
|
||||
imageData = ckalloc(view_height * bytesPerRow);
|
||||
CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
|
||||
cg_context = CGBitmapContextCreate(imageData, view_width, view_height,
|
||||
bitsPerComponent, bytesPerRow, colorSpace,
|
||||
kCGImageAlphaPremultipliedLast |
|
||||
kCGBitmapByteOrder32Big);
|
||||
CFRelease(colorSpace);
|
||||
[view.layer renderInContext:cg_context];
|
||||
}
|
||||
if (cg_context) {
|
||||
cg_image = CGBitmapContextCreateImage(cg_context);
|
||||
CGContextRelease(cg_context);
|
||||
}
|
||||
if (cg_image) {
|
||||
result = CGImageCreateWithImageInRect(cg_image, image_rect);
|
||||
CGImageRelease(cg_image);
|
||||
}
|
||||
ckfree(imageData);
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -627,9 +737,6 @@ CreateCGImageFromPixmap(
|
||||
*
|
||||
*----------------------------------------------------------------------
|
||||
*/
|
||||
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(
|
||||
@@ -639,14 +746,13 @@ XGetImage(
|
||||
int y,
|
||||
unsigned int width,
|
||||
unsigned int height,
|
||||
unsigned long plane_mask,
|
||||
TCL_UNUSED(unsigned long), /* plane_mask */
|
||||
int format)
|
||||
{
|
||||
NSBitmapImageRep* bitmapRep = nil;
|
||||
NSUInteger bitmap_fmt = 0;
|
||||
XImage* imagePtr = NULL;
|
||||
char* bitmap = NULL;
|
||||
char R, G, B, A;
|
||||
char *bitmap = NULL;
|
||||
int depth = 32, offset = 0, bitmap_pad = 0;
|
||||
unsigned int bytes_per_row, size, row, n, m;
|
||||
|
||||
@@ -668,49 +774,50 @@ XGetImage(
|
||||
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) {
|
||||
bitmap = (char *)ckalloc(size);
|
||||
if ((bitmap_fmt != 0 && bitmap_fmt != NSBitmapFormatAlphaFirst)
|
||||
|| [bitmapRep samplesPerPixel] != 4
|
||||
|| [bitmapRep isPlanar] != 0
|
||||
|| bytes_per_row < 4 * width
|
||||
|| size != bytes_per_row * height) {
|
||||
TkMacOSXDbgMsg("XGetImage: Unrecognized bitmap format");
|
||||
CFRelease(bitmapRep);
|
||||
[bitmapRep release];
|
||||
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;
|
||||
[bitmapRep release];
|
||||
|
||||
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);
|
||||
pixel32 pixel = *((pixel32 *)(bitmap + m));
|
||||
if (bitmap_fmt == 0) { // default format
|
||||
|
||||
*(bitmap + m) = R;
|
||||
*(bitmap + m + 1) = G;
|
||||
*(bitmap + m + 2) = B;
|
||||
*(bitmap + m + 3) = A;
|
||||
/*
|
||||
* This pixel is in ARGB32 format. We need RGBA32.
|
||||
*/
|
||||
|
||||
pixel32 flipped;
|
||||
flipped.rgba.red = pixel.argb.red;
|
||||
flipped.rgba.green = pixel.argb.green;
|
||||
flipped.rgba.blue = pixel.argb.blue;
|
||||
flipped.rgba.alpha = pixel.argb.alpha;
|
||||
*((pixel32 *)(bitmap + m)) = flipped;
|
||||
} else { // bitmap_fmt = NSBitmapFormatAlphaFirst
|
||||
*((pixel32 *)(bitmap + m)) = pixel;
|
||||
}
|
||||
}
|
||||
}
|
||||
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;
|
||||
|
||||
Reference in New Issue
Block a user