diff options
Diffstat (limited to 'src/image.c')
-rw-r--r-- | src/image.c | 967 |
1 files changed, 770 insertions, 197 deletions
diff --git a/src/image.c b/src/image.c index c2e76d5bfcd..439348759fd 100644 --- a/src/image.c +++ b/src/image.c @@ -20,6 +20,7 @@ along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */ #include <config.h> #include <fcntl.h> +#include <math.h> #include <unistd.h> /* Include this before including <setjmp.h> to work around bugs with @@ -30,6 +31,7 @@ along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */ #include <setjmp.h> +#include <math.h> #include <stdint.h> #include <c-ctype.h> #include <flexmember.h> @@ -78,14 +80,7 @@ typedef struct x_bitmap_record Bitmap_Record; #endif /* !USE_CAIRO */ #endif /* HAVE_X_WINDOWS */ -#ifdef USE_CAIRO -#define GET_PIXEL image_pix_context_get_pixel -#define PUT_PIXEL image_pix_container_put_pixel -#define NO_PIXMAP 0 - -#define PIX_MASK_RETAIN 0 -#define PIX_MASK_DRAW 255 - +#if defined(USE_CAIRO) || defined(HAVE_NS) #define RGB_TO_ULONG(r, g, b) (((r) << 16) | ((g) << 8) | (b)) #define ARGB_TO_ULONG(a, r, g, b) (((a) << 24) | ((r) << 16) | ((g) << 8) | (b)) #define RED_FROM_ULONG(color) (((color) >> 16) & 0xff) @@ -94,11 +89,29 @@ typedef struct x_bitmap_record Bitmap_Record; #define RED16_FROM_ULONG(color) (RED_FROM_ULONG (color) * 0x101) #define GREEN16_FROM_ULONG(color) (GREEN_FROM_ULONG (color) * 0x101) #define BLUE16_FROM_ULONG(color) (BLUE_FROM_ULONG (color) * 0x101) +#endif + +#ifdef USE_CAIRO +#define GET_PIXEL image_pix_context_get_pixel +#define PUT_PIXEL image_pix_container_put_pixel +#define NO_PIXMAP 0 + +#define PIX_MASK_RETAIN 0 +#define PIX_MASK_DRAW 255 static unsigned long image_alloc_image_color (struct frame *, struct image *, Lisp_Object, unsigned long); #endif /* USE_CAIRO */ +#if defined HAVE_PGTK && defined HAVE_IMAGEMAGICK +/* In pgtk, we don't want to create scaled image. If we create scaled + * image on scale=2.0 environment, the created image is half size and + * Gdk scales it back, and the result is blurry. To avoid this, we + * hold original size image as far as we can, and let Gdk to scale it + * when it is shown. */ +# define DONT_CREATE_TRANSFORMED_IMAGEMAGICK_IMAGE +#endif + #ifdef HAVE_NTGUI /* We need (or want) w32.h only when we're _not_ compiling for Cygwin. */ @@ -129,12 +142,37 @@ typedef struct ns_bitmap_record Bitmap_Record; #endif /* HAVE_NS */ +#ifdef HAVE_PGTK +typedef struct pgtk_bitmap_record Bitmap_Record; +#endif /* HAVE_PGTK */ + #if (defined HAVE_X_WINDOWS \ && ! (defined HAVE_NTGUI || defined USE_CAIRO || defined HAVE_NS)) /* W32_TODO : Color tables on W32. */ # define COLOR_TABLE_SUPPORT 1 #endif +#ifdef HAVE_HAIKU +#include "haiku_support.h" +typedef struct haiku_bitmap_record Bitmap_Record; + +#define GET_PIXEL(ximg, x, y) haiku_get_pixel (ximg, x, y) +#define PUT_PIXEL haiku_put_pixel +#define NO_PIXMAP 0 + +#define PIX_MASK_RETAIN 0 +#define PIX_MASK_DRAW 1 + +#define RGB_TO_ULONG(r, g, b) (((r) << 16) | ((g) << 8) | (b)) +#define RED_FROM_ULONG(color) (((color) >> 16) & 0xff) +#define GREEN_FROM_ULONG(color) (((color) >> 8) & 0xff) +#define BLUE_FROM_ULONG(color) ((color) & 0xff) +#define RED16_FROM_ULONG(color) (RED_FROM_ULONG (color) * 0x101) +#define GREEN16_FROM_ULONG(color) (GREEN_FROM_ULONG (color) * 0x101) +#define BLUE16_FROM_ULONG(color) (BLUE_FROM_ULONG (color) * 0x101) + +#endif + static void image_disable_image (struct frame *, struct image *); static void image_edge_detection (struct frame *, struct image *, Lisp_Object, Lisp_Object); @@ -396,6 +434,34 @@ image_reference_bitmap (struct frame *f, ptrdiff_t id) ++FRAME_DISPLAY_INFO (f)->bitmaps[id - 1].refcount; } +#ifdef HAVE_PGTK +static cairo_pattern_t * +image_create_pattern_from_pixbuf (struct frame *f, GdkPixbuf * pixbuf) +{ + GdkPixbuf *pb = gdk_pixbuf_add_alpha (pixbuf, TRUE, 255, 255, 255); + cairo_surface_t *surface = + cairo_surface_create_similar_image (cairo_get_target + (f->output_data.pgtk->cr_context), + CAIRO_FORMAT_A1, + gdk_pixbuf_get_width (pb), + gdk_pixbuf_get_height (pb)); + + cairo_t *cr = cairo_create (surface); + gdk_cairo_set_source_pixbuf (cr, pb, 0, 0); + cairo_set_operator (cr, CAIRO_OPERATOR_SOURCE); + cairo_paint (cr); + cairo_destroy (cr); + + cairo_pattern_t *pat = cairo_pattern_create_for_surface (surface); + cairo_pattern_set_extend (pat, CAIRO_EXTEND_REPEAT); + + cairo_surface_destroy (surface); + g_object_unref (pb); + + return pat; +} +#endif + /* Create a bitmap for frame F from a HEIGHT x WIDTH array of bits at BITS. */ ptrdiff_t @@ -430,6 +496,54 @@ image_create_bitmap_from_data (struct frame *f, char *bits, return -1; #endif +#ifdef HAVE_PGTK + GdkPixbuf *pixbuf = gdk_pixbuf_new (GDK_COLORSPACE_RGB, + FALSE, + 8, + width, + height); + { + char *sp = bits; + int mask = 0x01; + unsigned char *buf = gdk_pixbuf_get_pixels (pixbuf); + int rowstride = gdk_pixbuf_get_rowstride (pixbuf); + for (int y = 0; y < height; y++) + { + unsigned char *dp = buf + rowstride * y; + for (int x = 0; x < width; x++) + { + if (*sp & mask) + { + *dp++ = 0xff; + *dp++ = 0xff; + *dp++ = 0xff; + } + else + { + *dp++ = 0x00; + *dp++ = 0x00; + *dp++ = 0x00; + } + if ((mask <<= 1) >= 0x100) + { + mask = 0x01; + sp++; + } + } + if (mask != 0x01) + { + mask = 0x01; + sp++; + } + } + } +#endif /* HAVE_PGTK */ + +#ifdef HAVE_HAIKU + void *bitmap = BBitmap_new (width, height, 1); + BBitmap_import_mono_bits (bitmap, bits, width, height); +#endif + id = image_allocate_bitmap_record (f); #ifdef HAVE_NS @@ -437,6 +551,18 @@ image_create_bitmap_from_data (struct frame *f, char *bits, dpyinfo->bitmaps[id - 1].depth = 1; #endif +#ifdef HAVE_PGTK + dpyinfo->bitmaps[id - 1].img = pixbuf; + dpyinfo->bitmaps[id - 1].depth = 1; + dpyinfo->bitmaps[id - 1].pattern = + image_create_pattern_from_pixbuf (f, pixbuf); +#endif + +#ifdef HAVE_HAIKU + dpyinfo->bitmaps[id - 1].img = bitmap; + dpyinfo->bitmaps[id - 1].depth = 1; +#endif + dpyinfo->bitmaps[id - 1].file = NULL; dpyinfo->bitmaps[id - 1].height = height; dpyinfo->bitmaps[id - 1].width = width; @@ -465,7 +591,7 @@ image_create_bitmap_from_data (struct frame *f, char *bits, ptrdiff_t image_create_bitmap_from_file (struct frame *f, Lisp_Object file) { -#ifdef HAVE_NTGUI +#if defined (HAVE_NTGUI) || defined (HAVE_HAIKU) return -1; /* W32_TODO : bitmap support */ #else Display_Info *dpyinfo = FRAME_DISPLAY_INFO (f); @@ -489,6 +615,30 @@ image_create_bitmap_from_file (struct frame *f, Lisp_Object file) return id; #endif +#ifdef HAVE_PGTK + GError *err = NULL; + ptrdiff_t id; + void * bitmap = gdk_pixbuf_new_from_file (SSDATA (file), &err); + + if (!bitmap) + { + g_error_free (err); + return -1; + } + + id = image_allocate_bitmap_record (f); + + dpyinfo->bitmaps[id - 1].img = bitmap; + dpyinfo->bitmaps[id - 1].refcount = 1; + dpyinfo->bitmaps[id - 1].file = xlispstrdup (file); + //dpyinfo->bitmaps[id - 1].depth = 1; + dpyinfo->bitmaps[id - 1].height = gdk_pixbuf_get_width (bitmap); + dpyinfo->bitmaps[id - 1].width = gdk_pixbuf_get_height (bitmap); + dpyinfo->bitmaps[id - 1].pattern + = image_create_pattern_from_pixbuf (f, bitmap); + return id; +#endif + #ifdef HAVE_X_WINDOWS unsigned int width, height; Pixmap bitmap; @@ -561,6 +711,15 @@ free_bitmap_record (Display_Info *dpyinfo, Bitmap_Record *bm) ns_release_object (bm->img); #endif +#ifdef HAVE_PGTK + if (bm->pattern != NULL) + cairo_pattern_destroy (bm->pattern); +#endif + +#ifdef HAVE_HAIKU + BBitmap_free (bm->img); +#endif + if (bm->file) { xfree (bm->file); @@ -1321,7 +1480,6 @@ image_ascent (struct image *img, struct face *face, struct glyph_slice *slice) return ascent; } - /* Image background colors. */ @@ -1345,6 +1503,7 @@ four_corners_best (Emacs_Pix_Context pimg, int *corners, corner_pixels[3] = GET_PIXEL (pimg, corners[LEFT_CORNER], corners[BOT_CORNER] - 1); } else + { /* Get the colors at the corner_pixels of pimg. */ corner_pixels[0] = GET_PIXEL (pimg, 0, 0); @@ -1834,6 +1993,11 @@ image_size_in_bytes (struct image *img) if (img->mask) size += w32_image_size (img->mask); +#elif defined HAVE_HAIKU + if (img->pixmap) + size += BBitmap_bytes_length (img->pixmap); + if (img->mask) + size += BBitmap_bytes_length (img->mask); #endif return size; @@ -1975,14 +2139,16 @@ postprocess_image (struct frame *f, struct image *img) safely rounded and clipped to int range. */ static int -scale_image_size (int size, size_t divisor, size_t multiplier) +scale_image_size (int size, double divisor, double multiplier) { if (divisor != 0) { - double s = size; - double scaled = s * multiplier / divisor + 0.5; + double scaled = size * multiplier / divisor; if (scaled < INT_MAX) - return scaled; + { + /* Use ceil, as rounding can discard fractional SVG pixels. */ + return ceil (scaled); + } } return INT_MAX; } @@ -2003,84 +2169,77 @@ image_get_dimension (struct image *img, Lisp_Object symbol) if (FIXNATP (value)) return min (XFIXNAT (value), INT_MAX); if (CONSP (value) && NUMBERP (CAR (value)) && EQ (Qem, CDR (value))) - return min (img->face_font_size * XFLOATINT (CAR (value)), INT_MAX); + return scale_image_size (img->face_font_size, 1, XFLOATINT (CAR (value))); return -1; } /* Compute the desired size of an image with native size WIDTH x HEIGHT. - Use SPEC to deduce the size. Store the desired size into + Use IMG 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, +compute_image_size (double width, double height, struct image *img, int *d_width, int *d_height) { - Lisp_Object value; - int int_value; - int desired_width = -1, desired_height = -1, max_width = -1, max_height = -1; double scale = 1; - - value = image_spec_value (img->spec, QCscale, NULL); + Lisp_Object value = image_spec_value (img->spec, QCscale, NULL); if (NUMBERP (value)) - scale = XFLOATINT (value); - - int_value = image_get_dimension (img, QCmax_width); - if (int_value >= 0) - max_width = int_value; - - int_value = image_get_dimension (img, QCmax_height); - if (int_value >= 0) - max_height = int_value; + { + double dval = XFLOATINT (value); + if (0 <= dval) + scale = dval; + } /* 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. */ - int_value = image_get_dimension (img, QCwidth); - if (int_value >= 0) + int desired_width = image_get_dimension (img, QCwidth), max_width; + if (desired_width < 0) + max_width = image_get_dimension (img, QCmax_width); + else { - desired_width = int_value * scale; + desired_width = scale_image_size (desired_width, 1, scale); /* :width overrides :max-width. */ max_width = -1; } - int_value = image_get_dimension (img, QCheight); - if (int_value >= 0) + int desired_height = image_get_dimension (img, QCheight), max_height; + if (desired_height < 0) + max_height = image_get_dimension (img, QCmax_height); + else { - desired_height = int_value * scale; + desired_height = scale_image_size (desired_height, 1, scale); /* :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) + if (0 <= desired_width && 0 <= desired_height) goto out; - width = width * scale; - height = height * scale; - - if (desired_width != -1) + if (0 <= desired_width) /* Width known, calculate height. */ desired_height = scale_image_size (desired_width, width, height); - else if (desired_height != -1) + else if (0 <= desired_height) /* Height known, calculate width. */ desired_width = scale_image_size (desired_height, height, width); else { - desired_width = width; - desired_height = height; + desired_width = scale_image_size (width, 1, scale); + desired_height = scale_image_size (height, 1, scale); } - if (max_width != -1 && desired_width > max_width) + if (0 <= max_width && max_width < desired_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) + if (0 <= max_height && max_height < desired_height) { /* The image is higher than :max-height. */ desired_height = max_height; @@ -2173,6 +2332,7 @@ compute_image_size (size_t width, size_t height, single step, but the maths for each element is much more complex and performing the steps separately makes for more readable code. */ +#ifndef HAVE_HAIKU typedef double matrix3x3[3][3]; static void @@ -2187,6 +2347,7 @@ matrix3x3_mult (matrix3x3 a, matrix3x3 b, matrix3x3 result) result[i][j] = sum; } } +#endif /* not HAVE_HAIKU */ static void compute_image_rotation (struct image *img, double *rotation) @@ -2211,7 +2372,8 @@ compute_image_rotation (struct image *img, double *rotation) static void image_set_transform (struct frame *f, struct image *img) { -# ifdef HAVE_IMAGEMAGICK +# if (defined HAVE_IMAGEMAGICK \ + && !defined DONT_CREATE_TRANSFORMED_IMAGEMAGICK_IMAGE) /* ImageMagick images already have the correct transform. */ if (EQ (image_spec_value (img->spec, QCtype, NULL), Qimagemagick)) return; @@ -2244,6 +2406,7 @@ image_set_transform (struct frame *f, struct image *img) double rotation = 0.0; compute_image_rotation (img, &rotation); +#ifndef HAVE_HAIKU # if defined USE_CAIRO || defined HAVE_XRENDER || defined HAVE_NS /* We want scale up operations to use a nearest neighbor filter to show real pixels instead of munging them, but scale down @@ -2414,6 +2577,34 @@ image_set_transform (struct frame *f, struct image *img) img->xform.eDx = matrix[2][0]; img->xform.eDy = matrix[2][1]; # endif +#else + if (rotation != 0 && + rotation != 90 && + rotation != 180 && + rotation != 270 && + rotation != 360) + { + image_error ("No native support for rotation by %g degrees", + make_float (rotation)); + return; + } + + rotation = fmod (rotation, 360.0); + + if (rotation == 90 || rotation == 270) + { + int w = width; + width = height; + height = w; + } + + img->have_be_transforms_p = rotation != 0 || (img->width != width) || (img->height != height); + img->be_rotate = rotation; + img->be_scale_x = 1.0 / (img->width / (double) width); + img->be_scale_y = 1.0 / (img->height / (double) height); + img->width = width; + img->height = height; +#endif /* not HAVE_HAIKU */ } #endif /* HAVE_IMAGEMAGICK || HAVE_NATIVE_TRANSFORMS */ @@ -2435,8 +2626,8 @@ lookup_image (struct frame *f, Lisp_Object spec, int face_id) face_id = DEFAULT_FACE_ID; struct face *face = FACE_FROM_ID (f, face_id); - unsigned long foreground = FACE_COLOR_TO_PIXEL (face->foreground, f); - unsigned long background = FACE_COLOR_TO_PIXEL (face->background, f); + unsigned long foreground = face->foreground; + unsigned long background = face->background; int font_size = face->font->pixel_size; char *font_family = SSDATA (face->lface[LFACE_FAMILY_INDEX]); @@ -2820,6 +3011,30 @@ image_create_x_image_and_pixmap_1 (struct frame *f, int width, int height, int d return 1; #endif /* HAVE_X_WINDOWS */ +#ifdef HAVE_HAIKU + if (depth == 0) + depth = 24; + + if (depth != 24 && depth != 1) + { + *pimg = NULL; + image_error ("Invalid image bit depth specified"); + return 0; + } + + *pixmap = BBitmap_new (width, height, depth == 1); + + if (*pixmap == NO_PIXMAP) + { + *pimg = NULL; + image_error ("Unable to create pixmap", Qnil, Qnil); + return 0; + } + + *pimg = *pixmap; + return 1; +#endif + #ifdef HAVE_NTGUI BITMAPINFOHEADER *header; @@ -2960,7 +3175,7 @@ static void gui_put_x_image (struct frame *f, Emacs_Pix_Container pimg, Emacs_Pixmap pixmap, int width, int height) { -#ifdef USE_CAIRO +#if defined USE_CAIRO || defined HAVE_HAIKU eassert (pimg == pixmap); #elif defined HAVE_X_WINDOWS GC gc; @@ -2972,14 +3187,6 @@ gui_put_x_image (struct frame *f, Emacs_Pix_Container pimg, XFreeGC (FRAME_X_DISPLAY (f), gc); #endif /* HAVE_X_WINDOWS */ -#ifdef HAVE_NTGUI -#if 0 /* I don't think this is necessary looking at where it is used. */ - HDC hdc = get_frame_dc (f); - SetDIBits (hdc, pixmap, 0, height, pimg->data, &(pimg->info), DIB_RGB_COLORS); - release_frame_dc (f, hdc); -#endif -#endif /* HAVE_NTGUI */ - #ifdef HAVE_NS eassert (pimg == pixmap); ns_retain_object (pimg); @@ -3087,7 +3294,7 @@ image_unget_x_image_or_dc (struct image *img, bool mask_p, static Emacs_Pix_Container image_get_x_image (struct frame *f, struct image *img, bool mask_p) { -#ifdef USE_CAIRO +#if defined USE_CAIRO || defined (HAVE_HAIKU) return !mask_p ? img->pixmap : img->mask; #elif defined HAVE_X_WINDOWS XImage *ximg_in_img = !mask_p ? img->ximg : img->mask_img; @@ -3547,10 +3754,8 @@ convert_mono_to_color_image (struct frame *f, struct image *img, release_frame_dc (f, hdc); old_prev = SelectObject (old_img_dc, img->pixmap); new_prev = SelectObject (new_img_dc, new_pixmap); - /* Windows convention for mono bitmaps is black = background, - white = foreground. */ - SetTextColor (new_img_dc, background); - SetBkColor (new_img_dc, foreground); + SetTextColor (new_img_dc, foreground); + SetBkColor (new_img_dc, background); BitBlt (new_img_dc, 0, 0, img->width, img->height, old_img_dc, 0, 0, SRCCOPY); @@ -4015,6 +4220,13 @@ xbm_load (struct frame *f, struct image *img) XPM images ***********************************************************************/ +#if defined (HAVE_XPM) || defined (HAVE_NS) || defined (HAVE_PGTK) + +static bool xpm_image_p (Lisp_Object object); +static bool xpm_load (struct frame *f, struct image *img); + +#endif /* HAVE_XPM || HAVE_NS */ + #ifdef HAVE_XPM #ifdef HAVE_NTGUI /* Indicate to xpm.h that we don't have Xlib. */ @@ -4038,7 +4250,7 @@ xbm_load (struct frame *f, struct image *img) #endif /* not HAVE_NTGUI */ #endif /* HAVE_XPM */ -#if defined HAVE_XPM || defined USE_CAIRO || defined HAVE_NS +#if defined HAVE_XPM || defined USE_CAIRO || defined HAVE_NS || defined HAVE_HAIKU /* Indices of image specification fields in xpm_format, below. */ @@ -4058,7 +4270,7 @@ enum xpm_keyword_index XPM_LAST }; -#if defined HAVE_XPM || defined HAVE_NS +#if defined HAVE_XPM || defined HAVE_NS || defined HAVE_HAIKU || defined HAVE_PGTK /* Vector of image_keyword structures describing the format of valid XPM image specifications. */ @@ -4076,7 +4288,7 @@ static const struct image_keyword xpm_format[XPM_LAST] = {":color-symbols", IMAGE_DONT_CHECK_VALUE_TYPE, 0}, {":background", IMAGE_STRING_OR_NIL_VALUE, 0} }; -#endif /* HAVE_XPM || HAVE_NS */ +#endif /* HAVE_XPM || HAVE_NS || HAVE_HAIKU || HAVE_PGTK */ #if defined HAVE_X_WINDOWS && !defined USE_CAIRO @@ -4116,9 +4328,9 @@ struct xpm_cached_color }; /* The hash table used for the color cache, and its bucket vector - size. */ + size (which should be prime). */ -#define XPM_COLOR_CACHE_BUCKETS 1001 +#define XPM_COLOR_CACHE_BUCKETS 1009 static struct xpm_cached_color **xpm_color_cache; /* Initialize the color cache. */ @@ -4300,7 +4512,7 @@ init_xpm_functions (void) #endif /* WINDOWSNT */ -#if defined HAVE_XPM || defined HAVE_NS +#if defined HAVE_XPM || defined HAVE_NS || defined HAVE_HAIKU || defined HAVE_PGTK /* Value is true if COLOR_SYMBOLS is a valid color symbols list for XPM images. Such a list must consist of conses whose car and cdr are strings. */ @@ -4336,9 +4548,9 @@ xpm_image_p (Lisp_Object object) && (! fmt[XPM_COLOR_SYMBOLS].count || xpm_valid_color_symbols_p (fmt[XPM_COLOR_SYMBOLS].value))); } -#endif /* HAVE_XPM || HAVE_NS */ +#endif /* HAVE_XPM || HAVE_NS || HAVE_HAIKU || HAVE_PGTK */ -#endif /* HAVE_XPM || USE_CAIRO || HAVE_NS */ +#endif /* HAVE_XPM || USE_CAIRO || HAVE_NS || HAVE_HAIKU */ #if defined HAVE_XPM && defined HAVE_X_WINDOWS && !defined USE_GTK ptrdiff_t @@ -4707,9 +4919,11 @@ xpm_load (struct frame *f, struct image *img) #endif /* HAVE_XPM && !USE_CAIRO */ #if (defined USE_CAIRO && defined HAVE_XPM) \ - || (defined HAVE_NS && !defined HAVE_XPM) + || (defined HAVE_NS && !defined HAVE_XPM) \ + || (defined HAVE_HAIKU && !defined HAVE_XPM) \ + || (defined HAVE_PGTK && !defined HAVE_XPM) -/* XPM support functions for NS where libxpm is not available, and for +/* XPM support functions for NS and Haiku where libxpm is not available, and for Cairo. Only XPM version 3 (without any extensions) is supported. */ static void xpm_put_color_table_v (Lisp_Object, const char *, @@ -4906,7 +5120,7 @@ xpm_load_image (struct frame *f, Lisp_Object (*get_color_table) (Lisp_Object, const char *, int); Lisp_Object frame, color_symbols, color_table; int best_key; -#ifndef HAVE_NS +#if !defined (HAVE_NS) bool have_mask = false; #endif Emacs_Pix_Container ximg = NULL, mask_img = NULL; @@ -5446,7 +5660,7 @@ lookup_rgb_color (struct frame *f, int r, int g, int b) { #ifdef HAVE_NTGUI return PALETTERGB (r >> 8, g >> 8, b >> 8); -#elif defined USE_CAIRO || defined HAVE_NS +#elif defined USE_CAIRO || defined HAVE_NS || defined HAVE_HAIKU return RGB_TO_ULONG (r >> 8, g >> 8, b >> 8); #else xsignal1 (Qfile_error, @@ -5519,7 +5733,7 @@ image_to_emacs_colors (struct frame *f, struct image *img, bool rgb_p) p = colors; for (y = 0; y < img->height; ++y) { -#if !defined USE_CAIRO && !defined HAVE_NS +#if !defined USE_CAIRO && !defined HAVE_NS && !defined HAVE_HAIKU Emacs_Color *row = p; for (x = 0; x < img->width; ++x, ++p) p->pixel = GET_PIXEL (ximg, x, y); @@ -5527,7 +5741,7 @@ image_to_emacs_colors (struct frame *f, struct image *img, bool rgb_p) { FRAME_TERMINAL (f)->query_colors (f, row, img->width); } -#else /* USE_CAIRO || HAVE_NS */ +#else /* USE_CAIRO || HAVE_NS || HAVE_HAIKU */ for (x = 0; x < img->width; ++x, ++p) { p->pixel = GET_PIXEL (ximg, x, y); @@ -5841,6 +6055,7 @@ image_disable_image (struct frame *f, struct image *img) { #ifndef HAVE_NTGUI #ifndef HAVE_NS /* TODO: NS support, however this not needed for toolbars */ +#ifndef HAVE_HAIKU #ifndef USE_CAIRO #define CrossForeground(f) BLACK_PIX_DEFAULT (f) @@ -5858,6 +6073,7 @@ image_disable_image (struct frame *f, struct image *img) if (img->mask) image_pixmap_draw_cross (f, img->mask, 0, 0, img->width, img->height, MaskForeground (f)); +#endif /* !HAVE_HAIKU */ #endif /* !HAVE_NS */ #else HDC hdc, bmpdc; @@ -6415,15 +6631,16 @@ image_can_use_native_api (Lisp_Object type) return w32_can_use_native_image_api (type); # elif defined HAVE_NS return ns_can_use_native_image_api (type); +# elif defined HAVE_HAIKU + return haiku_can_use_native_image_api (type); # else return false; # endif } /* - * These functions are actually defined in the OS-native implementation - * file. Currently, for Windows GDI+ interface, w32image.c, but other - * operating systems can follow suit. + * These functions are actually defined in the OS-native implementation file. + * Currently, for Windows GDI+ interface, w32image.c, and nsimage.m for macOS. */ /* Indices of image specification fields in native format, below. */ @@ -6489,6 +6706,9 @@ native_image_load (struct frame *f, struct image *img) # elif defined HAVE_NS return ns_load_image (f, img, image_file, image_spec_value (img->spec, QCdata, NULL)); +# elif defined HAVE_HAIKU + return haiku_load_image (f, img, image_file, + image_spec_value (img->spec, QCdata, NULL)); # else return 0; # endif @@ -8233,24 +8453,30 @@ gif_image_p (Lisp_Object object) # undef DrawText # endif -/* Giflib before 5.0 didn't define these macros (used only if HAVE_NTGUI). */ -# ifndef GIFLIB_MINOR -# define GIFLIB_MINOR 0 -# endif -# ifndef GIFLIB_RELEASE -# define GIFLIB_RELEASE 0 -# endif - # else /* HAVE_NTGUI */ # include <gif_lib.h> # endif /* HAVE_NTGUI */ -/* Giflib before 5.0 didn't define these macros. */ +/* Giflib before 4.1.6 didn't define these macros. */ # ifndef GIFLIB_MAJOR # define GIFLIB_MAJOR 4 # endif +# ifndef GIFLIB_MINOR +# define GIFLIB_MINOR 0 +# endif +# ifndef GIFLIB_RELEASE +# define GIFLIB_RELEASE 0 +# endif +/* Giflib before 5.0 didn't define these macros. */ +# if GIFLIB_MAJOR < 5 +# define DISPOSAL_UNSPECIFIED 0 /* No disposal specified. */ +# define DISPOSE_DO_NOT 1 /* Leave image in place. */ +# define DISPOSE_BACKGROUND 2 /* Set area too background color. */ +# define DISPOSE_PREVIOUS 3 /* Restore to previous content. */ +# define NO_TRANSPARENT_COLOR -1 +# endif /* GifErrorString is declared to return char const * when GIFLIB_MAJOR and GIFLIB_MINOR indicate 5.1 or later. Do not bother using it in @@ -8273,6 +8499,8 @@ DEF_DLL_FN (GifFileType *, DGifOpenFileName, (const char *)); # else DEF_DLL_FN (GifFileType *, DGifOpen, (void *, InputFunc, int *)); DEF_DLL_FN (GifFileType *, DGifOpenFileName, (const char *, int *)); +DEF_DLL_FN (int, DGifSavedExtensionToGCB, + (GifFileType *, int, GraphicsControlBlock *)); # endif # if HAVE_GIFERRORSTRING DEF_DLL_FN (char const *, GifErrorString, (int)); @@ -8290,6 +8518,9 @@ init_gif_functions (void) LOAD_DLL_FN (library, DGifSlurp); LOAD_DLL_FN (library, DGifOpen); LOAD_DLL_FN (library, DGifOpenFileName); +# if GIFLIB_MAJOR >= 5 + LOAD_DLL_FN (library, DGifSavedExtensionToGCB); +# endif # if HAVE_GIFERRORSTRING LOAD_DLL_FN (library, GifErrorString); # endif @@ -8300,12 +8531,18 @@ init_gif_functions (void) # undef DGifOpen # undef DGifOpenFileName # undef DGifSlurp +# if GIFLIB_MAJOR >= 5 +# undef DGifSavedExtensionToGCB +# endif # undef GifErrorString # define DGifCloseFile fn_DGifCloseFile # define DGifOpen fn_DGifOpen # define DGifOpenFileName fn_DGifOpenFileName # define DGifSlurp fn_DGifSlurp +# if GIFLIB_MAJOR >= 5 +# define DGifSavedExtensionToGCB fn_DGifSavedExtensionToGCB +# endif # define GifErrorString fn_GifErrorString # endif /* WINDOWSNT */ @@ -8383,7 +8620,7 @@ gif_load (struct frame *f, struct image *img) if (!STRINGP (file)) { image_error ("Cannot find image file `%s'", specified_file); - return 0; + return false; } Lisp_Object encoded_file = ENCODE_FILE (file); @@ -8406,8 +8643,7 @@ gif_load (struct frame *f, struct image *img) else #endif image_error ("Cannot open `%s'", file); - - return 0; + return false; } } else @@ -8415,7 +8651,7 @@ gif_load (struct frame *f, struct image *img) if (!STRINGP (specified_data)) { image_error ("Invalid image data `%s'", specified_data); - return 0; + return false; } /* Read from memory! */ @@ -8439,7 +8675,7 @@ gif_load (struct frame *f, struct image *img) else #endif image_error ("Cannot open memory source `%s'", img->spec); - return 0; + return false; } } @@ -8447,8 +8683,7 @@ gif_load (struct frame *f, struct image *img) if (!check_image_size (f, gif->SWidth, gif->SHeight)) { image_size_error (); - gif_close (gif, NULL); - return 0; + goto gif_error; } /* Read entire contents. */ @@ -8459,8 +8694,7 @@ gif_load (struct frame *f, struct image *img) image_error ("Error reading `%s'", img->spec); else image_error ("Error reading GIF data"); - gif_close (gif, NULL); - return 0; + goto gif_error; } /* Which sub-image are we to display? */ @@ -8471,8 +8705,7 @@ gif_load (struct frame *f, struct image *img) { image_error ("Invalid image number `%s' in image `%s'", image_number, img->spec); - gif_close (gif, NULL); - return 0; + goto gif_error; } } @@ -8489,8 +8722,7 @@ gif_load (struct frame *f, struct image *img) if (!check_image_size (f, width, height)) { image_size_error (); - gif_close (gif, NULL); - return 0; + goto gif_error; } /* Check that the selected subimages fit. It's not clear whether @@ -8507,18 +8739,14 @@ gif_load (struct frame *f, struct image *img) && 0 <= subimg_left && subimg_left <= width - subimg_width)) { image_error ("Subimage does not fit in image"); - gif_close (gif, NULL); - return 0; + goto gif_error; } } /* Create the X image and pixmap. */ Emacs_Pix_Container ximg; if (!image_create_x_image_and_pixmap (f, img, width, height, 0, &ximg, 0)) - { - gif_close (gif, NULL); - return 0; - } + goto gif_error; /* Clear the part of the screen image not covered by the image. Full animated GIF support requires more here (see the gif89 spec, @@ -8577,13 +8805,17 @@ gif_load (struct frame *f, struct image *img) char *, which invites problems with bytes >= 0x80. */ struct SavedImage *subimage = gif->SavedImages + j; unsigned char *raster = (unsigned char *) subimage->RasterBits; - int transparency_color_index = -1; - int disposal = 0; int subimg_width = subimage->ImageDesc.Width; int subimg_height = subimage->ImageDesc.Height; int subimg_top = subimage->ImageDesc.Top; int subimg_left = subimage->ImageDesc.Left; + /* From gif89a spec: 1 = "keep in place", 2 = "restore + to background". Treat any other value like 2. */ + int disposal = DISPOSAL_UNSPECIFIED; + int transparency_color_index = NO_TRANSPARENT_COLOR; + +#if GIFLIB_MAJOR < 5 /* Find the Graphic Control Extension block for this sub-image. Extract the disposal method and transparency color. */ for (i = 0; i < subimage->ExtensionBlockCount; i++) @@ -8594,24 +8826,29 @@ gif_load (struct frame *f, struct image *img) && extblock->ByteCount == 4 && extblock->Bytes[0] & 1) { - /* From gif89a spec: 1 = "keep in place", 2 = "restore - to background". Treat any other value like 2. */ disposal = (extblock->Bytes[0] >> 2) & 7; transparency_color_index = (unsigned char) extblock->Bytes[3]; break; } } +#else + GraphicsControlBlock gcb; + DGifSavedExtensionToGCB (gif, j, &gcb); + disposal = gcb.DisposalMode; + transparency_color_index = gcb.TransparentColor; +#endif /* We can't "keep in place" the first subimage. */ if (j == 0) - disposal = 2; + disposal = DISPOSE_BACKGROUND; - /* For disposal == 0, the spec says "No disposal specified. The - decoder is not required to take any action." In practice, it - seems we need to treat this like "keep in place", see e.g. + /* For disposal == 0 (DISPOSAL_UNSPECIFIED), the spec says + "No disposal specified. The decoder is not required to take + any action." In practice, it seems we need to treat this + like "keep in place" (DISPOSE_DO_NOT), see e.g. https://upload.wikimedia.org/wikipedia/commons/3/37/Clock.gif */ - if (disposal == 0) - disposal = 1; + if (disposal == DISPOSAL_UNSPECIFIED) + disposal = DISPOSE_DO_NOT; gif_color_map = subimage->ImageDesc.ColorMap; if (!gif_color_map) @@ -8650,7 +8887,7 @@ gif_load (struct frame *f, struct image *img) for (x = 0; x < subimg_width; x++) { int c = raster[y * subimg_width + x]; - if (transparency_color_index != c || disposal != 1) + if (transparency_color_index != c || disposal != DISPOSE_DO_NOT) { PUT_PIXEL (ximg, x + subimg_left, row + subimg_top, pixel_colors[c]); @@ -8664,7 +8901,7 @@ gif_load (struct frame *f, struct image *img) for (x = 0; x < subimg_width; ++x) { int c = raster[y * subimg_width + x]; - if (transparency_color_index != c || disposal != 1) + if (transparency_color_index != c || disposal != DISPOSE_DO_NOT) { PUT_PIXEL (ximg, x + subimg_left, y + subimg_top, pixel_colors[c]); @@ -8734,14 +8971,302 @@ gif_load (struct frame *f, struct image *img) /* Put ximg into the image. */ image_put_x_image (f, img, ximg, 0); - return 1; + return true; + + gif_error: + gif_close (gif, NULL); + return false; } #endif /* HAVE_GIF */ +#ifdef HAVE_WEBP + + +/*********************************************************************** + WebP + ***********************************************************************/ + +#include "webp/decode.h" + +/* Indices of image specification fields in webp_format, below. */ + +enum webp_keyword_index +{ + WEBP_TYPE, + WEBP_DATA, + WEBP_FILE, + WEBP_ASCENT, + WEBP_MARGIN, + WEBP_RELIEF, + WEBP_ALGORITHM, + WEBP_HEURISTIC_MASK, + WEBP_MASK, + WEBP_BACKGROUND, + WEBP_LAST +}; + +/* Vector of image_keyword structures describing the format + of valid user-defined image specifications. */ + +static const struct image_keyword webp_format[WEBP_LAST] = +{ + {":type", IMAGE_SYMBOL_VALUE, 1}, + {":data", IMAGE_STRING_VALUE, 0}, + {":file", IMAGE_STRING_VALUE, 0}, + {":ascent", IMAGE_ASCENT_VALUE, 0}, + {":margin", IMAGE_NON_NEGATIVE_INTEGER_VALUE_OR_PAIR, 0}, + {":relief", IMAGE_INTEGER_VALUE, 0}, + {":conversion", IMAGE_DONT_CHECK_VALUE_TYPE, 0}, + {":heuristic-mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0}, + {":mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0}, + {":background", IMAGE_STRING_OR_NIL_VALUE, 0} +}; + +/* Return true if OBJECT is a valid WebP image specification. */ + +static bool +webp_image_p (Lisp_Object object) +{ + struct image_keyword fmt[WEBP_LAST]; + memcpy (fmt, webp_format, sizeof fmt); + + if (!parse_image_spec (object, fmt, WEBP_LAST, Qwebp)) + return false; + + /* Must specify either the :data or :file keyword. */ + return fmt[WEBP_FILE].count + fmt[WEBP_DATA].count == 1; +} + +#ifdef WINDOWSNT + +/* WebP library details. */ + +DEF_DLL_FN (int, WebPGetInfo, (const uint8_t *, size_t, int *, int *)); +/* WebPGetFeatures is a static inline function defined in WebP's + decode.h. Since we cannot use that with dynamically-loaded libwebp + DLL, we instead load the internal function it calls and redirect to + that through a macro. */ +DEF_DLL_FN (VP8StatusCode, WebPGetFeaturesInternal, + (const uint8_t *, size_t, WebPBitstreamFeatures *, int)); +DEF_DLL_FN (uint8_t *, WebPDecodeRGBA, (const uint8_t *, size_t, int *, int *)); +DEF_DLL_FN (uint8_t *, WebPDecodeRGB, (const uint8_t *, size_t, int *, int *)); +DEF_DLL_FN (void, WebPFree, (void *)); + +static bool +init_webp_functions (void) +{ + HMODULE library; + + if (!(library = w32_delayed_load (Qwebp))) + return false; + + LOAD_DLL_FN (library, WebPGetInfo); + LOAD_DLL_FN (library, WebPGetFeaturesInternal); + LOAD_DLL_FN (library, WebPDecodeRGBA); + LOAD_DLL_FN (library, WebPDecodeRGB); + LOAD_DLL_FN (library, WebPFree); + return true; +} + +#undef WebPGetInfo +#undef WebPGetFeatures +#undef WebPDecodeRGBA +#undef WebPDecodeRGB +#undef WebPFree + +#define WebPGetInfo fn_WebPGetInfo +#define WebPGetFeatures(d,s,f) \ + fn_WebPGetFeaturesInternal(d,s,f,WEBP_DECODER_ABI_VERSION) +#define WebPDecodeRGBA fn_WebPDecodeRGBA +#define WebPDecodeRGB fn_WebPDecodeRGB +#define WebPFree fn_WebPFree + +#endif /* WINDOWSNT */ + +/* Load WebP image IMG for use on frame F. Value is true if + successful. */ + +static bool +webp_load (struct frame *f, struct image *img) +{ + ptrdiff_t size = 0; + uint8_t *contents; + Lisp_Object file = Qnil; + + /* Open the WebP file. */ + Lisp_Object specified_file = image_spec_value (img->spec, QCfile, NULL); + Lisp_Object specified_data = image_spec_value (img->spec, QCdata, NULL); + + if (NILP (specified_data)) + { + int fd; + file = image_find_image_fd (specified_file, &fd); + if (!STRINGP (file)) + { + image_error ("Cannot find image file `%s'", specified_file); + return false; + } + + contents = (uint8_t *) slurp_file (fd, &size); + if (contents == NULL) + { + image_error ("Error loading WebP image `%s'", file); + return false; + } + } + else + { + if (!STRINGP (specified_data)) + { + image_error ("Invalid image data `%s'", specified_data); + return false; + } + contents = SDATA (specified_data); + size = SBYTES (specified_data); + } + + /* Validate the WebP image header. */ + if (!WebPGetInfo (contents, size, NULL, NULL)) + { + if (!NILP (file)) + image_error ("Not a WebP file: `%s'", file); + else + image_error ("Invalid header in WebP image data"); + goto webp_error1; + } + + /* Get WebP features. */ + WebPBitstreamFeatures features; + VP8StatusCode result = WebPGetFeatures (contents, size, &features); + switch (result) + { + case VP8_STATUS_OK: + break; + case VP8_STATUS_NOT_ENOUGH_DATA: + case VP8_STATUS_OUT_OF_MEMORY: + case VP8_STATUS_INVALID_PARAM: + case VP8_STATUS_BITSTREAM_ERROR: + case VP8_STATUS_UNSUPPORTED_FEATURE: + case VP8_STATUS_SUSPENDED: + case VP8_STATUS_USER_ABORT: + default: + /* Error out in all other cases. */ + if (!NILP (file)) + image_error ("Error when interpreting WebP image data: `%s'", file); + else + image_error ("Error when interpreting WebP image data"); + goto webp_error1; + } + + /* Decode WebP data. */ + uint8_t *decoded; + int width, height; + if (features.has_alpha) + /* Linear [r0, g0, b0, a0, r1, g1, b1, a1, ...] order. */ + decoded = WebPDecodeRGBA (contents, size, &width, &height); + else + /* Linear [r0, g0, b0, r1, g1, b1, ...] order. */ + decoded = WebPDecodeRGB (contents, size, &width, &height); + + if (!decoded) + { + image_error ("Error when interpreting WebP image data"); + goto webp_error1; + } + + if (!(width <= INT_MAX && height <= INT_MAX + && check_image_size (f, width, height))) + { + image_size_error (); + goto webp_error2; + } + + /* Create the x image and pixmap. */ + Emacs_Pix_Container ximg, mask_img = NULL; + if (!image_create_x_image_and_pixmap (f, img, width, height, 0, &ximg, false)) + goto webp_error2; + + /* Create an image and pixmap serving as mask if the WebP image + contains an alpha channel. */ + if (features.has_alpha + && !image_create_x_image_and_pixmap (f, img, width, height, 1, &mask_img, true)) + { + image_destroy_x_image (ximg); + image_clear_image_1 (f, img, CLEAR_IMAGE_PIXMAP); + goto webp_error2; + } + + /* Fill the X image and mask from WebP data. */ + init_color_table (); + + uint8_t *p = decoded; + for (int y = 0; y < height; ++y) + { + for (int x = 0; x < width; ++x) + { + int r = *p++ << 8; + int g = *p++ << 8; + int b = *p++ << 8; + PUT_PIXEL (ximg, x, y, lookup_rgb_color (f, r, g, b)); + + /* An alpha channel associates variable transparency with an + image. WebP allows up to 256 levels of partial transparency. + We handle this like with PNG (which see), using the frame's + background color to combine the image with. */ + if (features.has_alpha) + { + if (mask_img) + PUT_PIXEL (mask_img, x, y, *p > 0 ? PIX_MASK_DRAW : PIX_MASK_RETAIN); + ++p; + } + } + } + +#ifdef COLOR_TABLE_SUPPORT + /* Remember colors allocated for this image. */ + img->colors = colors_in_color_table (&img->ncolors); + free_color_table (); +#endif /* COLOR_TABLE_SUPPORT */ + + /* Put ximg into the image. */ + image_put_x_image (f, img, ximg, 0); + + /* Same for the mask. */ + if (mask_img) + { + /* Fill in the background_transparent field while we have the + mask handy. Casting avoids a GCC warning. */ + image_background_transparent (img, f, (Emacs_Pix_Context)mask_img); + + image_put_x_image (f, img, mask_img, 1); + } + + img->width = width; + img->height = height; + + /* Clean up. */ + WebPFree (decoded); + if (NILP (specified_data)) + xfree (contents); + return true; + + webp_error2: + WebPFree (decoded); + + webp_error1: + if (NILP (specified_data)) + xfree (contents); + return false; +} + +#endif /* HAVE_WEBP */ + + #ifdef HAVE_IMAGEMAGICK + /*********************************************************************** ImageMagick ***********************************************************************/ @@ -9117,11 +9642,15 @@ imagemagick_load_image (struct frame *f, struct image *img, PixelWand **pixels, *bg_wand = NULL; MagickPixelPacket pixel; Lisp_Object image; +#ifndef DONT_CREATE_TRANSFORMED_IMAGEMAGICK_IMAGE Lisp_Object value; +#endif Lisp_Object crop; EMACS_INT ino; int desired_width, desired_height; +#ifndef DONT_CREATE_TRANSFORMED_IMAGEMAGICK_IMAGE double rotation; +#endif char hint_buffer[MaxTextExtent]; char *filename_hint = NULL; imagemagick_initialize (); @@ -9238,9 +9767,13 @@ imagemagick_load_image (struct frame *f, struct image *img, PixelSetBlue (bg_wand, (double) bgcolor.blue / 65535); } +#ifndef DONT_CREATE_TRANSFORMED_IMAGEMAGICK_IMAGE compute_image_size (MagickGetImageWidth (image_wand), MagickGetImageHeight (image_wand), img, &desired_width, &desired_height); +#else + desired_width = desired_height = -1; +#endif if (desired_width != -1 && desired_height != -1) { @@ -9284,6 +9817,7 @@ imagemagick_load_image (struct frame *f, struct image *img, } } +#ifndef DONT_CREATE_TRANSFORMED_IMAGEMAGICK_IMAGE /* Furthermore :rotation. we need background color and angle for rotation. */ /* @@ -9302,6 +9836,7 @@ imagemagick_load_image (struct frame *f, struct image *img, goto imagemagick_error; } } +#endif /* Set the canvas background color to the frame or specified background, and flatten the image. Note: as of ImageMagick @@ -9339,7 +9874,8 @@ imagemagick_load_image (struct frame *f, struct image *img, init_color_table (); -#if defined (HAVE_MAGICKEXPORTIMAGEPIXELS) && ! defined (HAVE_NS) +#if defined (HAVE_MAGICKEXPORTIMAGEPIXELS) && \ + ! defined (HAVE_NS) && ! defined (HAVE_HAIKU) if (imagemagick_render_type != 0) { /* Magicexportimage is normally faster than pixelpushing. This @@ -9432,8 +9968,8 @@ imagemagick_load_image (struct frame *f, struct image *img, color_scale * pixel.red, color_scale * pixel.green, color_scale * pixel.blue)); - } - } + } + } DestroyPixelIterator (iterator); } @@ -9669,6 +10205,10 @@ DEF_DLL_FN (gboolean, rsvg_handle_close, (RsvgHandle *, GError **)); DEF_DLL_FN (void, rsvg_handle_set_dpi_x_y, (RsvgHandle * handle, double dpi_x, double dpi_y)); +# if LIBRSVG_CHECK_VERSION (2, 52, 1) +DEF_DLL_FN (gboolean, rsvg_handle_get_intrinsic_size_in_pixels, + (RsvgHandle *, gdouble *, gdouble *)); +# endif # if LIBRSVG_CHECK_VERSION (2, 46, 0) DEF_DLL_FN (void, rsvg_handle_get_intrinsic_dimensions, (RsvgHandle *, gboolean *, RsvgLength *, gboolean *, @@ -9676,14 +10216,15 @@ DEF_DLL_FN (void, rsvg_handle_get_intrinsic_dimensions, DEF_DLL_FN (gboolean, rsvg_handle_get_geometry_for_layer, (RsvgHandle *, const char *, const RsvgRectangle *, RsvgRectangle *, RsvgRectangle *, GError **)); +# else +DEF_DLL_FN (void, rsvg_handle_get_dimensions, + (RsvgHandle *, RsvgDimensionData *)); # endif # if LIBRSVG_CHECK_VERSION (2, 48, 0) DEF_DLL_FN (gboolean, rsvg_handle_set_stylesheet, (RsvgHandle *, const guint8 *, gsize, GError **)); # endif -DEF_DLL_FN (void, rsvg_handle_get_dimensions, - (RsvgHandle *, RsvgDimensionData *)); DEF_DLL_FN (GdkPixbuf *, rsvg_handle_get_pixbuf, (RsvgHandle *)); DEF_DLL_FN (int, gdk_pixbuf_get_width, (const GdkPixbuf *)); DEF_DLL_FN (int, gdk_pixbuf_get_height, (const GdkPixbuf *)); @@ -9731,14 +10272,18 @@ init_svg_functions (void) LOAD_DLL_FN (library, rsvg_handle_close); #endif LOAD_DLL_FN (library, rsvg_handle_set_dpi_x_y); +#if LIBRSVG_CHECK_VERSION (2, 52, 1) + LOAD_DLL_FN (library, rsvg_handle_get_intrinsic_size_in_pixels); +#endif #if LIBRSVG_CHECK_VERSION (2, 46, 0) LOAD_DLL_FN (library, rsvg_handle_get_intrinsic_dimensions); LOAD_DLL_FN (library, rsvg_handle_get_geometry_for_layer); +#else + LOAD_DLL_FN (library, rsvg_handle_get_dimensions); #endif #if LIBRSVG_CHECK_VERSION (2, 48, 0) LOAD_DLL_FN (library, rsvg_handle_set_stylesheet); #endif - LOAD_DLL_FN (library, rsvg_handle_get_dimensions); LOAD_DLL_FN (library, rsvg_handle_get_pixbuf); LOAD_DLL_FN (gdklib, gdk_pixbuf_get_width); @@ -9773,11 +10318,15 @@ init_svg_functions (void) # undef g_clear_error # undef g_object_unref # undef g_type_init +# if LIBRSVG_CHECK_VERSION (2, 52, 1) +# undef rsvg_handle_get_intrinsic_size_in_pixels +# endif # if LIBRSVG_CHECK_VERSION (2, 46, 0) # undef rsvg_handle_get_intrinsic_dimensions # undef rsvg_handle_get_geometry_for_layer +# else +# undef rsvg_handle_get_dimensions # endif -# undef rsvg_handle_get_dimensions # if LIBRSVG_CHECK_VERSION (2, 48, 0) # undef rsvg_handle_set_stylesheet # endif @@ -9807,13 +10356,18 @@ init_svg_functions (void) # if ! GLIB_CHECK_VERSION (2, 36, 0) # define g_type_init fn_g_type_init # endif +# if LIBRSVG_CHECK_VERSION (2, 52, 1) +# define rsvg_handle_get_intrinsic_size_in_pixels \ + fn_rsvg_handle_get_intrinsic_size_in_pixels +# endif # if LIBRSVG_CHECK_VERSION (2, 46, 0) # define rsvg_handle_get_intrinsic_dimensions \ fn_rsvg_handle_get_intrinsic_dimensions # define rsvg_handle_get_geometry_for_layer \ fn_rsvg_handle_get_geometry_for_layer +# else +# define rsvg_handle_get_dimensions fn_rsvg_handle_get_dimensions # endif -# define rsvg_handle_get_dimensions fn_rsvg_handle_get_dimensions # if LIBRSVG_CHECK_VERSION (2, 48, 0) # define rsvg_handle_set_stylesheet fn_rsvg_handle_set_stylesheet # endif @@ -10043,72 +10597,85 @@ svg_load_image (struct frame *f, struct image *img, char *contents, /* Get the image dimensions. */ #if LIBRSVG_CHECK_VERSION (2, 46, 0) - RsvgRectangle zero_rect, viewbox, out_logical_rect; - - /* Try the intrinsic dimensions first. */ - gboolean has_width, has_height, has_viewbox; - RsvgLength iwidth, iheight; - double dpi = FRAME_DISPLAY_INFO (f)->resx; - - rsvg_handle_get_intrinsic_dimensions (rsvg_handle, - &has_width, &iwidth, - &has_height, &iheight, - &has_viewbox, &viewbox); + gdouble gviewbox_width = 0, gviewbox_height = 0; + gboolean has_viewbox = FALSE; +# if LIBRSVG_CHECK_VERSION (2, 52, 1) + has_viewbox = rsvg_handle_get_intrinsic_size_in_pixels (rsvg_handle, + &gviewbox_width, + &gviewbox_height); +# endif - if (has_width && has_height) - { - /* Success! We can use these values directly. */ - viewbox_width = svg_css_length_to_pixels (iwidth, dpi, img->face_font_size); - viewbox_height = svg_css_length_to_pixels (iheight, dpi, img->face_font_size); - } - else if (has_width && has_viewbox) + if (has_viewbox) { - viewbox_width = svg_css_length_to_pixels (iwidth, dpi, img->face_font_size); - viewbox_height = svg_css_length_to_pixels (iwidth, dpi, img->face_font_size) - * viewbox.height / viewbox.width; - } - else if (has_height && has_viewbox) - { - viewbox_height = svg_css_length_to_pixels (iheight, dpi, img->face_font_size); - viewbox_width = svg_css_length_to_pixels (iheight, dpi, img->face_font_size) - * viewbox.width / viewbox.height; - } - else if (has_viewbox) - { - viewbox_width = viewbox.width; - viewbox_height = viewbox.height; + viewbox_width = gviewbox_width; + viewbox_height = gviewbox_height; } else { - /* We haven't found a usable set of sizes, so try working out - the visible area. */ - rsvg_handle_get_geometry_for_layer (rsvg_handle, NULL, - &zero_rect, &viewbox, - &out_logical_rect, NULL); - viewbox_width = viewbox.x + viewbox.width; - viewbox_height = viewbox.y + viewbox.height; - } + RsvgRectangle zero_rect, viewbox, out_logical_rect; - if (viewbox_width == 0 || viewbox_height == 0) -#endif - { - /* The functions used above to get the geometry of the visible - area of the SVG are only available in librsvg 2.46 and above, - so in certain circumstances this code path can result in some - parts of the SVG being cropped. */ - RsvgDimensionData dimension_data; + /* Try the intrinsic dimensions first. */ + gboolean has_width, has_height; + RsvgLength iwidth, iheight; + double dpi = FRAME_DISPLAY_INFO (f)->resx; - rsvg_handle_get_dimensions (rsvg_handle, &dimension_data); + rsvg_handle_get_intrinsic_dimensions (rsvg_handle, + &has_width, &iwidth, + &has_height, &iheight, + &has_viewbox, &viewbox); - viewbox_width = dimension_data.width; - viewbox_height = dimension_data.height; - } + if (has_width && has_height) + { + /* Success! We can use these values directly. */ + viewbox_width = svg_css_length_to_pixels (iwidth, dpi, + img->face_font_size); + viewbox_height = svg_css_length_to_pixels (iheight, dpi, + img->face_font_size); + } + else if (has_width && has_viewbox) + { + viewbox_width = svg_css_length_to_pixels (iwidth, dpi, + img->face_font_size); + viewbox_height = viewbox_width * viewbox.height / viewbox.width; + } + else if (has_height && has_viewbox) + { + viewbox_height = svg_css_length_to_pixels (iheight, dpi, + img->face_font_size); + viewbox_width = viewbox_height * viewbox.width / viewbox.height; + } + else if (has_viewbox) + { + viewbox_width = viewbox.width; + viewbox_height = viewbox.height; + } + else + viewbox_width = viewbox_height = 0; + + if (! (0 < viewbox_width && 0 < viewbox_height)) + { + /* We haven't found a usable set of sizes, so try working out + the visible area. */ + rsvg_handle_get_geometry_for_layer (rsvg_handle, NULL, + &zero_rect, &viewbox, + &out_logical_rect, NULL); + viewbox_width = viewbox.x + viewbox.width; + viewbox_height = viewbox.y + viewbox.height; + } + } +#else + /* In librsvg before 2.46.0, guess the viewbox from the image dimensions. */ + RsvgDimensionData dimension_data; + rsvg_handle_get_dimensions (rsvg_handle, &dimension_data); + viewbox_width = dimension_data.width; + viewbox_height = dimension_data.height; +#endif compute_image_size (viewbox_width, viewbox_height, img, &width, &height); - width *= FRAME_SCALE_FACTOR (f); - height *= FRAME_SCALE_FACTOR (f); + width = scale_image_size (width, 1, FRAME_SCALE_FACTOR (f)); + height = scale_image_size (height, 1, FRAME_SCALE_FACTOR (f)); if (! check_image_size (f, width, height)) { @@ -10555,16 +11122,6 @@ x_kill_gs_process (Pixmap pixmap, struct frame *f) free_color_table (); #endif XDestroyImage (ximg); - -#if 0 /* This doesn't seem to be the case. If we free the colors - here, we get a BadAccess later in image_clear_image when - freeing the colors. */ - /* We have allocated colors once, but Ghostscript has also - allocated colors on behalf of us. So, to get the - reference counts right, free them once. */ - if (img->ncolors) - x_free_colors (f, img->colors, img->ncolors); -#endif } else image_error ("Cannot get X image of `%s'; colors will not be freed", @@ -10633,7 +11190,8 @@ The list of capabilities can include one or more of the following: if (FRAME_WINDOW_P (f)) { #ifdef HAVE_NATIVE_TRANSFORMS -# if defined HAVE_IMAGEMAGICK || defined (USE_CAIRO) || defined (HAVE_NS) +# if defined HAVE_IMAGEMAGICK || defined (USE_CAIRO) || defined (HAVE_NS) \ + || defined (HAVE_HAIKU) return list2 (Qscale, Qrotate90); # elif defined (HAVE_X_WINDOWS) && defined (HAVE_XRENDER) int event_basep, error_basep; @@ -10723,10 +11281,14 @@ static struct image_type const image_types[] = { SYMBOL_INDEX (Qjpeg), jpeg_image_p, jpeg_load, image_clear_image, IMAGE_TYPE_INIT (init_jpeg_functions) }, #endif -#if defined HAVE_XPM || defined HAVE_NS +#if defined HAVE_XPM || defined HAVE_NS || defined HAVE_HAIKU || defined HAVE_PGTK { SYMBOL_INDEX (Qxpm), xpm_image_p, xpm_load, image_clear_image, IMAGE_TYPE_INIT (init_xpm_functions) }, #endif +#if defined HAVE_WEBP + { SYMBOL_INDEX (Qwebp), webp_image_p, webp_load, image_clear_image, + IMAGE_TYPE_INIT (init_webp_functions) }, +#endif { SYMBOL_INDEX (Qxbm), xbm_image_p, xbm_load, image_clear_image }, { SYMBOL_INDEX (Qpbm), pbm_image_p, pbm_load, image_clear_image }, }; @@ -10867,7 +11429,8 @@ non-numeric, there is no explicit limit on the size of images. */); DEFSYM (Qxbm, "xbm"); add_image_type (Qxbm); -#if defined (HAVE_XPM) || defined (HAVE_NS) +#if defined (HAVE_XPM) || defined (HAVE_NS) \ + || defined (HAVE_HAIKU) || defined (HAVE_PGTK) DEFSYM (Qxpm, "xpm"); add_image_type (Qxpm); #endif @@ -10892,6 +11455,11 @@ non-numeric, there is no explicit limit on the size of images. */); add_image_type (Qpng); #endif +#if defined (HAVE_WEBP) + DEFSYM (Qwebp, "webp"); + add_image_type (Qwebp); +#endif + #if defined (HAVE_IMAGEMAGICK) DEFSYM (Qimagemagick, "imagemagick"); add_image_type (Qimagemagick); @@ -10913,6 +11481,11 @@ non-numeric, there is no explicit limit on the size of images. */); #endif /* HAVE_NTGUI */ #endif /* HAVE_RSVG */ +#ifdef HAVE_NS + DEFSYM (Qheic, "heic"); + add_image_type (Qheic); +#endif + #if HAVE_NATIVE_IMAGE_API DEFSYM (Qnative_image, "native-image"); # ifdef HAVE_NTGUI |