diff options
| author | Lars Ingebrigtsen | 2022-04-11 13:35:45 +0200 |
|---|---|---|
| committer | Lars Ingebrigtsen | 2022-04-11 13:35:56 +0200 |
| commit | 5141234acf85fe232adcaa3b0278f7766eb0d250 (patch) | |
| tree | d46352aaa3261faa70db2b5ad75bfa385393cdb1 /src | |
| parent | 07ee24d83debfeb0570a596fa27e7203bf55a4b3 (diff) | |
| download | emacs-5141234acf85fe232adcaa3b0278f7766eb0d250.tar.gz emacs-5141234acf85fe232adcaa3b0278f7766eb0d250.zip | |
Refactor the webp cache code to allow usage by gif_load, too
* src/image.c (struct anim_cache, anim_create_cache)
(anim_prune_animation_cache, anim_get_animation_cache): Rename
from webp_cache (etc) to prepare for usage in the gif animation
implementation, too.
(webp_load): Adjust cache usage.
Diffstat (limited to 'src')
| -rw-r--r-- | src/image.c | 180 |
1 files changed, 97 insertions, 83 deletions
diff --git a/src/image.c b/src/image.c index 3f9111a7093..a3c98684261 100644 --- a/src/image.c +++ b/src/image.c | |||
| @@ -8431,6 +8431,95 @@ tiff_load (struct frame *f, struct image *img) | |||
| 8431 | 8431 | ||
| 8432 | 8432 | ||
| 8433 | 8433 | ||
| 8434 | |||
| 8435 | |||
| 8436 | #if defined (HAVE_WEBP) | ||
| 8437 | |||
| 8438 | /* To speed animations up, we keep a cache (based on EQ-ness of the | ||
| 8439 | image spec/object) where we put the animator iterator. */ | ||
| 8440 | |||
| 8441 | struct anim_cache | ||
| 8442 | { | ||
| 8443 | Lisp_Object spec; | ||
| 8444 | /* For webp, this will be an iterator, and for libgif, a gif handle. */ | ||
| 8445 | void *handle; | ||
| 8446 | /* If we need to maintain temporary data of some sort. */ | ||
| 8447 | void *temp; | ||
| 8448 | /* A function to call to free the handle. */ | ||
| 8449 | void (*destructor)(void*); | ||
| 8450 | int index, width, height, frames; | ||
| 8451 | struct timespec update_time; | ||
| 8452 | struct anim_cache *next; | ||
| 8453 | }; | ||
| 8454 | |||
| 8455 | static struct anim_cache *anim_cache = NULL; | ||
| 8456 | |||
| 8457 | static struct anim_cache * | ||
| 8458 | anim_create_cache (Lisp_Object spec) | ||
| 8459 | { | ||
| 8460 | struct anim_cache *cache = xmalloc (sizeof (struct anim_cache)); | ||
| 8461 | cache->handle = NULL; | ||
| 8462 | cache->temp = NULL; | ||
| 8463 | |||
| 8464 | cache->index = 0; | ||
| 8465 | cache->next = NULL; | ||
| 8466 | /* FIXME: Does this need gc protection? */ | ||
| 8467 | cache->spec = spec; | ||
| 8468 | return cache; | ||
| 8469 | } | ||
| 8470 | |||
| 8471 | /* Discard cached images that haven't been used for a minute. */ | ||
| 8472 | static void | ||
| 8473 | anim_prune_animation_cache (void) | ||
| 8474 | { | ||
| 8475 | struct anim_cache **pcache = &anim_cache; | ||
| 8476 | struct timespec old = timespec_sub (current_timespec (), | ||
| 8477 | make_timespec (60, 0)); | ||
| 8478 | |||
| 8479 | while (*pcache) | ||
| 8480 | { | ||
| 8481 | struct anim_cache *cache = *pcache; | ||
| 8482 | if (timespec_cmp (old, cache->update_time) <= 0) | ||
| 8483 | pcache = &cache->next; | ||
| 8484 | else | ||
| 8485 | { | ||
| 8486 | if (cache->handle) | ||
| 8487 | cache->destructor (cache->handle); | ||
| 8488 | if (cache->temp) | ||
| 8489 | xfree (cache->temp); | ||
| 8490 | *pcache = cache->next; | ||
| 8491 | xfree (cache); | ||
| 8492 | } | ||
| 8493 | } | ||
| 8494 | } | ||
| 8495 | |||
| 8496 | static struct anim_cache * | ||
| 8497 | anim_get_animation_cache (Lisp_Object spec) | ||
| 8498 | { | ||
| 8499 | struct anim_cache *cache; | ||
| 8500 | struct anim_cache **pcache = &anim_cache; | ||
| 8501 | |||
| 8502 | anim_prune_animation_cache (); | ||
| 8503 | |||
| 8504 | while (1) | ||
| 8505 | { | ||
| 8506 | cache = *pcache; | ||
| 8507 | if (! cache) | ||
| 8508 | { | ||
| 8509 | *pcache = cache = anim_create_cache (spec); | ||
| 8510 | break; | ||
| 8511 | } | ||
| 8512 | if (EQ (spec, cache->spec)) | ||
| 8513 | break; | ||
| 8514 | pcache = &cache->next; | ||
| 8515 | } | ||
| 8516 | |||
| 8517 | cache->update_time = current_timespec (); | ||
| 8518 | return cache; | ||
| 8519 | } | ||
| 8520 | |||
| 8521 | #endif /* HAVE_GIF || HAVE_WEBP */ | ||
| 8522 | |||
| 8434 | /*********************************************************************** | 8523 | /*********************************************************************** |
| 8435 | GIF | 8524 | GIF |
| 8436 | ***********************************************************************/ | 8525 | ***********************************************************************/ |
| @@ -9203,82 +9292,6 @@ init_webp_functions (void) | |||
| 9203 | 9292 | ||
| 9204 | #endif /* WINDOWSNT */ | 9293 | #endif /* WINDOWSNT */ |
| 9205 | 9294 | ||
| 9206 | /* To speed webp animations up, we keep a cache (based on EQ-ness of | ||
| 9207 | the image spec/object) where we put the libwebp animator | ||
| 9208 | iterator. */ | ||
| 9209 | |||
| 9210 | struct webp_cache | ||
| 9211 | { | ||
| 9212 | Lisp_Object spec; | ||
| 9213 | WebPAnimDecoder* anim; | ||
| 9214 | int index, width, height, frames; | ||
| 9215 | struct timespec update_time; | ||
| 9216 | struct webp_cache *next; | ||
| 9217 | }; | ||
| 9218 | |||
| 9219 | static struct webp_cache *webp_cache = NULL; | ||
| 9220 | |||
| 9221 | static struct webp_cache * | ||
| 9222 | webp_create_cache (Lisp_Object spec) | ||
| 9223 | { | ||
| 9224 | struct webp_cache *cache = xmalloc (sizeof (struct webp_cache)); | ||
| 9225 | cache->anim = NULL; | ||
| 9226 | |||
| 9227 | cache->index = 0; | ||
| 9228 | cache->next = NULL; | ||
| 9229 | /* FIXME: Does this need gc protection? */ | ||
| 9230 | cache->spec = spec; | ||
| 9231 | return cache; | ||
| 9232 | } | ||
| 9233 | |||
| 9234 | /* Discard cached images that haven't been used for a minute. */ | ||
| 9235 | static void | ||
| 9236 | webp_prune_animation_cache (void) | ||
| 9237 | { | ||
| 9238 | struct webp_cache **pcache = &webp_cache; | ||
| 9239 | struct timespec old = timespec_sub (current_timespec (), | ||
| 9240 | make_timespec (60, 0)); | ||
| 9241 | |||
| 9242 | while (*pcache) | ||
| 9243 | { | ||
| 9244 | struct webp_cache *cache = *pcache; | ||
| 9245 | if (timespec_cmp (old, cache->update_time) <= 0) | ||
| 9246 | pcache = &cache->next; | ||
| 9247 | else | ||
| 9248 | { | ||
| 9249 | if (cache->anim) | ||
| 9250 | WebPAnimDecoderDelete (cache->anim); | ||
| 9251 | *pcache = cache->next; | ||
| 9252 | xfree (cache); | ||
| 9253 | } | ||
| 9254 | } | ||
| 9255 | } | ||
| 9256 | |||
| 9257 | static struct webp_cache * | ||
| 9258 | webp_get_animation_cache (Lisp_Object spec) | ||
| 9259 | { | ||
| 9260 | struct webp_cache *cache; | ||
| 9261 | struct webp_cache **pcache = &webp_cache; | ||
| 9262 | |||
| 9263 | webp_prune_animation_cache (); | ||
| 9264 | |||
| 9265 | while (1) | ||
| 9266 | { | ||
| 9267 | cache = *pcache; | ||
| 9268 | if (! cache) | ||
| 9269 | { | ||
| 9270 | *pcache = cache = webp_create_cache (spec); | ||
| 9271 | break; | ||
| 9272 | } | ||
| 9273 | if (EQ (spec, cache->spec)) | ||
| 9274 | break; | ||
| 9275 | pcache = &cache->next; | ||
| 9276 | } | ||
| 9277 | |||
| 9278 | cache->update_time = current_timespec (); | ||
| 9279 | return cache; | ||
| 9280 | } | ||
| 9281 | |||
| 9282 | /* Load WebP image IMG for use on frame F. Value is true if | 9295 | /* Load WebP image IMG for use on frame F. Value is true if |
| 9283 | successful. */ | 9296 | successful. */ |
| 9284 | 9297 | ||
| @@ -9371,14 +9384,14 @@ webp_load (struct frame *f, struct image *img) | |||
| 9371 | webp_data.size = size; | 9384 | webp_data.size = size; |
| 9372 | int timestamp; | 9385 | int timestamp; |
| 9373 | 9386 | ||
| 9374 | struct webp_cache* cache = webp_get_animation_cache (img->spec); | 9387 | struct anim_cache* cache = anim_get_animation_cache (img->spec); |
| 9375 | /* Get the next frame from the animation cache. */ | 9388 | /* Get the next frame from the animation cache. */ |
| 9376 | if (cache->anim && cache->index == idx - 1) | 9389 | if (cache->handle && cache->index == idx - 1) |
| 9377 | { | 9390 | { |
| 9378 | WebPAnimDecoderGetNext (cache->anim, &decoded, ×tamp); | 9391 | WebPAnimDecoderGetNext (cache->handle, &decoded, ×tamp); |
| 9379 | delay = timestamp; | 9392 | delay = timestamp; |
| 9380 | cache->index++; | 9393 | cache->index++; |
| 9381 | anim = cache->anim; | 9394 | anim = cache->handle; |
| 9382 | width = cache->width; | 9395 | width = cache->width; |
| 9383 | height = cache->height; | 9396 | height = cache->height; |
| 9384 | frames = cache->frames; | 9397 | frames = cache->frames; |
| @@ -9386,8 +9399,8 @@ webp_load (struct frame *f, struct image *img) | |||
| 9386 | else | 9399 | else |
| 9387 | { | 9400 | { |
| 9388 | /* Start a new cache entry. */ | 9401 | /* Start a new cache entry. */ |
| 9389 | if (cache->anim) | 9402 | if (cache->handle) |
| 9390 | WebPAnimDecoderDelete (cache->anim); | 9403 | WebPAnimDecoderDelete (cache->handle); |
| 9391 | 9404 | ||
| 9392 | /* Get the width/height of the total image. */ | 9405 | /* Get the width/height of the total image. */ |
| 9393 | WebPDemuxer* demux = WebPDemux (&webp_data); | 9406 | WebPDemuxer* demux = WebPDemux (&webp_data); |
| @@ -9395,13 +9408,14 @@ webp_load (struct frame *f, struct image *img) | |||
| 9395 | cache->height = height = WebPDemuxGetI (demux, | 9408 | cache->height = height = WebPDemuxGetI (demux, |
| 9396 | WEBP_FF_CANVAS_HEIGHT); | 9409 | WEBP_FF_CANVAS_HEIGHT); |
| 9397 | cache->frames = frames = WebPDemuxGetI (demux, WEBP_FF_FRAME_COUNT); | 9410 | cache->frames = frames = WebPDemuxGetI (demux, WEBP_FF_FRAME_COUNT); |
| 9411 | cache->destructor = (void (*)(void *)) &WebPAnimDecoderDelete; | ||
| 9398 | WebPDemuxDelete (demux); | 9412 | WebPDemuxDelete (demux); |
| 9399 | 9413 | ||
| 9400 | WebPAnimDecoderOptions dec_options; | 9414 | WebPAnimDecoderOptions dec_options; |
| 9401 | WebPAnimDecoderOptionsInit (&dec_options); | 9415 | WebPAnimDecoderOptionsInit (&dec_options); |
| 9402 | anim = WebPAnimDecoderNew (&webp_data, &dec_options); | 9416 | anim = WebPAnimDecoderNew (&webp_data, &dec_options); |
| 9403 | 9417 | ||
| 9404 | cache->anim = anim; | 9418 | cache->handle = anim; |
| 9405 | cache->index = idx; | 9419 | cache->index = idx; |
| 9406 | 9420 | ||
| 9407 | while (WebPAnimDecoderHasMoreFrames (anim)) { | 9421 | while (WebPAnimDecoderHasMoreFrames (anim)) { |