diff options
author | Lars Ingebrigtsen <larsi@gnus.org> | 2022-07-14 18:58:12 +0200 |
---|---|---|
committer | Lars Ingebrigtsen <larsi@gnus.org> | 2022-07-14 18:59:09 +0200 |
commit | 564f6c171eeaef4dea4b4fc2524c0b082dfbb531 (patch) | |
tree | 014595873d94947428e4a1a604f0d7602d5d51ea | |
parent | 4c542747bd40f3098a20aafe001889607f044188 (diff) | |
download | emacs-564f6c171eeaef4dea4b4fc2524c0b082dfbb531.tar.gz |
Prune animation cache when images are no longer reachable
* lisp/image.el (image-animate-timeout): Eject cached animated
images that are no longer reachable (bug#56546).
* src/image.c (Fclear_image_cache): Allow specifying a cached
animated image to eject.
(gif_load, webp_load): Adjust what to use as the caching key --
the identity of the list itself is apparently changed by some
callers.
-rw-r--r-- | lisp/image.el | 15 | ||||
-rw-r--r-- | src/image.c | 41 |
2 files changed, 42 insertions, 14 deletions
diff --git a/lisp/image.el b/lisp/image.el index bdaaec608ef..f4f73fd31f2 100644 --- a/lisp/image.el +++ b/lisp/image.el @@ -966,9 +966,10 @@ for the animation speed. A negative value means to animate in reverse." (plist-put (cdr image) :animate-tardiness (+ (* (plist-get (cdr image) :animate-tardiness) 0.9) (float-time (time-since target-time)))) - (let ((buffer (plist-get (cdr image) :animate-buffer)) - (position (plist-get (cdr image) :animate-position))) - (when (and (buffer-live-p buffer) + (let* ((buffer (plist-get (cdr image) :animate-buffer)) + (position (plist-get (cdr image) :animate-position)) + (continue-animation + (and (buffer-live-p buffer) ;; If we have a :animate-position setting, the caller ;; has requested that the animation be stopped if the ;; image is no longer displayed in the buffer. @@ -985,7 +986,13 @@ for the animation speed. A negative value means to animate in reverse." (or (< (plist-get (cdr image) :animate-tardiness) 2) (progn (message "Stopping animation; animation possibly too big") - nil))) + nil))))) + (if (not continue-animation) + ;; Eject from the animation cache since we've decided not to + ;; keep updating it. This helps stop unbounded RAM usage when + ;; doing, for instance, `g' in an eww buffer with animated + ;; images. + (clear-image-cache nil image) (let* ((time (prog1 (current-time) (image-show-frame image n t))) (speed (image-animate-get-speed image)) diff --git a/src/image.c b/src/image.c index ba2a1f4294e..f5004c2c4c7 100644 --- a/src/image.c +++ b/src/image.c @@ -186,6 +186,10 @@ static void free_color_table (void); static unsigned long *colors_in_color_table (int *n); #endif +#if defined (HAVE_WEBP) || defined (HAVE_GIF) +static void anim_prune_animation_cache (Lisp_Object); +#endif + #ifdef USE_CAIRO static Emacs_Pix_Container @@ -2127,14 +2131,27 @@ clear_image_caches (Lisp_Object filter) } DEFUN ("clear-image-cache", Fclear_image_cache, Sclear_image_cache, - 0, 1, 0, + 0, 2, 0, doc: /* Clear the image cache. 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. */) - (Lisp_Object 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) { + if (!NILP (animation_cache)) + { +#if defined (HAVE_WEBP) || defined (HAVE_GIF) + anim_prune_animation_cache (XCDR (animation_cache)); +#endif + return Qnil; + } + if (! (NILP (filter) || FRAMEP (filter))) clear_image_caches (filter); else @@ -3048,9 +3065,11 @@ anim_create_cache (Lisp_Object spec) } /* Discard cached images that haven't been used for a minute. If - CLEAR, remove all animation cache entries. */ + CLEAR is t, remove all animation cache entries. If CLEAR is + anything other than nil or t, only remove the entries that have a + spec `eq' to CLEAR. */ static void -anim_prune_animation_cache (bool clear) +anim_prune_animation_cache (Lisp_Object clear) { struct anim_cache **pcache = &anim_cache; struct timespec old = timespec_sub (current_timespec (), @@ -3059,7 +3078,9 @@ anim_prune_animation_cache (bool clear) while (*pcache) { struct anim_cache *cache = *pcache; - if (clear || timespec_cmp (old, cache->update_time) > 0) + if (EQ (clear, Qt) + || (EQ (clear, Qnil) && timespec_cmp (old, cache->update_time) > 0) + || EQ (clear, cache->spec)) { if (cache->handle) cache->destructor (cache); @@ -3079,7 +3100,7 @@ anim_get_animation_cache (Lisp_Object spec) struct anim_cache *cache; struct anim_cache **pcache = &anim_cache; - anim_prune_animation_cache (false); + anim_prune_animation_cache (Qnil); while (1) { @@ -9020,7 +9041,7 @@ gif_load (struct frame *f, struct image *img) if (!NILP (image_number)) { /* If this is an animated image, create a cache for it. */ - cache = anim_get_animation_cache (img->spec); + cache = anim_get_animation_cache (XCDR (img->spec)); /* We have an old cache entry, so use it. */ if (cache->handle) { @@ -9722,7 +9743,7 @@ webp_load (struct frame *f, struct image *img) /* Animated image. */ int timestamp; - struct anim_cache* cache = anim_get_animation_cache (img->spec); + struct anim_cache* cache = anim_get_animation_cache (XCDR (img->spec)); /* Get the next frame from the animation cache. */ if (cache->handle && cache->index == idx - 1) { @@ -11998,7 +12019,7 @@ void image_prune_animation_caches (bool clear) { #if defined (HAVE_WEBP) || defined (HAVE_GIF) - anim_prune_animation_cache (clear); + anim_prune_animation_cache (clear? Qt: Qnil); #endif #ifdef HAVE_IMAGEMAGICK imagemagick_prune_animation_cache (clear); |