aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLars Ingebrigtsen2022-07-14 18:58:12 +0200
committerLars Ingebrigtsen2022-07-14 18:59:09 +0200
commit564f6c171eeaef4dea4b4fc2524c0b082dfbb531 (patch)
tree014595873d94947428e4a1a604f0d7602d5d51ea
parent4c542747bd40f3098a20aafe001889607f044188 (diff)
downloademacs-564f6c171eeaef4dea4b4fc2524c0b082dfbb531.tar.gz
emacs-564f6c171eeaef4dea4b4fc2524c0b082dfbb531.zip
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.el15
-rw-r--r--src/image.c41
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."
966 (plist-put (cdr image) :animate-tardiness 966 (plist-put (cdr image) :animate-tardiness
967 (+ (* (plist-get (cdr image) :animate-tardiness) 0.9) 967 (+ (* (plist-get (cdr image) :animate-tardiness) 0.9)
968 (float-time (time-since target-time)))) 968 (float-time (time-since target-time))))
969 (let ((buffer (plist-get (cdr image) :animate-buffer)) 969 (let* ((buffer (plist-get (cdr image) :animate-buffer))
970 (position (plist-get (cdr image) :animate-position))) 970 (position (plist-get (cdr image) :animate-position))
971 (when (and (buffer-live-p buffer) 971 (continue-animation
972 (and (buffer-live-p buffer)
972 ;; If we have a :animate-position setting, the caller 973 ;; If we have a :animate-position setting, the caller
973 ;; has requested that the animation be stopped if the 974 ;; has requested that the animation be stopped if the
974 ;; image is no longer displayed in the buffer. 975 ;; image is no longer displayed in the buffer.
@@ -985,7 +986,13 @@ for the animation speed. A negative value means to animate in reverse."
985 (or (< (plist-get (cdr image) :animate-tardiness) 2) 986 (or (< (plist-get (cdr image) :animate-tardiness) 2)
986 (progn 987 (progn
987 (message "Stopping animation; animation possibly too big") 988 (message "Stopping animation; animation possibly too big")
988 nil))) 989 nil)))))
990 (if (not continue-animation)
991 ;; Eject from the animation cache since we've decided not to
992 ;; keep updating it. This helps stop unbounded RAM usage when
993 ;; doing, for instance, `g' in an eww buffer with animated
994 ;; images.
995 (clear-image-cache nil image)
989 (let* ((time (prog1 (current-time) 996 (let* ((time (prog1 (current-time)
990 (image-show-frame image n t))) 997 (image-show-frame image n t)))
991 (speed (image-animate-get-speed image)) 998 (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);
186static unsigned long *colors_in_color_table (int *n); 186static unsigned long *colors_in_color_table (int *n);
187#endif 187#endif
188 188
189#if defined (HAVE_WEBP) || defined (HAVE_GIF)
190static void anim_prune_animation_cache (Lisp_Object);
191#endif
192
189#ifdef USE_CAIRO 193#ifdef USE_CAIRO
190 194
191static Emacs_Pix_Container 195static Emacs_Pix_Container
@@ -2127,14 +2131,27 @@ clear_image_caches (Lisp_Object filter)
2127} 2131}
2128 2132
2129DEFUN ("clear-image-cache", Fclear_image_cache, Sclear_image_cache, 2133DEFUN ("clear-image-cache", Fclear_image_cache, Sclear_image_cache,
2130 0, 1, 0, 2134 0, 2, 0,
2131 doc: /* Clear the image cache. 2135 doc: /* Clear the image cache.
2132FILTER nil or a frame means clear all images in the selected frame. 2136FILTER nil or a frame means clear all images in the selected frame.
2133FILTER t means clear the image caches of all frames. 2137FILTER t means clear the image caches of all frames.
2134Anything else means clear only those images that refer to FILTER, 2138Anything else means clear only those images that refer to FILTER,
2135which is then usually a filename. */) 2139which is then usually a filename.
2136 (Lisp_Object filter) 2140
2141This function also clears the image animation cache. If
2142ANIMATION-CACHE is non-nil, only the image spec `eq' with
2143ANIMATION-CACHE is removed, and other image cache entries are not
2144evicted. */)
2145 (Lisp_Object filter, Lisp_Object animation_cache)
2137{ 2146{
2147 if (!NILP (animation_cache))
2148 {
2149#if defined (HAVE_WEBP) || defined (HAVE_GIF)
2150 anim_prune_animation_cache (XCDR (animation_cache));
2151#endif
2152 return Qnil;
2153 }
2154
2138 if (! (NILP (filter) || FRAMEP (filter))) 2155 if (! (NILP (filter) || FRAMEP (filter)))
2139 clear_image_caches (filter); 2156 clear_image_caches (filter);
2140 else 2157 else
@@ -3048,9 +3065,11 @@ anim_create_cache (Lisp_Object spec)
3048} 3065}
3049 3066
3050/* Discard cached images that haven't been used for a minute. If 3067/* Discard cached images that haven't been used for a minute. If
3051 CLEAR, remove all animation cache entries. */ 3068 CLEAR is t, remove all animation cache entries. If CLEAR is
3069 anything other than nil or t, only remove the entries that have a
3070 spec `eq' to CLEAR. */
3052static void 3071static void
3053anim_prune_animation_cache (bool clear) 3072anim_prune_animation_cache (Lisp_Object clear)
3054{ 3073{
3055 struct anim_cache **pcache = &anim_cache; 3074 struct anim_cache **pcache = &anim_cache;
3056 struct timespec old = timespec_sub (current_timespec (), 3075 struct timespec old = timespec_sub (current_timespec (),
@@ -3059,7 +3078,9 @@ anim_prune_animation_cache (bool clear)
3059 while (*pcache) 3078 while (*pcache)
3060 { 3079 {
3061 struct anim_cache *cache = *pcache; 3080 struct anim_cache *cache = *pcache;
3062 if (clear || timespec_cmp (old, cache->update_time) > 0) 3081 if (EQ (clear, Qt)
3082 || (EQ (clear, Qnil) && timespec_cmp (old, cache->update_time) > 0)
3083 || EQ (clear, cache->spec))
3063 { 3084 {
3064 if (cache->handle) 3085 if (cache->handle)
3065 cache->destructor (cache); 3086 cache->destructor (cache);
@@ -3079,7 +3100,7 @@ anim_get_animation_cache (Lisp_Object spec)
3079 struct anim_cache *cache; 3100 struct anim_cache *cache;
3080 struct anim_cache **pcache = &anim_cache; 3101 struct anim_cache **pcache = &anim_cache;
3081 3102
3082 anim_prune_animation_cache (false); 3103 anim_prune_animation_cache (Qnil);
3083 3104
3084 while (1) 3105 while (1)
3085 { 3106 {
@@ -9020,7 +9041,7 @@ gif_load (struct frame *f, struct image *img)
9020 if (!NILP (image_number)) 9041 if (!NILP (image_number))
9021 { 9042 {
9022 /* If this is an animated image, create a cache for it. */ 9043 /* If this is an animated image, create a cache for it. */
9023 cache = anim_get_animation_cache (img->spec); 9044 cache = anim_get_animation_cache (XCDR (img->spec));
9024 /* We have an old cache entry, so use it. */ 9045 /* We have an old cache entry, so use it. */
9025 if (cache->handle) 9046 if (cache->handle)
9026 { 9047 {
@@ -9722,7 +9743,7 @@ webp_load (struct frame *f, struct image *img)
9722 /* Animated image. */ 9743 /* Animated image. */
9723 int timestamp; 9744 int timestamp;
9724 9745
9725 struct anim_cache* cache = anim_get_animation_cache (img->spec); 9746 struct anim_cache* cache = anim_get_animation_cache (XCDR (img->spec));
9726 /* Get the next frame from the animation cache. */ 9747 /* Get the next frame from the animation cache. */
9727 if (cache->handle && cache->index == idx - 1) 9748 if (cache->handle && cache->index == idx - 1)
9728 { 9749 {
@@ -11998,7 +12019,7 @@ void
11998image_prune_animation_caches (bool clear) 12019image_prune_animation_caches (bool clear)
11999{ 12020{
12000#if defined (HAVE_WEBP) || defined (HAVE_GIF) 12021#if defined (HAVE_WEBP) || defined (HAVE_GIF)
12001 anim_prune_animation_cache (clear); 12022 anim_prune_animation_cache (clear? Qt: Qnil);
12002#endif 12023#endif
12003#ifdef HAVE_IMAGEMAGICK 12024#ifdef HAVE_IMAGEMAGICK
12004 imagemagick_prune_animation_cache (clear); 12025 imagemagick_prune_animation_cache (clear);