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:
Alan Third 2019-01-02 21:00:09 +00:00
parent c342b26371
commit a1b7a3f2a3
11 changed files with 345 additions and 233 deletions

View file

@ -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) , ,

View file

@ -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

View file

@ -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

View file

@ -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)

View file

@ -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@

View file

@ -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. */

View file

@ -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.

View file

@ -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;

View file

@ -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);

View file

@ -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);
}

View file

@ -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