summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorKevin Walzer <kw@codebykevin.com>2016-07-15 10:46:56 (GMT)
committerKevin Walzer <kw@codebykevin.com>2016-07-15 10:46:56 (GMT)
commitdd3deac9990a92730e998c6ae282fe02cde5a700 (patch)
tree5136088d70a7fe010e59b99288f068d4770107b6
parent96e1dfb2816cd8f2790d1a533b7065735fd3c7bf (diff)
downloadtk-dd3deac9990a92730e998c6ae282fe02cde5a700.zip
tk-dd3deac9990a92730e998c6ae282fe02cde5a700.tar.gz
tk-dd3deac9990a92730e998c6ae282fe02cde5a700.tar.bz2
Fix for image/alpha rendering under hidpi/Retina displays on Mac OS; thanks to Marc Culler for assistance
-rw-r--r--generic/tkImgPhInstance.c25
-rw-r--r--macosx/tkMacOSXDraw.c6
-rw-r--r--macosx/tkMacOSXXStubs.c37
-rw-r--r--xlib/X11/Xlib.h3
4 files changed, 60 insertions, 11 deletions
diff --git a/generic/tkImgPhInstance.c b/generic/tkImgPhInstance.c
index 666a9b0..bd152f2 100644
--- a/generic/tkImgPhInstance.c
+++ b/generic/tkImgPhInstance.c
@@ -404,6 +404,9 @@ TkImgPhotoGet(
*
* Note that Win32 pre-defines those operations that we really need.
*
+ * Note that on MacOS, if the background comes from a Retina display
+ * then it will be twice as wide and twice as high as the photoimage.
+ *
*----------------------------------------------------------------------
*/
@@ -433,7 +436,16 @@ BlendComplexAlpha(
unsigned long pixel;
unsigned char r, g, b, alpha, unalpha, *masterPtr;
unsigned char *alphaAr = iPtr->masterPtr->pix32;
-
+#if defined(MAC_OSX_TK)
+ /* Background "pixels" are actually 2^pp x 2^pp blocks of subpixels. Each
+ * block gets blended with the color of one image pixel. Since we iterate
+ * over the background subpixels, we reset the width and height to the
+ * subpixel dimensions of the background image we are using.
+ */
+ int pp = bgImg->pixelpower;
+ width = width << pp;
+ height = height << pp;
+#endif
/*
* This blending is an integer version of the Source-Over compositing rule
* (see Porter&Duff, "Compositing Digital Images", proceedings of SIGGRAPH
@@ -532,9 +544,16 @@ BlendComplexAlpha(
#endif /* !_WIN32 && !MAC_OSX_TK */
for (y = 0; y < height; y++) {
+# if !defined(MAC_OSX_TK)
line = (y + yOffset) * iPtr->masterPtr->width;
for (x = 0; x < width; x++) {
masterPtr = alphaAr + ((line + x + xOffset) * 4);
+#else
+ /* Repeat each image row and column 2^pp times. */
+ line = ((y>>pp) + yOffset) * iPtr->masterPtr->width;
+ for (x = 0; x < width; x++) {
+ masterPtr = alphaAr + ((line + (x>>pp) + xOffset) * 4);
+#endif
alpha = masterPtr[3];
/*
@@ -635,7 +654,9 @@ TkImgPhotoDisplay(
(unsigned int)width, (unsigned int)height, AllPlanes, ZPixmap);
if (bgImg == NULL) {
Tk_DeleteErrorHandler(handler);
- /* We failed to get the image so draw without blending alpha. It's the best we can do */
+ /* We failed to get the image, so draw without blending alpha.
+ * It's the best we can do.
+ */
goto fallBack;
}
diff --git a/macosx/tkMacOSXDraw.c b/macosx/tkMacOSXDraw.c
index d9b909b..f48538d 100644
--- a/macosx/tkMacOSXDraw.c
+++ b/macosx/tkMacOSXDraw.c
@@ -399,9 +399,11 @@ TkPutImage(
CGImageRef img = CreateCGImageWithXImage(image);
if (img) {
+ /* If the XImage has big pixels, rescale the source dimensions.*/
+ int pp = image->pixelpower;
DrawCGImage(d, gc, dc.context, img, gc->foreground, gc->background,
- CGRectMake(0, 0, image->width, image->height),
- CGRectMake(src_x, src_y, width, height),
+ CGRectMake(0, 0, image->width<<pp, image->height<<pp),
+ CGRectMake(src_x<<pp, src_y<<pp, width<<pp, height<<pp),
CGRectMake(dest_x, dest_y, width, height));
CFRelease(img);
} else {
diff --git a/macosx/tkMacOSXXStubs.c b/macosx/tkMacOSXXStubs.c
index 5d6ffb9..a2d175b 100644
--- a/macosx/tkMacOSXXStubs.c
+++ b/macosx/tkMacOSXXStubs.c
@@ -805,6 +805,10 @@ XCreateImage(
ximage->format = format;
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;
@@ -856,7 +860,8 @@ XCreateImage(
* 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.
+ * 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.
@@ -885,7 +890,19 @@ XGetImage(
int bitmap_pad = 0;
int bytes_per_row = 4*width;
int size;
- TkMacOSXDbgMsg("XGetImage");
+ MacDrawable *macDraw = (MacDrawable *) d;
+ 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.
+ */
+ int scalefactor = 1;
+ if (win && [win respondsToSelector:@selector(backingScaleFactor)]) {
+ scalefactor = ([win backingScaleFactor] == 2.0) ? 2 : 1;
+ }
+ int scaled_height = height * scalefactor;
+ int scaled_width = width * scalefactor;
+
if (format == ZPixmap) {
if (width == 0 || height == 0) {
/* This happens all the time.
@@ -894,7 +911,7 @@ XGetImage(
return NULL;
}
- bitmap_rep = BitmapRepFromDrawableRect(d, x, y,width, height);
+ bitmap_rep = BitmapRepFromDrawableRect(d, x, y, width, height);
bitmap_fmt = [bitmap_rep bitmapFormat];
if ( bitmap_rep == Nil ||
@@ -913,7 +930,9 @@ XGetImage(
if ( [bitmap_rep isPlanar ] == 0 &&
[bitmap_rep samplesPerPixel] == 4 ) {
bytes_per_row = [bitmap_rep bytesPerRow];
- size = bytes_per_row*height;
+ 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;
@@ -924,7 +943,7 @@ XGetImage(
*/
if (bitmap_fmt == 0) {
/* BGRA */
- for (row=0, n=0; row<height; row++, n+=bytes_per_row) {
+ for (row=0, n=0; row<scaled_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);
@@ -934,7 +953,7 @@ XGetImage(
}
} else {
/* ABGR */
- for (row=0, n=0; row<height; row++, n+=bytes_per_row) {
+ for (row=0, n=0; row<scaled_height; row++, n+=bytes_per_row) {
for (m=n; m<n+bytes_per_row; m+=4) {
*(bitmap+m) = *(image_data+m+3);
*(bitmap+m+1) = *(image_data+m+2);
@@ -947,7 +966,11 @@ XGetImage(
}
if (bitmap) {
imagePtr = XCreateImage(display, NULL, depth, format, offset,
- (char*)bitmap, width, height, bitmap_pad, bytes_per_row);
+ (char*)bitmap, scaled_width, scaled_height,
+ bitmap_pad, bytes_per_row);
+ if (scalefactor == 2) {
+ imagePtr->pixelpower = 1;
+ }
[ns_image removeRepresentation:bitmap_rep]; /*releases the rep*/
[ns_image release];
}
diff --git a/xlib/X11/Xlib.h b/xlib/X11/Xlib.h
index 667bdc7..8d8ec68 100644
--- a/xlib/X11/Xlib.h
+++ b/xlib/X11/Xlib.h
@@ -330,6 +330,9 @@ typedef struct _XImage {
unsigned long green_mask;
unsigned long blue_mask;
XPointer obdata; /* hook for the object routines to hang on */
+#if defined(MAC_OSX_TK)
+ int pixelpower; /* n such that pixels are 2^n x 2^n blocks*/
+#endif
struct funcs { /* image manipulation routines */
struct _XImage *(*create_image)();
#if NeedFunctionPrototypes