Add native image scaling (bug#33587)
* configure.ac: Test for XRender outside of xft checks. * src/Makefile.in (XRENDER_LIBS): List XRender libs separately from xft libs. * lisp/image.el (image--get-imagemagick-and-warn): Allow resizing if native scaling is available. * src/dispextern.h: Add XRender and image scaling stuff. (struct image): Add XRender Pictures. * src/image.c (x_create_bitmap_mask): (image_create_x_image_and_pixmap): Handle XRender Picture. (scale_image_size): (compute_image_size): Make available when any form of scaling is enabled. (x_set_image_size): New function. (lookup_image): Set image size. (x_create_x_image_and_pixmap): Create XRender Picture when necessary. (x_put_x_image): Handle the case where desired size != actual size. (free_image): Free XRender Pictures. (Fimage_scaling_p): New function. (syms_of_image): Add image-scaling-p. * src/nsimage.m (ns_load_image): Remove NS specific resizing. ([EmacsImage setSizeFromSpec:]): Remove method. (ns_image_set_size): New function. * src/nsterm.m (ns_draw_fringe_bitmap): Cocoa and GNUstep both have the same compositing functions, so remove unnecessary difference. * src/xterm.c (x_composite_image): New function. (x_draw_image_foreground): Use new x_composite_image function. * doc/lispref/display.texi (Image Descriptors): Document image-scaling-p and add resizing descriptors. (ImageMagick Images): Remove resizing descriptors.
This commit is contained in:
parent
c342b26371
commit
a1b7a3f2a3
11 changed files with 345 additions and 233 deletions
14
configure.ac
14
configure.ac
|
@ -3241,6 +3241,17 @@ either XPointer or XPointer*.])dnl
|
|||
CFLAGS=$late_CFLAGS
|
||||
fi
|
||||
|
||||
# Check for XRender
|
||||
HAVE_XRENDER=no
|
||||
if test "${HAVE_X11}" = "yes"; then
|
||||
AC_CHECK_LIB(Xrender, XRenderQueryExtension, HAVE_XRENDER=yes)
|
||||
if test $HAVE_XRENDER = yes; then
|
||||
XRENDER_LIBS="-lXrender"
|
||||
AC_SUBST(XRENDER_LIBS)
|
||||
AC_DEFINE([HAVE_XRENDER], 1, [Define to 1 if XRender is available.])
|
||||
fi
|
||||
fi
|
||||
|
||||
### Start of font-backend (under any platform) section.
|
||||
# (nothing here yet -- this is a placeholder)
|
||||
### End of font-backend (under any platform) section.
|
||||
|
@ -3263,15 +3274,12 @@ if test "${HAVE_X11}" = "yes"; then
|
|||
EMACS_CHECK_MODULES([XFT], [xft >= 0.13.0], [], [HAVE_XFT=no])
|
||||
## Because xterm.c uses XRenderQueryExtension when XFT is
|
||||
## enabled, we also need to link to -lXrender.
|
||||
HAVE_XRENDER=no
|
||||
AC_CHECK_LIB(Xrender, XRenderQueryExtension, HAVE_XRENDER=yes)
|
||||
if test "$HAVE_XFT" != no && test "$HAVE_XRENDER" != no; then
|
||||
OLD_CPPFLAGS="$CPPFLAGS"
|
||||
OLD_CFLAGS="$CFLAGS"
|
||||
OLD_LIBS="$LIBS"
|
||||
CPPFLAGS="$CPPFLAGS $XFT_CFLAGS"
|
||||
CFLAGS="$CFLAGS $XFT_CFLAGS"
|
||||
XFT_LIBS="-lXrender $XFT_LIBS"
|
||||
LIBS="$XFT_LIBS $LIBS"
|
||||
AC_CHECK_HEADER(X11/Xft/Xft.h,
|
||||
AC_CHECK_LIB(Xft, XftFontOpen, HAVE_XFT=yes, , $XFT_LIBS) , ,
|
||||
|
|
|
@ -5112,6 +5112,47 @@ This adds a shadow rectangle around the image. The value,
|
|||
@var{relief} is negative, shadows are drawn so that the image appears
|
||||
as a pressed button; otherwise, it appears as an unpressed button.
|
||||
|
||||
@item :width @var{width}, :height @var{height}
|
||||
The @code{:width} and @code{:height} keywords are used for scaling the
|
||||
image. If only one of them is specified, the other one will be
|
||||
calculated so as to preserve the aspect ratio. If both are specified,
|
||||
aspect ratio may not be preserved.
|
||||
|
||||
@item :max-width @var{max-width}, :max-height @var{max-height}
|
||||
The @code{:max-width} and @code{:max-height} keywords are used for
|
||||
scaling if the size of the image exceeds these values. If
|
||||
@code{:width} is set, it will have precedence over @code{max-width},
|
||||
and if @code{:height} is set, it will have precedence over
|
||||
@code{max-height}, but you can otherwise mix these keywords as you
|
||||
wish.
|
||||
|
||||
If both @code{:max-width} and @code{:height} are specified, but
|
||||
@code{:width} is not, preserving the aspect ratio might require that
|
||||
width exceeds @code{:max-width}. If this happens, scaling will use a
|
||||
smaller value for the height so as to preserve the aspect ratio while
|
||||
not exceeding @code{:max-width}. Similarly when both
|
||||
@code{:max-height} and @code{:width} are specified, but @code{:height}
|
||||
is not. For example, if you have a 200x100 image and specify that
|
||||
@code{:width} should be 400 and @code{:max-height} should be 150,
|
||||
you'll end up with an image that is 300x150: Preserving the aspect
|
||||
ratio and not exceeding the ``max'' setting. This combination of
|
||||
parameters is a useful way of saying ``display this image as large as
|
||||
possible, but no larger than the available display area''.
|
||||
|
||||
@item :scale @var{scale}
|
||||
This should be a number, where values higher than 1 means to increase
|
||||
the size, and lower means to decrease the size, by multiplying both
|
||||
the width and height. For instance, a value of 0.25 will make the
|
||||
image a quarter size of what it originally was. If the scaling makes
|
||||
the image larger than specified by @code{:max-width} or
|
||||
@code{:max-height}, the resulting size will not exceed those two
|
||||
values. If both @code{:scale} and @code{:height}/@code{:width} are
|
||||
specified, the height/width will be adjusted by the specified scaling
|
||||
factor.
|
||||
|
||||
@item :index @var{frame}
|
||||
@xref{Multi-Frame Images}.
|
||||
|
||||
@item :conversion @var{algorithm}
|
||||
This specifies a conversion algorithm that should be applied to the
|
||||
image before it is displayed; the value, @var{algorithm}, specifies
|
||||
|
@ -5251,6 +5292,16 @@ This function returns @code{t} if image @var{spec} has a mask bitmap.
|
|||
(@pxref{Input Focus}).
|
||||
@end defun
|
||||
|
||||
@defun image-scaling-p &optional frame
|
||||
This function returns @code{t} if @var{frame} supports image scaling.
|
||||
@var{frame} @code{nil} or omitted means to use the selected frame
|
||||
(@pxref{Input Focus}).
|
||||
|
||||
If image scaling is not supported, @code{:width}, @code{:height},
|
||||
@code{:scale}, @code{:max-width} and @code{:max-height} will only be
|
||||
usable through ImageMagick, if available (@pxref{ImageMagick Images}).
|
||||
@end defun
|
||||
|
||||
@node XBM Images
|
||||
@subsection XBM Images
|
||||
@cindex XBM
|
||||
|
@ -5387,42 +5438,6 @@ color, which is used as the image's background color if the image
|
|||
supports transparency. If the value is @code{nil}, it defaults to the
|
||||
frame's background color.
|
||||
|
||||
@item :width @var{width}, :height @var{height}
|
||||
The @code{:width} and @code{:height} keywords are used for scaling the
|
||||
image. If only one of them is specified, the other one will be
|
||||
calculated so as to preserve the aspect ratio. If both are specified,
|
||||
aspect ratio may not be preserved.
|
||||
|
||||
@item :max-width @var{max-width}, :max-height @var{max-height}
|
||||
The @code{:max-width} and @code{:max-height} keywords are used for
|
||||
scaling if the size of the image of the image exceeds these values.
|
||||
If @code{:width} is set it will have precedence over @code{max-width},
|
||||
and if @code{:height} is set it will have precedence over
|
||||
@code{max-height}, but you can otherwise mix these keywords as you
|
||||
wish. @code{:max-width} and @code{:max-height} will always preserve
|
||||
the aspect ratio.
|
||||
|
||||
If both @code{:width} and @code{:max-height} has been set (but
|
||||
@code{:height} has not been set), then @code{:max-height} will have
|
||||
precedence. The same is the case for the opposite combination: The
|
||||
``max'' keyword has precedence. That is, if you have a 200x100 image
|
||||
and specify that @code{:width} should be 400 and @code{:max-height}
|
||||
should be 150, you'll end up with an image that is 300x150: Preserving
|
||||
the aspect ratio and not exceeding the ``max'' setting. This
|
||||
combination of parameters is a useful way of saying ``display this
|
||||
image as large as possible, but no larger than the available display
|
||||
area''.
|
||||
|
||||
@item :scale @var{scale}
|
||||
This should be a number, where values higher than 1 means to increase
|
||||
the size, and lower means to decrease the size. For instance, a value
|
||||
of 0.25 will make the image a quarter size of what it originally was.
|
||||
If the scaling makes the image larger than specified by
|
||||
@code{:max-width} or @code{:max-height}, the resulting size will not
|
||||
exceed those two values. If both @code{:scale} and
|
||||
@code{:height}/@code{:width} are specified, the height/width will be
|
||||
adjusted by the specified scaling factor.
|
||||
|
||||
@item :format @var{type}
|
||||
The value, @var{type}, should be a symbol specifying the type of the
|
||||
image data, as found in @code{image-format-suffixes}. This is used
|
||||
|
@ -5431,9 +5446,6 @@ hint to ImageMagick to help it detect the image type.
|
|||
|
||||
@item :rotation @var{angle}
|
||||
Specifies a rotation angle in degrees.
|
||||
|
||||
@item :index @var{frame}
|
||||
@xref{Multi-Frame Images}.
|
||||
@end table
|
||||
|
||||
@node SVG Images
|
||||
|
|
6
etc/NEWS
6
etc/NEWS
|
@ -1461,6 +1461,12 @@ that is non-nil, it will look for a file name handler for the current
|
|||
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.
|
||||
The new function 'image-scaling-p' can be used to test whether any
|
||||
given frame supports resizing.
|
||||
|
||||
|
||||
* Changes in Emacs 27.1 on Non-Free Operating Systems
|
||||
|
||||
|
|
|
@ -982,8 +982,8 @@ default is 20%."
|
|||
image))
|
||||
|
||||
(defun image--get-imagemagick-and-warn ()
|
||||
(unless (or (fboundp 'imagemagick-types) (featurep 'ns))
|
||||
(error "Cannot rescale images without ImageMagick support"))
|
||||
(unless (or (fboundp 'imagemagick-types) (image-scaling-p))
|
||||
(error "Cannot rescale images on this terminal"))
|
||||
(let ((image (image--get-image)))
|
||||
(image-flush image)
|
||||
(when (fboundp 'imagemagick-types)
|
||||
|
|
|
@ -127,7 +127,8 @@ LIBIMAGE=@LIBTIFF@ @LIBJPEG@ @LIBPNG@ @LIBGIF@ @LIBXPM@
|
|||
|
||||
XCB_LIBS=@XCB_LIBS@
|
||||
XFT_LIBS=@XFT_LIBS@
|
||||
LIBX_EXTRA=-lX11 $(XCB_LIBS) $(XFT_LIBS)
|
||||
XRENDER_LIBS=@XRENDER_LIBS@
|
||||
LIBX_EXTRA=-lX11 $(XCB_LIBS) $(XFT_LIBS) $(XRENDER_LIBS)
|
||||
|
||||
FONTCONFIG_CFLAGS = @FONTCONFIG_CFLAGS@
|
||||
FONTCONFIG_LIBS = @FONTCONFIG_LIBS@
|
||||
|
|
|
@ -31,6 +31,9 @@ along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */
|
|||
#include <X11/Intrinsic.h>
|
||||
#endif /* USE_X_TOOLKIT */
|
||||
|
||||
#ifdef HAVE_XRENDER
|
||||
#include <X11/extensions/Xrender.h>
|
||||
#endif
|
||||
#else /* !HAVE_X_WINDOWS */
|
||||
|
||||
/* X-related stuff used by non-X gui code. */
|
||||
|
@ -2935,6 +2938,11 @@ struct redisplay_interface
|
|||
|
||||
#ifdef HAVE_WINDOW_SYSTEM
|
||||
|
||||
#if defined (HAVE_X_WINDOWS) && defined (HAVE_XRENDER) \
|
||||
|| defined (HAVE_NS)
|
||||
#define HAVE_NATIVE_SCALING
|
||||
#endif
|
||||
|
||||
/* Structure describing an image. Specific image formats like XBM are
|
||||
converted into this form, so that display only has to deal with
|
||||
this type of image. */
|
||||
|
@ -2958,6 +2966,11 @@ struct image
|
|||
and the latter is outdated. NULL means the X image has been
|
||||
synchronized to Pixmap. */
|
||||
XImagePtr ximg, mask_img;
|
||||
|
||||
#ifdef HAVE_NATIVE_SCALING
|
||||
/* Picture versions of pixmap and mask for compositing. */
|
||||
Picture picture, mask_picture;
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/* Colors allocated for this image, if any. Allocated via xmalloc. */
|
||||
|
|
312
src/image.c
312
src/image.c
|
@ -408,8 +408,13 @@ x_destroy_all_bitmaps (Display_Info *dpyinfo)
|
|||
dpyinfo->bitmaps_last = 0;
|
||||
}
|
||||
|
||||
#ifndef HAVE_XRENDER
|
||||
/* Required for the definition of x_create_x_image_and_pixmap below. */
|
||||
typedef void Picture;
|
||||
#endif
|
||||
|
||||
static bool x_create_x_image_and_pixmap (struct frame *, int, int, int,
|
||||
XImagePtr *, Pixmap *);
|
||||
XImagePtr *, Pixmap *, Picture *);
|
||||
static void x_destroy_x_image (XImagePtr ximg);
|
||||
|
||||
#ifdef HAVE_NTGUI
|
||||
|
@ -472,7 +477,8 @@ x_create_bitmap_mask (struct frame *f, ptrdiff_t id)
|
|||
return;
|
||||
}
|
||||
|
||||
result = x_create_x_image_and_pixmap (f, width, height, 1, &mask_img, &mask);
|
||||
result = x_create_x_image_and_pixmap (f, width, height, 1,
|
||||
&mask_img, &mask, NULL);
|
||||
|
||||
unblock_input ();
|
||||
if (!result)
|
||||
|
@ -1011,6 +1017,13 @@ free_image (struct frame *f, struct image *img)
|
|||
|
||||
c->images[img->id] = NULL;
|
||||
|
||||
#ifdef HAVE_XRENDER
|
||||
if (img->picture)
|
||||
XRenderFreePicture (FRAME_X_DISPLAY (f), img->picture);
|
||||
if (img->mask_picture)
|
||||
XRenderFreePicture (FRAME_X_DISPLAY (f), img->mask_picture);
|
||||
#endif
|
||||
|
||||
/* Windows NT redefines 'free', but in this file, we need to
|
||||
avoid the redefinition. */
|
||||
#ifdef WINDOWSNT
|
||||
|
@ -1747,6 +1760,147 @@ postprocess_image (struct frame *f, struct image *img)
|
|||
}
|
||||
}
|
||||
|
||||
#if defined (HAVE_IMAGEMAGICK) || defined (HAVE_NATIVE_SCALING)
|
||||
/* Scale an image size by returning SIZE / DIVISOR * MULTIPLIER,
|
||||
safely rounded and clipped to int range. */
|
||||
|
||||
static int
|
||||
scale_image_size (int size, size_t divisor, size_t multiplier)
|
||||
{
|
||||
if (divisor != 0)
|
||||
{
|
||||
double s = size;
|
||||
double scaled = s * multiplier / divisor + 0.5;
|
||||
if (scaled < INT_MAX)
|
||||
return scaled;
|
||||
}
|
||||
return INT_MAX;
|
||||
}
|
||||
|
||||
/* Compute the desired size of an image with native size WIDTH x HEIGHT.
|
||||
Use SPEC to deduce the size. Store the desired size into
|
||||
*D_WIDTH x *D_HEIGHT. Store -1 x -1 if the native size is OK. */
|
||||
static void
|
||||
compute_image_size (size_t width, size_t height,
|
||||
Lisp_Object spec,
|
||||
int *d_width, int *d_height)
|
||||
{
|
||||
Lisp_Object value;
|
||||
int desired_width = -1, desired_height = -1, max_width = -1, max_height = -1;
|
||||
double scale = 1;
|
||||
|
||||
value = image_spec_value (spec, QCscale, NULL);
|
||||
if (NUMBERP (value))
|
||||
scale = XFLOATINT (value);
|
||||
|
||||
value = image_spec_value (spec, QCmax_width, NULL);
|
||||
if (FIXNATP (value))
|
||||
max_width = min (XFIXNAT (value), INT_MAX);
|
||||
|
||||
value = image_spec_value (spec, QCmax_height, NULL);
|
||||
if (FIXNATP (value))
|
||||
max_height = min (XFIXNAT (value), INT_MAX);
|
||||
|
||||
/* If width and/or height is set in the display spec assume we want
|
||||
to scale to those values. If either h or w is unspecified, the
|
||||
unspecified should be calculated from the specified to preserve
|
||||
aspect ratio. */
|
||||
value = image_spec_value (spec, QCwidth, NULL);
|
||||
if (FIXNATP (value))
|
||||
{
|
||||
desired_width = min (XFIXNAT (value) * scale, INT_MAX);
|
||||
/* :width overrides :max-width. */
|
||||
max_width = -1;
|
||||
}
|
||||
|
||||
value = image_spec_value (spec, QCheight, NULL);
|
||||
if (FIXNATP (value))
|
||||
{
|
||||
desired_height = min (XFIXNAT (value) * scale, INT_MAX);
|
||||
/* :height overrides :max-height. */
|
||||
max_height = -1;
|
||||
}
|
||||
|
||||
/* If we have both width/height set explicitly, we skip past all the
|
||||
aspect ratio-preserving computations below. */
|
||||
if (desired_width != -1 && desired_height != -1)
|
||||
goto out;
|
||||
|
||||
width = width * scale;
|
||||
height = height * scale;
|
||||
|
||||
if (desired_width != -1)
|
||||
/* Width known, calculate height. */
|
||||
desired_height = scale_image_size (desired_width, width, height);
|
||||
else if (desired_height != -1)
|
||||
/* Height known, calculate width. */
|
||||
desired_width = scale_image_size (desired_height, height, width);
|
||||
else
|
||||
{
|
||||
desired_width = width;
|
||||
desired_height = height;
|
||||
}
|
||||
|
||||
if (max_width != -1 && desired_width > max_width)
|
||||
{
|
||||
/* The image is wider than :max-width. */
|
||||
desired_width = max_width;
|
||||
desired_height = scale_image_size (desired_width, width, height);
|
||||
}
|
||||
|
||||
if (max_height != -1 && desired_height > max_height)
|
||||
{
|
||||
/* The image is higher than :max-height. */
|
||||
desired_height = max_height;
|
||||
desired_width = scale_image_size (desired_height, height, width);
|
||||
}
|
||||
|
||||
out:
|
||||
*d_width = desired_width;
|
||||
*d_height = desired_height;
|
||||
}
|
||||
|
||||
#ifdef HAVE_NATIVE_SCALING
|
||||
static void
|
||||
x_set_image_size (struct frame *f, struct image *img)
|
||||
{
|
||||
#ifdef HAVE_IMAGEMAGICK
|
||||
/* ImageMagick images are already the correct size. */
|
||||
if (!EQ (image_spec_value (img->spec, QCtype, NULL), Qimagemagick))
|
||||
#endif
|
||||
{
|
||||
int width, height;
|
||||
|
||||
compute_image_size (img->width, img->height, img->spec, &width, &height);
|
||||
|
||||
#ifdef HAVE_NS
|
||||
ns_image_set_size (img->pixmap, width, height);
|
||||
img->width = width;
|
||||
img->height = height;
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_XRENDER
|
||||
if (img->picture)
|
||||
{
|
||||
double xscale = (double) img->width/width;
|
||||
double yscale = (double) img->height/height;
|
||||
|
||||
XTransform tmat = {{{XDoubleToFixed (xscale), XDoubleToFixed (0), XDoubleToFixed (0)},
|
||||
{XDoubleToFixed (0), XDoubleToFixed (yscale), XDoubleToFixed (0)},
|
||||
{XDoubleToFixed (0), XDoubleToFixed (0), XDoubleToFixed (1)}}};
|
||||
|
||||
XRenderSetPictureFilter (FRAME_X_DISPLAY (f), img->picture, FilterBest, 0, 0);
|
||||
XRenderSetPictureTransform (FRAME_X_DISPLAY (f), img->picture, &tmat);
|
||||
|
||||
img->width = width;
|
||||
img->height = height;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
#endif
|
||||
#endif /* HAVE_IMAGEMAGICK || HAVE_XRENDER || HAVE_NS */
|
||||
|
||||
|
||||
/* Return the id of image with Lisp specification SPEC on frame F.
|
||||
SPEC must be a valid Lisp image specification (see valid_image_p). */
|
||||
|
@ -1802,6 +1956,9 @@ lookup_image (struct frame *f, Lisp_Object spec)
|
|||
`:background COLOR'. */
|
||||
Lisp_Object ascent, margin, relief, bg;
|
||||
int relief_bound;
|
||||
#ifdef HAVE_NATIVE_SCALING
|
||||
x_set_image_size (f, img);
|
||||
#endif
|
||||
|
||||
ascent = image_spec_value (spec, QCascent, NULL);
|
||||
if (FIXNUMP (ascent))
|
||||
|
@ -1976,12 +2133,15 @@ x_check_image_size (XImagePtr ximg, int width, int height)
|
|||
|
||||
static bool
|
||||
x_create_x_image_and_pixmap (struct frame *f, int width, int height, int depth,
|
||||
XImagePtr *ximg, Pixmap *pixmap)
|
||||
XImagePtr *ximg, Pixmap *pixmap, Picture *picture)
|
||||
{
|
||||
#ifdef HAVE_X_WINDOWS
|
||||
Display *display = FRAME_X_DISPLAY (f);
|
||||
Drawable drawable = FRAME_X_DRAWABLE (f);
|
||||
Screen *screen = FRAME_X_SCREEN (f);
|
||||
#ifdef HAVE_XRENDER
|
||||
int event_basep, error_basep;
|
||||
#endif
|
||||
|
||||
eassert (input_blocked_p ());
|
||||
|
||||
|
@ -2018,6 +2178,21 @@ x_create_x_image_and_pixmap (struct frame *f, int width, int height, int depth,
|
|||
return 0;
|
||||
}
|
||||
|
||||
#ifdef HAVE_XRENDER
|
||||
if (picture && XRenderQueryExtension (display, &event_basep, &error_basep))
|
||||
{
|
||||
XRenderPictFormat *format;
|
||||
XRenderPictureAttributes attr;
|
||||
|
||||
/* FIXME: Do we need to handle all possible bit depths? */
|
||||
format = XRenderFindStandardFormat (display,
|
||||
depth > 24 ? PictStandardARGB32
|
||||
: depth > 8 ? PictStandardRGB24
|
||||
: PictStandardA8);
|
||||
*picture = XRenderCreatePicture (display, *pixmap, format, 0, &attr);
|
||||
}
|
||||
#endif
|
||||
|
||||
return 1;
|
||||
#endif /* HAVE_X_WINDOWS */
|
||||
|
||||
|
@ -2163,7 +2338,8 @@ x_put_x_image (struct frame *f, XImagePtr ximg, Pixmap pixmap, int width, int he
|
|||
|
||||
eassert (input_blocked_p ());
|
||||
gc = XCreateGC (FRAME_X_DISPLAY (f), pixmap, 0, NULL);
|
||||
XPutImage (FRAME_X_DISPLAY (f), pixmap, gc, ximg, 0, 0, 0, 0, width, height);
|
||||
XPutImage (FRAME_X_DISPLAY (f), pixmap, gc, ximg, 0, 0, 0, 0,
|
||||
ximg->width, ximg->height);
|
||||
XFreeGC (FRAME_X_DISPLAY (f), gc);
|
||||
#endif /* HAVE_X_WINDOWS */
|
||||
|
||||
|
@ -2192,7 +2368,13 @@ image_create_x_image_and_pixmap (struct frame *f, struct image *img,
|
|||
eassert ((!mask_p ? img->pixmap : img->mask) == NO_PIXMAP);
|
||||
|
||||
return x_create_x_image_and_pixmap (f, width, height, depth, ximg,
|
||||
!mask_p ? &img->pixmap : &img->mask);
|
||||
!mask_p ? &img->pixmap : &img->mask,
|
||||
#ifdef HAVE_XRENDER
|
||||
!mask_p ? &img->picture : &img->mask_picture
|
||||
#else
|
||||
NULL
|
||||
#endif
|
||||
);
|
||||
}
|
||||
|
||||
/* Put X image XIMG into image IMG on frame F, as a mask if and only
|
||||
|
@ -8101,105 +8283,6 @@ gif_load (struct frame *f, struct image *img)
|
|||
ImageMagick
|
||||
***********************************************************************/
|
||||
|
||||
/* Scale an image size by returning SIZE / DIVISOR * MULTIPLIER,
|
||||
safely rounded and clipped to int range. */
|
||||
|
||||
static int
|
||||
scale_image_size (int size, size_t divisor, size_t multiplier)
|
||||
{
|
||||
if (divisor != 0)
|
||||
{
|
||||
double s = size;
|
||||
double scaled = s * multiplier / divisor + 0.5;
|
||||
if (scaled < INT_MAX)
|
||||
return scaled;
|
||||
}
|
||||
return INT_MAX;
|
||||
}
|
||||
|
||||
/* Compute the desired size of an image with native size WIDTH x HEIGHT.
|
||||
Use SPEC to deduce the size. Store the desired size into
|
||||
*D_WIDTH x *D_HEIGHT. Store -1 x -1 if the native size is OK. */
|
||||
static void
|
||||
compute_image_size (size_t width, size_t height,
|
||||
Lisp_Object spec,
|
||||
int *d_width, int *d_height)
|
||||
{
|
||||
Lisp_Object value;
|
||||
int desired_width = -1, desired_height = -1, max_width = -1, max_height = -1;
|
||||
double scale = 1;
|
||||
|
||||
value = image_spec_value (spec, QCscale, NULL);
|
||||
if (NUMBERP (value))
|
||||
scale = XFLOATINT (value);
|
||||
|
||||
value = image_spec_value (spec, QCmax_width, NULL);
|
||||
if (FIXNATP (value))
|
||||
max_width = min (XFIXNAT (value), INT_MAX);
|
||||
|
||||
value = image_spec_value (spec, QCmax_height, NULL);
|
||||
if (FIXNATP (value))
|
||||
max_height = min (XFIXNAT (value), INT_MAX);
|
||||
|
||||
/* If width and/or height is set in the display spec assume we want
|
||||
to scale to those values. If either h or w is unspecified, the
|
||||
unspecified should be calculated from the specified to preserve
|
||||
aspect ratio. */
|
||||
value = image_spec_value (spec, QCwidth, NULL);
|
||||
if (FIXNATP (value))
|
||||
{
|
||||
desired_width = min (XFIXNAT (value) * scale, INT_MAX);
|
||||
/* :width overrides :max-width. */
|
||||
max_width = -1;
|
||||
}
|
||||
|
||||
value = image_spec_value (spec, QCheight, NULL);
|
||||
if (FIXNATP (value))
|
||||
{
|
||||
desired_height = min (XFIXNAT (value) * scale, INT_MAX);
|
||||
/* :height overrides :max-height. */
|
||||
max_height = -1;
|
||||
}
|
||||
|
||||
/* If we have both width/height set explicitly, we skip past all the
|
||||
aspect ratio-preserving computations below. */
|
||||
if (desired_width != -1 && desired_height != -1)
|
||||
goto out;
|
||||
|
||||
width = width * scale;
|
||||
height = height * scale;
|
||||
|
||||
if (desired_width != -1)
|
||||
/* Width known, calculate height. */
|
||||
desired_height = scale_image_size (desired_width, width, height);
|
||||
else if (desired_height != -1)
|
||||
/* Height known, calculate width. */
|
||||
desired_width = scale_image_size (desired_height, height, width);
|
||||
else
|
||||
{
|
||||
desired_width = width;
|
||||
desired_height = height;
|
||||
}
|
||||
|
||||
if (max_width != -1 && desired_width > max_width)
|
||||
{
|
||||
/* The image is wider than :max-width. */
|
||||
desired_width = max_width;
|
||||
desired_height = scale_image_size (desired_width, width, height);
|
||||
}
|
||||
|
||||
if (max_height != -1 && desired_height > max_height)
|
||||
{
|
||||
/* The image is higher than :max-height. */
|
||||
desired_height = max_height;
|
||||
desired_width = scale_image_size (desired_height, height, width);
|
||||
}
|
||||
|
||||
out:
|
||||
*d_width = desired_width;
|
||||
*d_height = desired_height;
|
||||
}
|
||||
|
||||
static bool imagemagick_image_p (Lisp_Object);
|
||||
static bool imagemagick_load (struct frame *, struct image *);
|
||||
static void imagemagick_clear_image (struct frame *, struct image *);
|
||||
|
@ -9816,6 +9899,25 @@ DEFUN ("lookup-image", Flookup_image, Slookup_image, 1, 1, 0,
|
|||
Initialization
|
||||
***********************************************************************/
|
||||
|
||||
DEFUN ("image-scaling-p", Fimage_scaling_p, Simage_scaling_p, 0, 1, 0,
|
||||
doc: /* Test whether FRAME supports resizing images.
|
||||
Return t if FRAME supports native scaling, nil otherwise. */)
|
||||
(Lisp_Object frame)
|
||||
{
|
||||
#ifdef HAVE_NS
|
||||
return Qt;
|
||||
#elif defined (HAVE_X_WINDOWS) && defined (HAVE_XRENDER)
|
||||
int event_basep, error_basep;
|
||||
|
||||
if (XRenderQueryExtension
|
||||
(FRAME_X_DISPLAY (decode_window_system_frame (frame)),
|
||||
&event_basep, &error_basep))
|
||||
return Qt;
|
||||
#endif
|
||||
|
||||
return Qnil;
|
||||
}
|
||||
|
||||
DEFUN ("init-image-library", Finit_image_library, Sinit_image_library, 1, 1, 0,
|
||||
doc: /* Initialize image library implementing image type TYPE.
|
||||
Return non-nil if TYPE is a supported image type.
|
||||
|
@ -10058,6 +10160,8 @@ non-numeric, there is no explicit limit on the size of images. */);
|
|||
defsubr (&Slookup_image);
|
||||
#endif
|
||||
|
||||
defsubr (&Simage_scaling_p);
|
||||
|
||||
DEFVAR_BOOL ("cross-disabled-images", cross_disabled_images,
|
||||
doc: /* Non-nil means always draw a cross over disabled images.
|
||||
Disabled images are those having a `:conversion disabled' property.
|
||||
|
|
|
@ -126,8 +126,6 @@ Updated by Christian Limpach (chris@nice.ch)
|
|||
eImg = temp;
|
||||
}
|
||||
|
||||
[eImg setSizeFromSpec:XCDR (img->spec)];
|
||||
|
||||
size = [eImg size];
|
||||
img->width = size.width;
|
||||
img->height = size.height;
|
||||
|
@ -151,6 +149,12 @@ Updated by Christian Limpach (chris@nice.ch)
|
|||
return [(id)img size].height;
|
||||
}
|
||||
|
||||
void
|
||||
ns_image_set_size (void *img, int width, int height)
|
||||
{
|
||||
[(EmacsImage *)img setSize:NSMakeSize (width, height)];
|
||||
}
|
||||
|
||||
unsigned long
|
||||
ns_get_pixel (void *img, int x, int y)
|
||||
{
|
||||
|
@ -524,66 +528,6 @@ - (BOOL)setFrame: (unsigned int) index
|
|||
return YES;
|
||||
}
|
||||
|
||||
- (void)setSizeFromSpec: (Lisp_Object) spec
|
||||
{
|
||||
NSSize size = [self size];
|
||||
Lisp_Object value;
|
||||
double scale = 1, aspect = size.width / size.height;
|
||||
double width = -1, height = -1, max_width = -1, max_height = -1;
|
||||
|
||||
value = Fplist_get (spec, QCscale);
|
||||
if (NUMBERP (value))
|
||||
scale = XFLOATINT (value) ;
|
||||
|
||||
value = Fplist_get (spec, QCmax_width);
|
||||
if (NUMBERP (value))
|
||||
max_width = XFLOATINT (value);
|
||||
|
||||
value = Fplist_get (spec, QCmax_height);
|
||||
if (NUMBERP (value))
|
||||
max_height = XFLOATINT (value);
|
||||
|
||||
value = Fplist_get (spec, QCwidth);
|
||||
if (NUMBERP (value))
|
||||
{
|
||||
width = XFLOATINT (value) * scale;
|
||||
/* :width overrides :max-width. */
|
||||
max_width = -1;
|
||||
}
|
||||
|
||||
value = Fplist_get (spec, QCheight);
|
||||
if (NUMBERP (value))
|
||||
{
|
||||
height = XFLOATINT (value) * scale;
|
||||
/* :height overrides :max-height. */
|
||||
max_height = -1;
|
||||
}
|
||||
|
||||
if (width <= 0 && height <= 0)
|
||||
{
|
||||
width = size.width * scale;
|
||||
height = size.height * scale;
|
||||
}
|
||||
else if (width > 0 && height <= 0)
|
||||
height = width / aspect;
|
||||
else if (height > 0 && width <= 0)
|
||||
width = height * aspect;
|
||||
|
||||
if (max_width > 0 && width > max_width)
|
||||
{
|
||||
width = max_width;
|
||||
height = max_width / aspect;
|
||||
}
|
||||
|
||||
if (max_height > 0 && height > max_height)
|
||||
{
|
||||
height = max_height;
|
||||
width = max_height * aspect;
|
||||
}
|
||||
|
||||
[self setSize:NSMakeSize(width, height)];
|
||||
}
|
||||
|
||||
- (instancetype)rotate: (double)rotation
|
||||
{
|
||||
EmacsImage *new_image;
|
||||
|
|
|
@ -648,7 +648,6 @@ typedef id instancetype;
|
|||
- (NSColor *)stippleMask;
|
||||
- (Lisp_Object)getMetadata;
|
||||
- (BOOL)setFrame: (unsigned int) index;
|
||||
- (void)setSizeFromSpec: (Lisp_Object) spec;
|
||||
- (instancetype)rotate: (double)rotation;
|
||||
@end
|
||||
|
||||
|
@ -1197,6 +1196,7 @@ extern bool ns_load_image (struct frame *f, struct image *img,
|
|||
Lisp_Object spec_file, Lisp_Object spec_data);
|
||||
extern int ns_image_width (void *img);
|
||||
extern int ns_image_height (void *img);
|
||||
extern void ns_image_set_size (void *img, int width, int height);
|
||||
extern unsigned long ns_get_pixel (void *img, int x, int y);
|
||||
extern void ns_put_pixel (void *img, int x, int y, unsigned long argb);
|
||||
extern void ns_set_alpha (void *img, int x, int y, unsigned char a);
|
||||
|
|
|
@ -3121,7 +3121,6 @@ so some key presses (TAB) are swallowed by the system. */
|
|||
[img setXBMColor: bm_color];
|
||||
}
|
||||
|
||||
#ifdef NS_IMPL_COCOA
|
||||
// Note: For periodic images, the full image height is "h + hd".
|
||||
// By using the height h, a suitable part of the image is used.
|
||||
NSRect fromRect = NSMakeRect(0, 0, p->wd, p->h);
|
||||
|
@ -3134,13 +3133,6 @@ so some key presses (TAB) are swallowed by the system. */
|
|||
fraction: 1.0
|
||||
respectFlipped: YES
|
||||
hints: nil];
|
||||
#else
|
||||
{
|
||||
NSPoint pt = imageRect.origin;
|
||||
pt.y += p->h;
|
||||
[img compositeToPoint: pt operation: NSCompositingOperationSourceOver];
|
||||
}
|
||||
#endif
|
||||
}
|
||||
ns_reset_clipping (f);
|
||||
}
|
||||
|
|
58
src/xterm.c
58
src/xterm.c
|
@ -38,11 +38,6 @@ along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */
|
|||
#include <X11/extensions/Xfixes.h>
|
||||
#endif
|
||||
|
||||
/* Using Xft implies that XRender is available. */
|
||||
#ifdef HAVE_XFT
|
||||
#include <X11/extensions/Xrender.h>
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_XDBE
|
||||
#include <X11/extensions/Xdbe.h>
|
||||
#endif
|
||||
|
@ -2976,6 +2971,46 @@ x_draw_glyph_string_box (struct glyph_string *s)
|
|||
}
|
||||
|
||||
|
||||
static void
|
||||
x_composite_image (struct glyph_string *s, Pixmap dest,
|
||||
int srcX, int srcY, int dstX, int dstY,
|
||||
int width, int height)
|
||||
{
|
||||
#ifdef HAVE_XRENDER
|
||||
if (s->img->picture)
|
||||
{
|
||||
Picture destination;
|
||||
XRenderPictFormat *default_format;
|
||||
XRenderPictureAttributes attr;
|
||||
|
||||
/* FIXME: Should we do this each time or would it make sense to
|
||||
store destination in the frame struct? */
|
||||
default_format = XRenderFindVisualFormat (s->display,
|
||||
DefaultVisual (s->display, 0));
|
||||
destination = XRenderCreatePicture (s->display, dest,
|
||||
default_format, 0, &attr);
|
||||
|
||||
/* FIXME: It may make sense to use PictOpSrc instead of
|
||||
PictOpOver, as I don't know if we care about alpha values too
|
||||
much here. */
|
||||
XRenderComposite (s->display, PictOpOver,
|
||||
s->img->picture, s->img->mask_picture, destination,
|
||||
srcX, srcY,
|
||||
srcX, srcY,
|
||||
dstX, dstY,
|
||||
width, height);
|
||||
|
||||
XRenderFreePicture (s->display, destination);
|
||||
}
|
||||
else
|
||||
#endif
|
||||
XCopyArea (s->display, s->img->pixmap,
|
||||
dest, s->gc,
|
||||
srcX, srcY,
|
||||
width, height, dstX, dstY);
|
||||
}
|
||||
|
||||
|
||||
/* Draw foreground of image glyph string S. */
|
||||
|
||||
static void
|
||||
|
@ -3007,6 +3042,7 @@ x_draw_image_foreground (struct glyph_string *s)
|
|||
trust on the shape extension to be available
|
||||
(XShapeCombineRegion). So, compute the rectangle to draw
|
||||
manually. */
|
||||
/* FIXME: Do we need to do this when using XRender compositing? */
|
||||
unsigned long mask = (GCClipMask | GCClipXOrigin | GCClipYOrigin
|
||||
| GCFunction);
|
||||
XGCValues xgcv;
|
||||
|
@ -3024,10 +3060,8 @@ x_draw_image_foreground (struct glyph_string *s)
|
|||
image_rect.width = s->slice.width;
|
||||
image_rect.height = s->slice.height;
|
||||
if (x_intersect_rectangles (&clip_rect, &image_rect, &r))
|
||||
XCopyArea (s->display, s->img->pixmap,
|
||||
FRAME_X_DRAWABLE (s->f), s->gc,
|
||||
s->slice.x + r.x - x, s->slice.y + r.y - y,
|
||||
r.width, r.height, r.x, r.y);
|
||||
x_composite_image (s, FRAME_X_DRAWABLE (s->f), s->slice.x + r.x - x, s->slice.y + r.y - y,
|
||||
r.x, r.y, r.width, r.height);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -3039,10 +3073,8 @@ x_draw_image_foreground (struct glyph_string *s)
|
|||
image_rect.width = s->slice.width;
|
||||
image_rect.height = s->slice.height;
|
||||
if (x_intersect_rectangles (&clip_rect, &image_rect, &r))
|
||||
XCopyArea (s->display, s->img->pixmap,
|
||||
FRAME_X_DRAWABLE (s->f), s->gc,
|
||||
s->slice.x + r.x - x, s->slice.y + r.y - y,
|
||||
r.width, r.height, r.x, r.y);
|
||||
x_composite_image (s, FRAME_X_DRAWABLE (s->f), s->slice.x + r.x - x, s->slice.y + r.y - y,
|
||||
r.x, r.y, r.width, r.height);
|
||||
|
||||
/* When the image has a mask, we can expect that at
|
||||
least part of a mouse highlight or a block cursor will
|
||||
|
|
Loading…
Add table
Reference in a new issue