diff --git a/doc/lispref/display.texi b/doc/lispref/display.texi index 1d037807070..4211b435db5 100644 --- a/doc/lispref/display.texi +++ b/doc/lispref/display.texi @@ -7415,7 +7415,7 @@ period much shorter than @code{image-cache-eviction-delay} (see below), you can opt to flush unused images yourself, instead of waiting for Emacs to do it automatically. -@defun clear-image-cache &optional filter +@defun clear-image-cache &optional filter animation-filter This function clears an image cache, removing all the images stored in it. If @var{filter} is omitted or @code{nil}, it clears the cache for the selected frame. If @var{filter} is a frame, it clears the cache @@ -7423,6 +7423,16 @@ for that frame. If @var{filter} is @code{t}, all image caches are cleared. Otherwise, @var{filter} is taken to be a file name, and all images associated with that file name are removed from all image caches. + +This function also clears the image animation cache, which is a separate +cache that Emacs maintains for animated multi-frame images +(@pxref{Multi-Frame Images}). If @var{animation-filter} is omitted or +@code{nil}, it clears the animation cache in addition to the image +caches selected by @var{filter}. Otherwise, this function removes the +image with specification @code{eq} to @var{animation-filter} only from +the animation cache, and does not clear any image caches. This can help +reduce memory usage after an animation is stopped but the image is still +displayed. @end defun If an image in the image cache has not been displayed for a specified diff --git a/lisp/image.el b/lisp/image.el index 6048caea0be..a15d66c5a81 100644 --- a/lisp/image.el +++ b/lisp/image.el @@ -33,7 +33,7 @@ (declare-function image-flush "image.c" (spec &optional frame)) (declare-function clear-image-cache "image.c" - (&optional filter animation-cache)) + (&optional filter animation-filter)) (defconst image-type-header-regexps `(("\\`/[\t\n\r ]*\\*.*XPM.\\*/" . xpm) @@ -1053,6 +1053,7 @@ for the animation speed. A negative value means to animate in reverse." ;; keep updating it. This helps stop unbounded RAM usage when ;; doing, for instance, `g' in an eww buffer with animated ;; images. + ;; FIXME: This doesn't currently support ImageMagick. (clear-image-cache nil image) (let* ((time (prog1 (current-time) (image-show-frame image n t))) diff --git a/src/image.c b/src/image.c index f55596cd1ba..f5db851cfbd 100644 --- a/src/image.c +++ b/src/image.c @@ -2427,23 +2427,27 @@ clear_image_caches (Lisp_Object filter) DEFUN ("clear-image-cache", Fclear_image_cache, Sclear_image_cache, 0, 2, 0, - doc: /* Clear the image cache. + doc: /* Clear the image and animation caches. FILTER nil or a frame means clear all images in the selected frame. FILTER t means clear the image caches of all frames. Anything else means clear only those images that refer to FILTER, which is then usually a filename. -This function also clears the image animation cache. If -ANIMATION-CACHE is non-nil, only the image spec `eq' with -ANIMATION-CACHE is removed, and other image cache entries are not -evicted. */) - (Lisp_Object filter, Lisp_Object animation_cache) +This function also clears the image animation cache. +ANIMATION-FILTER nil means clear all animation cache entries. +Otherwise, clear the image spec `eq' to ANIMATION-FILTER only +from the animation cache, and do not clear any image caches. +This can help reduce memory usage after an animation is stopped +but the image is still displayed. */) + (Lisp_Object filter, Lisp_Object animation_filter) { - if (!NILP (animation_cache)) + if (!NILP (animation_filter)) { - CHECK_CONS (animation_cache); + /* IMAGEP? */ + CHECK_CONS (animation_filter); #if defined (HAVE_WEBP) || defined (HAVE_GIF) - anim_prune_animation_cache (XCDR (animation_cache)); + /* FIXME: Implement the ImageMagick case. */ + anim_prune_animation_cache (XCDR (animation_filter)); #endif return Qnil; } @@ -3683,6 +3687,8 @@ cache_image (struct frame *f, struct image *img) struct anim_cache { + /* 'Key' of this cache entry. + Typically the cdr (plist) of an image spec. */ Lisp_Object spec; /* For webp, this will be an iterator, and for libgif, a gif handle. */ void *handle; @@ -3690,18 +3696,26 @@ struct anim_cache void *temp; /* A function to call to free the handle. */ void (*destructor) (void *); - int index, width, height, frames; + /* Current frame index, and total number of frames. Note that + different image formats may start at different indices. */ + int index, frames; + /* Animation frame dimensions. */ + int width, height; /* This is used to be able to say something about the cache size. - We don't actually know how much memory the different libraries - actually use here (since these cache structures are opaque), so - this is mostly just the size of the original image file. */ + We don't know how much memory the different libraries actually + use here (since these cache structures are opaque), so this is + mostly just the size of the original image file. */ intmax_t byte_size; + /* Last time this cache entry was updated. */ struct timespec update_time; struct anim_cache *next; }; static struct anim_cache *anim_cache = NULL; +/* Return a new animation cache entry for image SPEC (which need not be + an image specification, and is typically its cdr/plist). + Freed only by pruning the cache. */ static struct anim_cache * anim_create_cache (Lisp_Object spec) { @@ -3773,11 +3787,7 @@ anim_get_animation_cache (Lisp_Object spec) #endif /* HAVE_WEBP || HAVE_GIF */ -/* Call FN on every image in the image cache of frame F. Used to mark - Lisp Objects in the image cache. */ - /* Mark Lisp objects in image IMG. */ - static void mark_image (struct image *img) { @@ -3788,7 +3798,8 @@ mark_image (struct image *img) mark_object (img->lisp_data); } - +/* Mark every image in image cache C, as well as the global animation + cache. */ void mark_image_cache (struct image_cache *c) { @@ -10884,7 +10895,7 @@ imagemagick_filename_hint (Lisp_Object spec, char hint_buffer[MaxTextExtent]) } /* Animated images (e.g., GIF89a) are composed from one "master image" - (which is the first one, and then there's a number of images that + (which is the first one), and then there's a number of images that follow. If following images have non-transparent colors, these are composed "on top" of the master image. So, in general, one has to compute all the preceding images to be able to display a particular @@ -10893,7 +10904,10 @@ imagemagick_filename_hint (Lisp_Object spec, char hint_buffer[MaxTextExtent]) Computing all the preceding images is too slow, so we maintain a cache of previously computed images. We have to maintain a cache separate from the image cache, because the images may be scaled - before display. */ + before display. + + FIXME: Consolidate this with the GIF and WebP anim_cache. + Not just for DRY, but for Fclear_image_cache too. */ struct animation_cache { @@ -12898,11 +12912,12 @@ lookup_image_type (Lisp_Object type) return NULL; } -/* Prune the animation caches. If CLEAR, remove all animation cache - entries. */ +/* Prune old entries from the animation cache. + If CLEAR, remove all animation cache entries. */ void image_prune_animation_caches (bool clear) { + /* FIXME: Consolidate these animation cache implementations. */ #if defined (HAVE_WEBP) || defined (HAVE_GIF) anim_prune_animation_cache (clear? Qt: Qnil); #endif