summaryrefslogtreecommitdiff
path: root/src/image.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/image.c')
-rw-r--r--src/image.c967
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