From 67b1053dcd958d21a964dc09c2ba9666e11240b2 Mon Sep 17 00:00:00 2001 From: Eli Zaretskii Date: Sun, 20 Jan 2019 17:59:12 +0200 Subject: [PATCH] Support native image resizing on MS-Windows * src/w32term.c (x_draw_image_foreground): Scale the image if the requested dimensions are different from the bitmap dimensions. * src/image.c (Fimage_scaling_p): Return t when HAVE_NTGUI. (x_set_image_size) [HAVE_NTGUI]: Record the scaled dimensions in the image struct. * src/dispextern.h (HAVE_NATIVE_SCALING): Define when HAVE_NTGUI as well. * etc/NEWS: Update the announcement of native image scaling. --- etc/NEWS | 8 +++-- src/dispextern.h | 2 +- src/image.c | 8 ++++- src/w32term.c | 76 +++++++++++++++++++++++++++++++++++++++++------- 4 files changed, 79 insertions(+), 15 deletions(-) diff --git a/etc/NEWS b/etc/NEWS index 9d91a30a583..21187474a28 100644 --- a/etc/NEWS +++ b/etc/NEWS @@ -1505,8 +1505,12 @@ buffer's 'default-directory' and invoke that file name handler to make the process. That way 'make-process' can start remote processes. +++ -** Emacs now supports resizing images without ImageMagick on X window -systems where the XRender extension is available, and on the NS port. +** Emacs now supports resizing (scaling) of images without ImageMagick. +All modern systems are supported by this feature. (On GNU and Unix +systems, the XRender extension to X11 is required for this to be +available; the configure script will test for it and, if found, enable +scaling.) + The new function 'image-scaling-p' can be used to test whether any given frame supports resizing. diff --git a/src/dispextern.h b/src/dispextern.h index 9cea3218c16..894753669d0 100644 --- a/src/dispextern.h +++ b/src/dispextern.h @@ -2938,7 +2938,7 @@ struct redisplay_interface #ifdef HAVE_WINDOW_SYSTEM -# if defined HAVE_XRENDER || defined HAVE_NS +# if defined HAVE_XRENDER || defined HAVE_NS || defined HAVE_NTGUI # define HAVE_NATIVE_SCALING # endif diff --git a/src/image.c b/src/image.c index bcc61dfccda..20148605817 100644 --- a/src/image.c +++ b/src/image.c @@ -1900,6 +1900,12 @@ x_set_image_size (struct frame *f, struct image *img) img->height = height; } # endif +# ifdef HAVE_NTGUI + /* Under HAVE_NTGUI, we will scale the image on the fly, when we + draw it. See w32term.c:x_draw_image_foreground. */ + img->width = width; + img->height = height; +# endif #endif } @@ -9915,7 +9921,7 @@ DEFUN ("image-scaling-p", Fimage_scaling_p, Simage_scaling_p, 0, 1, 0, Return t if FRAME supports native scaling, nil otherwise. */) (Lisp_Object frame) { -#ifdef HAVE_NS +#if defined (HAVE_NS) || defined (HAVE_NTGUI) return Qt; #elif defined (HAVE_X_WINDOWS) && defined (HAVE_XRENDER) int event_basep, error_basep; diff --git a/src/w32term.c b/src/w32term.c index d13763d7db3..6fc86124199 100644 --- a/src/w32term.c +++ b/src/w32term.c @@ -1874,9 +1874,24 @@ x_draw_image_foreground (struct glyph_string *s) HBRUSH fg_brush = CreateSolidBrush (s->gc->foreground); HBRUSH orig_brush = SelectObject (s->hdc, fg_brush); HGDIOBJ orig_obj = SelectObject (compat_hdc, s->img->pixmap); + LONG orig_width, orig_height; + DIBSECTION dib; SetBkColor (compat_hdc, RGB (255, 255, 255)); SetTextColor (s->hdc, RGB (0, 0, 0)); x_set_glyph_string_clipping (s); + /* Extract the original dimensions of the bitmap. */ + if (GetObject (s->img->pixmap, sizeof (dib), &dib) > 0) + { + BITMAP bmp = dib.dsBm; + orig_width = bmp.bmWidth; + orig_height = bmp.bmHeight; + } + else + { + DebPrint (("x_draw_image_foreground: GetObject failed!\n")); + orig_width = s->slice.width; + orig_height = s->slice.height; + } if (s->img->mask) { @@ -1885,14 +1900,36 @@ x_draw_image_foreground (struct glyph_string *s) SetTextColor (s->hdc, RGB (255, 255, 255)); SetBkColor (s->hdc, RGB (0, 0, 0)); - - BitBlt (s->hdc, x, y, s->slice.width, s->slice.height, - compat_hdc, s->slice.x, s->slice.y, SRCINVERT); - BitBlt (s->hdc, x, y, s->slice.width, s->slice.height, - mask_dc, s->slice.x, s->slice.y, SRCAND); - BitBlt (s->hdc, x, y, s->slice.width, s->slice.height, - compat_hdc, s->slice.x, s->slice.y, SRCINVERT); - + if (s->slice.width == orig_width && s->slice.height == orig_height) + { + BitBlt (s->hdc, x, y, s->slice.width, s->slice.height, + compat_hdc, s->slice.x, s->slice.y, SRCINVERT); + BitBlt (s->hdc, x, y, s->slice.width, s->slice.height, + mask_dc, s->slice.x, s->slice.y, SRCAND); + BitBlt (s->hdc, x, y, s->slice.width, s->slice.height, + compat_hdc, s->slice.x, s->slice.y, SRCINVERT); + } + else + { + int pmode = 0; + /* HALFTONE produces better results, especially when + scaling to a larger size, but Windows 9X doesn't + support HALFTONE. */ + if (os_subtype == OS_NT + && (pmode = SetStretchBltMode (s->hdc, HALFTONE)) != 0) + SetBrushOrgEx (s->hdc, 0, 0, NULL); + StretchBlt (s->hdc, x, y, s->slice.width, s->slice.height, + compat_hdc, s->slice.x, s->slice.y, + orig_width, orig_height, SRCINVERT); + StretchBlt (s->hdc, x, y, s->slice.width, s->slice.height, + mask_dc, s->slice.x, s->slice.y, + orig_width, orig_height, SRCAND); + StretchBlt (s->hdc, x, y, s->slice.width, s->slice.height, + compat_hdc, s->slice.x, s->slice.y, + orig_width, orig_height, SRCINVERT); + if (pmode) + SetStretchBltMode (s->hdc, pmode); + } SelectObject (mask_dc, mask_orig_obj); DeleteDC (mask_dc); } @@ -1900,9 +1937,22 @@ x_draw_image_foreground (struct glyph_string *s) { SetTextColor (s->hdc, s->gc->foreground); SetBkColor (s->hdc, s->gc->background); - - BitBlt (s->hdc, x, y, s->slice.width, s->slice.height, - compat_hdc, s->slice.x, s->slice.y, SRCCOPY); + if (s->slice.width == orig_width && s->slice.height == orig_height) + BitBlt (s->hdc, x, y, s->slice.width, s->slice.height, + compat_hdc, s->slice.x, s->slice.y, SRCCOPY); + else + { + int pmode = 0; + /* Windows 9X doesn't support HALFTONE. */ + if (os_subtype == OS_NT + && (pmode = SetStretchBltMode (s->hdc, HALFTONE)) != 0) + SetBrushOrgEx (s->hdc, 0, 0, NULL); + StretchBlt (s->hdc, x, y, s->slice.width, s->slice.height, + compat_hdc, s->slice.x, s->slice.y, + orig_width, orig_height, SRCCOPY); + if (pmode) + SetStretchBltMode (s->hdc, pmode); + } /* When the image has a mask, we can expect that at least part of a mouse highlight or a block cursor will @@ -2031,6 +2081,10 @@ w32_draw_image_foreground_1 (struct glyph_string *s, HBITMAP pixmap) if (s->slice.y == 0) y += s->img->vmargin; + /* FIXME (maybe): The below doesn't support image scaling. But it + seems to never be called, because the conditions for its call in + x_draw_image_glyph_string are never fulfilled (they will be if + the #ifdef'ed away part of that function is ever activated). */ if (s->img->pixmap) { HDC compat_hdc = CreateCompatibleDC (hdc); -- 2.39.2