aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorAlan Third2021-03-28 17:52:57 +0100
committerAlan Third2021-04-03 23:07:01 +0100
commit1fdbeffe3a65cb23abb43a4ea59df9553c9246f9 (patch)
treee0bf007c9aa559aa184c05ee795e8abe6d787db7 /src
parent40842f67afb2931de6789237a49570f99b70404f (diff)
downloademacs-1fdbeffe3a65cb23abb43a4ea59df9553c9246f9.tar.gz
emacs-1fdbeffe3a65cb23abb43a4ea59df9553c9246f9.zip
Set CSS for SVG files
* src/dispextern.h (struct image): Add font details required for the CSS. * src/image.c (free_image): Free the font family string. (search_image_cache): (uncache_image): Make image caching understand the font details. (lookup_image): Handle the font details when generating the image and looking up the cache. (svg_css_length_to_pixels): Handle 'em' when we know the font size. (svg_load_image): Generate the CSS and apply it to the SVG. (enum svg_keyword_index): (svg_format): (syms_of_image): Add ':css' attribute. * doc/lispref/display.texi (SVG Images): Add details of new svg image attributes.
Diffstat (limited to 'src')
-rw-r--r--src/dispextern.h5
-rw-r--r--src/image.c84
2 files changed, 74 insertions, 15 deletions
diff --git a/src/dispextern.h b/src/dispextern.h
index f4e872644db..a2ebd04f235 100644
--- a/src/dispextern.h
+++ b/src/dispextern.h
@@ -3066,6 +3066,11 @@ struct image
3066 is created. */ 3066 is created. */
3067 unsigned long face_foreground, face_background; 3067 unsigned long face_foreground, face_background;
3068 3068
3069 /* Details of the font, only really relevant for types like SVG that
3070 allow us to draw text. */
3071 int face_font_size;
3072 char *face_font_family;
3073
3069 /* True if this image has a `transparent' background -- that is, is 3074 /* True if this image has a `transparent' background -- that is, is
3070 uses an image mask. The accessor macro for this is 3075 uses an image mask. The accessor macro for this is
3071 `IMAGE_BACKGROUND_TRANSPARENT'. */ 3076 `IMAGE_BACKGROUND_TRANSPARENT'. */
diff --git a/src/image.c b/src/image.c
index 774b7e14ea9..13bd503e535 100644
--- a/src/image.c
+++ b/src/image.c
@@ -1199,6 +1199,7 @@ free_image (struct frame *f, struct image *img)
1199 1199
1200 /* Free resources, then free IMG. */ 1200 /* Free resources, then free IMG. */
1201 img->type->free_img (f, img); 1201 img->type->free_img (f, img);
1202 xfree (img->face_font_family);
1202 xfree (img); 1203 xfree (img);
1203 } 1204 }
1204} 1205}
@@ -1597,7 +1598,7 @@ make_image_cache (void)
1597static struct image * 1598static struct image *
1598search_image_cache (struct frame *f, Lisp_Object spec, EMACS_UINT hash, 1599search_image_cache (struct frame *f, Lisp_Object spec, EMACS_UINT hash,
1599 unsigned long foreground, unsigned long background, 1600 unsigned long foreground, unsigned long background,
1600 bool ignore_colors) 1601 int font_size, char *font_family, bool ignore_colors)
1601{ 1602{
1602 struct image *img; 1603 struct image *img;
1603 struct image_cache *c = FRAME_IMAGE_CACHE (f); 1604 struct image_cache *c = FRAME_IMAGE_CACHE (f);
@@ -1621,7 +1622,10 @@ search_image_cache (struct frame *f, Lisp_Object spec, EMACS_UINT hash,
1621 if (img->hash == hash 1622 if (img->hash == hash
1622 && !NILP (Fequal (img->spec, spec)) 1623 && !NILP (Fequal (img->spec, spec))
1623 && (ignore_colors || (img->face_foreground == foreground 1624 && (ignore_colors || (img->face_foreground == foreground
1624 && img->face_background == background))) 1625 && img->face_background == background
1626 && img->face_font_size == font_size
1627 && (font_family
1628 &&!strcmp (font_family, img->face_font_family)))))
1625 break; 1629 break;
1626 return img; 1630 return img;
1627} 1631}
@@ -1639,7 +1643,7 @@ uncache_image (struct frame *f, Lisp_Object spec)
1639 can have multiple copies of an image with the same spec. We want 1643 can have multiple copies of an image with the same spec. We want
1640 to remove them all to ensure the user doesn't see an old version 1644 to remove them all to ensure the user doesn't see an old version
1641 of the image when the face changes. */ 1645 of the image when the face changes. */
1642 while ((img = search_image_cache (f, spec, hash, 0, 0, true))) 1646 while ((img = search_image_cache (f, spec, hash, 0, 0, 0, NULL, true)))
1643 { 1647 {
1644 free_image (f, img); 1648 free_image (f, img);
1645 /* As display glyphs may still be referring to the image ID, we 1649 /* As display glyphs may still be referring to the image ID, we
@@ -2411,6 +2415,8 @@ lookup_image (struct frame *f, Lisp_Object spec, int face_id)
2411 struct face *face = FACE_FROM_ID (f, face_id); 2415 struct face *face = FACE_FROM_ID (f, face_id);
2412 unsigned long foreground = FACE_COLOR_TO_PIXEL (face->foreground, f); 2416 unsigned long foreground = FACE_COLOR_TO_PIXEL (face->foreground, f);
2413 unsigned long background = FACE_COLOR_TO_PIXEL (face->background, f); 2417 unsigned long background = FACE_COLOR_TO_PIXEL (face->background, f);
2418 int font_size = face->font->pixel_size;
2419 char *font_family = SSDATA (face->lface[LFACE_FAMILY_INDEX]);
2414 2420
2415 /* F must be a window-system frame, and SPEC must be a valid image 2421 /* F must be a window-system frame, and SPEC must be a valid image
2416 specification. */ 2422 specification. */
@@ -2419,7 +2425,8 @@ lookup_image (struct frame *f, Lisp_Object spec, int face_id)
2419 2425
2420 /* Look up SPEC in the hash table of the image cache. */ 2426 /* Look up SPEC in the hash table of the image cache. */
2421 hash = sxhash (spec); 2427 hash = sxhash (spec);
2422 img = search_image_cache (f, spec, hash, foreground, background, false); 2428 img = search_image_cache (f, spec, hash, foreground, background,
2429 font_size, font_family, false);
2423 if (img && img->load_failed_p) 2430 if (img && img->load_failed_p)
2424 { 2431 {
2425 free_image (f, img); 2432 free_image (f, img);
@@ -2434,6 +2441,9 @@ lookup_image (struct frame *f, Lisp_Object spec, int face_id)
2434 cache_image (f, img); 2441 cache_image (f, img);
2435 img->face_foreground = foreground; 2442 img->face_foreground = foreground;
2436 img->face_background = background; 2443 img->face_background = background;
2444 img->face_font_size = font_size;
2445 img->face_font_family = malloc (strlen (font_family) + 1);
2446 strcpy (img->face_font_family, font_family);
2437 img->load_failed_p = ! img->type->load_img (f, img); 2447 img->load_failed_p = ! img->type->load_img (f, img);
2438 2448
2439 /* If we can't load the image, and we don't have a width and 2449 /* If we can't load the image, and we don't have a width and
@@ -9532,6 +9542,7 @@ enum svg_keyword_index
9532 SVG_DATA, 9542 SVG_DATA,
9533 SVG_FILE, 9543 SVG_FILE,
9534 SVG_BASE_URI, 9544 SVG_BASE_URI,
9545 SVG_CSS,
9535 SVG_ASCENT, 9546 SVG_ASCENT,
9536 SVG_MARGIN, 9547 SVG_MARGIN,
9537 SVG_RELIEF, 9548 SVG_RELIEF,
@@ -9552,6 +9563,7 @@ static const struct image_keyword svg_format[SVG_LAST] =
9552 {":data", IMAGE_STRING_VALUE, 0}, 9563 {":data", IMAGE_STRING_VALUE, 0},
9553 {":file", IMAGE_STRING_VALUE, 0}, 9564 {":file", IMAGE_STRING_VALUE, 0},
9554 {":base-uri", IMAGE_STRING_VALUE, 0}, 9565 {":base-uri", IMAGE_STRING_VALUE, 0},
9566 {":css", IMAGE_STRING_VALUE, 0},
9555 {":ascent", IMAGE_ASCENT_VALUE, 0}, 9567 {":ascent", IMAGE_ASCENT_VALUE, 0},
9556 {":margin", IMAGE_NON_NEGATIVE_INTEGER_VALUE_OR_PAIR, 0}, 9568 {":margin", IMAGE_NON_NEGATIVE_INTEGER_VALUE_OR_PAIR, 0},
9557 {":relief", IMAGE_INTEGER_VALUE, 0}, 9569 {":relief", IMAGE_INTEGER_VALUE, 0},
@@ -9838,7 +9850,7 @@ svg_load (struct frame *f, struct image *img)
9838 9850
9839#if LIBRSVG_CHECK_VERSION (2, 46, 0) 9851#if LIBRSVG_CHECK_VERSION (2, 46, 0)
9840static double 9852static double
9841svg_css_length_to_pixels (RsvgLength length, double dpi) 9853svg_css_length_to_pixels (RsvgLength length, double dpi, int font_size)
9842{ 9854{
9843 double value = length.length; 9855 double value = length.length;
9844 9856
@@ -9866,9 +9878,16 @@ svg_css_length_to_pixels (RsvgLength length, double dpi)
9866 case RSVG_UNIT_IN: 9878 case RSVG_UNIT_IN:
9867 value *= dpi; 9879 value *= dpi;
9868 break; 9880 break;
9881#if LIBRSVG_CHECK_VERSION (2, 48, 0)
9882 /* We don't know exactly what font size is used on older librsvg
9883 versions. */
9884 case RSVG_UNIT_EM:
9885 value *= font_size;
9886 break;
9887#endif
9869 default: 9888 default:
9870 /* Probably one of em, ex, or %. We can't know what the pixel 9889 /* Probably ex or %. We can't know what the pixel value is
9871 value is without more information. */ 9890 without more information. */
9872 value = 0; 9891 value = 0;
9873 } 9892 }
9874 9893
@@ -9923,6 +9942,27 @@ svg_load_image (struct frame *f, struct image *img, char *contents,
9923 9942
9924 rsvg_handle_set_dpi_x_y (rsvg_handle, FRAME_DISPLAY_INFO (f)->resx, 9943 rsvg_handle_set_dpi_x_y (rsvg_handle, FRAME_DISPLAY_INFO (f)->resx,
9925 FRAME_DISPLAY_INFO (f)->resy); 9944 FRAME_DISPLAY_INFO (f)->resy);
9945
9946#if LIBRSVG_CHECK_VERSION (2, 48, 0)
9947 char *css;
9948 Lisp_Object lcss = image_spec_value (img->spec, QCcss, NULL);
9949 if (!STRINGP (lcss))
9950 {
9951 /* Generate the CSS for the SVG image. */
9952 char *css_spec = "svg{font-family:\"%s\";font-size:%4dpx}";
9953 int css_len = strlen (css_spec) + strlen (img->face_font_family);
9954 css = xmalloc (css_len);
9955 snprintf (css, css_len, css_spec, img->face_font_family, img->face_font_size);
9956 rsvg_handle_set_stylesheet (rsvg_handle, css, strlen (css), NULL);
9957 }
9958 else
9959 {
9960 css = xmalloc (SBYTES (lcss) + 1);
9961 strncpy (css, SSDATA (lcss), SBYTES (lcss));
9962 *(css + SBYTES (lcss) + 1) = 0;
9963 }
9964#endif
9965
9926#else 9966#else
9927 /* Make a handle to a new rsvg object. */ 9967 /* Make a handle to a new rsvg object. */
9928 rsvg_handle = rsvg_handle_new (); 9968 rsvg_handle = rsvg_handle_new ();
@@ -9965,20 +10005,20 @@ svg_load_image (struct frame *f, struct image *img, char *contents,
9965 if (has_width && has_height) 10005 if (has_width && has_height)
9966 { 10006 {
9967 /* Success! We can use these values directly. */ 10007 /* Success! We can use these values directly. */
9968 viewbox_width = svg_css_length_to_pixels (iwidth, dpi); 10008 viewbox_width = svg_css_length_to_pixels (iwidth, dpi, img->face_font_size);
9969 viewbox_height = svg_css_length_to_pixels (iheight, dpi); 10009 viewbox_height = svg_css_length_to_pixels (iheight, dpi, img->face_font_size);
9970 } 10010 }
9971 else if (has_width && has_viewbox) 10011 else if (has_width && has_viewbox)
9972 { 10012 {
9973 viewbox_width = svg_css_length_to_pixels (iwidth, dpi); 10013 viewbox_width = svg_css_length_to_pixels (iwidth, dpi, img->face_font_size);
9974 viewbox_height = svg_css_length_to_pixels (iwidth, dpi) 10014 viewbox_height = svg_css_length_to_pixels (iwidth, dpi, img->face_font_size)
9975 * viewbox.width / viewbox.height; 10015 * viewbox.height / viewbox.width;
9976 } 10016 }
9977 else if (has_height && has_viewbox) 10017 else if (has_height && has_viewbox)
9978 { 10018 {
9979 viewbox_height = svg_css_length_to_pixels (iheight, dpi); 10019 viewbox_height = svg_css_length_to_pixels (iheight, dpi, img->face_font_size);
9980 viewbox_width = svg_css_length_to_pixels (iheight, dpi) 10020 viewbox_width = svg_css_length_to_pixels (iheight, dpi, img->face_font_size)
9981 * viewbox.height / viewbox.width; 10021 * viewbox.width / viewbox.height;
9982 } 10022 }
9983 else if (has_viewbox) 10023 else if (has_viewbox)
9984 { 10024 {
@@ -10099,6 +10139,10 @@ svg_load_image (struct frame *f, struct image *img, char *contents,
10099 10139
10100 rsvg_handle_set_dpi_x_y (rsvg_handle, FRAME_DISPLAY_INFO (f)->resx, 10140 rsvg_handle_set_dpi_x_y (rsvg_handle, FRAME_DISPLAY_INFO (f)->resx,
10101 FRAME_DISPLAY_INFO (f)->resy); 10141 FRAME_DISPLAY_INFO (f)->resy);
10142
10143#if LIBRSVG_CHECK_VERSION (2, 48, 0)
10144 rsvg_handle_set_stylesheet (rsvg_handle, css, strlen (css), NULL);
10145#endif
10102#else 10146#else
10103 /* Make a handle to a new rsvg object. */ 10147 /* Make a handle to a new rsvg object. */
10104 rsvg_handle = rsvg_handle_new (); 10148 rsvg_handle = rsvg_handle_new ();
@@ -10132,6 +10176,11 @@ svg_load_image (struct frame *f, struct image *img, char *contents,
10132 g_object_unref (rsvg_handle); 10176 g_object_unref (rsvg_handle);
10133 xfree (wrapped_contents); 10177 xfree (wrapped_contents);
10134 10178
10179#if LIBRSVG_CHECK_VERSION (2, 48, 0)
10180 if (!STRINGP (lcss))
10181 xfree (css);
10182#endif
10183
10135 /* Extract some meta data from the svg handle. */ 10184 /* Extract some meta data from the svg handle. */
10136 width = gdk_pixbuf_get_width (pixbuf); 10185 width = gdk_pixbuf_get_width (pixbuf);
10137 height = gdk_pixbuf_get_height (pixbuf); 10186 height = gdk_pixbuf_get_height (pixbuf);
@@ -10202,6 +10251,10 @@ svg_load_image (struct frame *f, struct image *img, char *contents,
10202 g_object_unref (rsvg_handle); 10251 g_object_unref (rsvg_handle);
10203 if (wrapped_contents) 10252 if (wrapped_contents)
10204 xfree (wrapped_contents); 10253 xfree (wrapped_contents);
10254#if LIBRSVG_CHECK_VERSION (2, 48, 0)
10255 if (css && !STRINGP (lcss))
10256 xfree (css);
10257#endif
10205 /* FIXME: Use error->message so the user knows what is the actual 10258 /* FIXME: Use error->message so the user knows what is the actual
10206 problem with the image. */ 10259 problem with the image. */
10207 image_error ("Error parsing SVG image `%s'", img->spec); 10260 image_error ("Error parsing SVG image `%s'", img->spec);
@@ -10793,6 +10846,7 @@ non-numeric, there is no explicit limit on the size of images. */);
10793#if defined (HAVE_RSVG) 10846#if defined (HAVE_RSVG)
10794 DEFSYM (Qsvg, "svg"); 10847 DEFSYM (Qsvg, "svg");
10795 DEFSYM (QCbase_uri, ":base-uri"); 10848 DEFSYM (QCbase_uri, ":base-uri");
10849 DEFSYM (QCcss, ":css");
10796 add_image_type (Qsvg); 10850 add_image_type (Qsvg);
10797#ifdef HAVE_NTGUI 10851#ifdef HAVE_NTGUI
10798 /* Other libraries used directly by svg code. */ 10852 /* Other libraries used directly by svg code. */