From 295a9501067511bf82d48f273c88b9b9f94f483f Mon Sep 17 00:00:00 2001 From: Manuel Giraud Date: Thu, 17 Oct 2024 11:27:56 +0200 Subject: [PATCH] User controlled image cache --- src/alloc.c | 3 +- src/dispextern.h | 31 +++-- src/frame.h | 16 ++- src/image.c | 310 ++++++++++++++++++++++++++++++++++++----------- src/xfaces.c | 19 +++ 5 files changed, 290 insertions(+), 89 deletions(-) diff --git a/src/alloc.c b/src/alloc.c index 4fab0d54248..eee76fa11ce 100644 --- a/src/alloc.c +++ b/src/alloc.c @@ -7042,8 +7042,7 @@ mark_frame (struct Lisp_Vector *ptr) #ifdef HAVE_WINDOW_SYSTEM /* Mark this frame's image cache, though it might be common to several frames with the same font size. */ - if (FRAME_IMAGE_CACHE (f)) - mark_image_cache (FRAME_IMAGE_CACHE (f)); + mark_image_store (f); #endif /* HAVE_WINDOW_SYSTEM */ } diff --git a/src/dispextern.h b/src/dispextern.h index cc248a4472e..63445772509 100644 --- a/src/dispextern.h +++ b/src/dispextern.h @@ -3141,6 +3141,12 @@ reset_mouse_highlight (Mouse_HLInfo *hlinfo) in prepare_image_for_display. */ struct timespec timestamp; + /* The end of life for an image in the user's image cache. */ + struct timespec eol; + + /* Link to the cache used for this image. */ + struct image_cache *cache; + /* Pixmaps of the image. */ Emacs_Pixmap pixmap, mask; @@ -3277,23 +3283,25 @@ #define CENTERED_IMAGE_ASCENT -1 struct image *next, *prev; }; - -/* Cache of images. Each frame has a cache. X frames with the same - x_display_info share their caches. */ - -struct image_cache +struct image_store { - /* Hash table of images. */ - struct image **buckets; - /* Vector mapping image ids to images. */ struct image **images; /* Allocated size of `images'. */ ptrdiff_t size; - /* Number of images in the cache. */ + /* Number of images in the store. */ ptrdiff_t used; +}; + +/* Cache of images. Each frame has a cache. X frames with the same + x_display_info share their caches. */ + +struct image_cache +{ + /* Hash table of images. */ + struct image **buckets; /* Reference count (number of frames sharing this cache). */ ptrdiff_t refcount; @@ -3632,6 +3640,7 @@ #define TRY_WINDOW_IGNORE_FONTS_CHANGE (1 << 1) #ifdef HAVE_WINDOW_SYSTEM extern void clear_image_cache (struct frame *, Lisp_Object); +extern void clear_user_image_cache (struct frame *); extern ptrdiff_t image_bitmap_pixmap (struct frame *, ptrdiff_t); extern void image_reference_bitmap (struct frame *, ptrdiff_t); extern ptrdiff_t image_create_bitmap_from_data (struct frame *, char *, @@ -3652,10 +3661,11 @@ #define TRY_WINDOW_IGNORE_FONTS_CHANGE (1 << 1) #endif extern Lisp_Object image_find_image_file (Lisp_Object); +struct image_store *make_image_store (void); struct image_cache *make_image_cache (void); extern void free_image_cache (struct frame *); void clear_image_caches (Lisp_Object); -void mark_image_cache (struct image_cache *); +void mark_image_store (struct frame *); void image_prune_animation_caches (bool); bool valid_image_p (Lisp_Object); void prepare_image_for_display (struct frame *, struct image *); @@ -3719,6 +3729,7 @@ #define RGB_PIXEL_COLOR COLORREF int lookup_derived_face (struct window *, struct frame *, Lisp_Object, int, bool); #ifdef HAVE_WINDOW_SYSTEM +extern struct image_store *share_image_store (struct frame *f); extern struct image_cache *share_image_cache (struct frame *f); #endif /* HAVE_WINDOW_SYSTEM */ void init_frame_faces (struct frame *); diff --git a/src/frame.h b/src/frame.h index 1d920d1a6bc..6ded69ef14f 100644 --- a/src/frame.h +++ b/src/frame.h @@ -292,6 +292,12 @@ #define EMACS_FRAME_H /* Cache of realized images, which may be shared with other frames. */ struct image_cache *image_cache; + + /* Another image cache that can be managed from Emacs. */ + struct image_cache *user_image_cache; + + /* Vector of cached images. Used by internal and user's cache. */ + struct image_store *image_store; #endif /* HAVE_WINDOW_SYSTEM */ /* Tab-bar item index of the item on which a mouse button was pressed. */ @@ -916,6 +922,8 @@ #define FRAME_KBOARD(f) ((f)->terminal->kboard) /* Return a pointer to the image cache of frame F. */ #define FRAME_IMAGE_CACHE(F) ((F)->image_cache) +#define FRAME_USER_IMAGE_CACHE(F) ((F)->user_image_cache) +#define FRAME_IMAGE_STORE(F) ((F)->image_store) #define XFRAME(p) \ (eassert (FRAMEP (p)), XUNTAG (p, Lisp_Vectorlike, struct frame)) @@ -1668,8 +1676,8 @@ FACE_FROM_ID_OR_NULL (struct frame *f, int id) INLINE struct image * IMAGE_FROM_ID (struct frame *f, int id) { - eassert (0 <= id && id < FRAME_IMAGE_CACHE (f)->used); - return FRAME_IMAGE_CACHE (f)->images[id]; + eassert (0 <= id && id < FRAME_IMAGE_STORE (f)->used); + return FRAME_IMAGE_STORE (f)->images[id]; } /* Value is a pointer to the image with id ID on frame F, or null if @@ -1678,9 +1686,9 @@ IMAGE_FROM_ID (struct frame *f, int id) INLINE struct image * IMAGE_OPT_FROM_ID (struct frame *f, int id) { - int used = FRAME_IMAGE_CACHE (f)->used; + int used = FRAME_IMAGE_STORE (f)->used; eassume (0 <= used); - return 0 <= id && id < used ? FRAME_IMAGE_CACHE (f)->images[id] : NULL; + return 0 <= id && id < used ? FRAME_IMAGE_STORE (f)->images[id] : NULL; } #endif diff --git a/src/image.c b/src/image.c index 34936977a40..7d6ad18bd51 100644 --- a/src/image.c +++ b/src/image.c @@ -1744,6 +1744,7 @@ make_image (Lisp_Object spec, EMACS_UINT hash) { struct image *img = xzalloc (sizeof *img); Lisp_Object file = image_spec_value (spec, QCfile, NULL); + Lisp_Object ttl = image_spec_value (spec, QCttl, NULL); eassert (valid_image_p (spec)); img->dependencies = NILP (file) ? Qnil : list1 (file); @@ -1754,18 +1755,36 @@ make_image (Lisp_Object spec, EMACS_UINT hash) img->ascent = DEFAULT_IMAGE_ASCENT; img->hash = hash; img->corners[BOT_CORNER] = -1; /* Full image */ + if (! NILP (ttl) && FIXNUMP (ttl)) + { + struct timespec now = current_timespec (); + struct timespec ttl_spec; + + /* A negative TTL is used to mean forever. */ + if (XFIXNUM (ttl) < 0) + (img->eol).tv_sec = -1; + else + { + ttl_spec.tv_sec = XFIXNUM (ttl); + ttl_spec.tv_nsec = 0; + img->eol = timespec_add(now, ttl_spec); + } + } + else + (img->eol).tv_sec = (img->eol).tv_nsec = 0; + return img; } -/* Free image IMG which was used on frame F, including its resources. */ +/* Free image IMG from the cache C, including its resources on frame F. */ static void -free_image (struct frame *f, struct image *img) +free_image (struct image_cache *c, struct frame *f, struct image *img) { if (img) { - struct image_cache *c = FRAME_IMAGE_CACHE (f); + struct image_store *s = FRAME_IMAGE_STORE (f); /* Remove IMG from the hash table of its cache. */ if (img->prev) @@ -1776,7 +1795,8 @@ free_image (struct frame *f, struct image *img) if (img->next) img->next->prev = img->prev; - c->images[img->id] = NULL; + /* Free store's slot. */ + s->images[img->id] = NULL; #if !defined USE_CAIRO && defined HAVE_XRENDER /* FRAME_X_DISPLAY (f) could be NULL if this is being called from @@ -2178,7 +2198,20 @@ image_alloc_image_color (struct frame *f, struct image *img, Image Cache ***********************************************************************/ +static void do_cache_image (struct image_cache *, struct frame *, struct image *); static void cache_image (struct frame *f, struct image *img); +static void user_cache_image (struct frame *f, struct image *img); + +struct image_store * +make_image_store (void) +{ + struct image_store *s = xmalloc (sizeof *s); + + s->size = 50; + s->used = 0; + s->images = xmalloc (s->size * sizeof *s->images); + return s; +} /* Return a new, initialized image cache that is allocated from the heap. Call free_image_cache to free an image cache. */ @@ -2188,25 +2221,22 @@ make_image_cache (void) { struct image_cache *c = xmalloc (sizeof *c); - c->size = 50; - c->used = c->refcount = 0; - c->images = xmalloc (c->size * sizeof *c->images); + c->refcount = 0; c->buckets = xzalloc (IMAGE_CACHE_BUCKETS_SIZE * sizeof *c->buckets); /* This value should never be encountered. */ c->scaling_col_width = -1; return c; } -/* Find an image matching SPEC in the cache, and return it. If no +/* Find an image matching SPEC in the cache C, and return it. If no image is found, return NULL. */ static struct image * -search_image_cache (struct frame *f, Lisp_Object spec, EMACS_UINT hash, +search_image_cache (struct image_cache *c, Lisp_Object spec, EMACS_UINT hash, unsigned long foreground, unsigned long background, int font_size, char *font_family, bool ignore_colors) { struct image *img; - struct image_cache *c = FRAME_IMAGE_CACHE (f); - int i = hash % IMAGE_CACHE_BUCKETS_SIZE; + int i; if (!c) return NULL; @@ -2222,6 +2252,7 @@ search_image_cache (struct frame *f, Lisp_Object spec, EMACS_UINT hash, image spec specifies :background. However, the extra memory usage is probably negligible in practice, so we don't bother. */ + i = hash % IMAGE_CACHE_BUCKETS_SIZE; for (img = c->buckets[i]; img; img = img->next) if (img->hash == hash && !NILP (Fequal (img->spec, spec)) @@ -2258,11 +2289,13 @@ filter_image_spec (Lisp_Object spec) spec = XCDR (spec); /* Some animation-related data doesn't affect display, but - breaks the image cache. Filter those out. */ + breaks the image cache. Filter those out. Also filter out + the user's cache time to live. */ if (!(EQ (key, QCanimate_buffer) || EQ (key, QCanimate_tardiness) || EQ (key, QCanimate_position) - || EQ (key, QCanimate_multi_frame_data))) + || EQ (key, QCanimate_multi_frame_data) + || EQ (key, QCttl))) { out = Fcons (value, out); out = Fcons (key, out); @@ -2279,14 +2312,15 @@ uncache_image (struct frame *f, Lisp_Object spec) { struct image *img; EMACS_UINT hash = sxhash (filter_image_spec (spec)); + struct image_cache *c = FRAME_IMAGE_CACHE (f); /* Because the background colors are based on the current face, we can have multiple copies of an image with the same spec. We want to remove them all to ensure the user doesn't see an old version of the image when the face changes. */ - while ((img = search_image_cache (f, spec, hash, 0, 0, 0, NULL, true))) + while ((img = search_image_cache (c, spec, hash, 0, 0, 0, NULL, true))) { - free_image (f, img); + free_image (c, f, img); /* As display glyphs may still be referring to the image ID, we must garbage the frame (Bug#6426). */ SET_FRAME_GARBAGED (f); @@ -2301,6 +2335,7 @@ uncache_image (struct frame *f, Lisp_Object spec) free_image_cache (struct frame *f) { struct image_cache *c = FRAME_IMAGE_CACHE (f); + struct image_store *s = FRAME_IMAGE_STORE (f); ptrdiff_t i; /* This function assumes the caller already verified that the frame's @@ -2309,9 +2344,8 @@ free_image_cache (struct frame *f) /* Cache should not be referenced by any frame when freed. */ eassert (c->refcount == 0); - for (i = 0; i < c->used; ++i) - free_image (f, c->images[i]); - xfree (c->images); + for (i = 0; i < s->used; ++i) + free_image (c, f, s->images[i]); xfree (c->buckets); xfree (c); } @@ -2328,8 +2362,9 @@ free_image_cache (struct frame *f) clear_image_cache (struct frame *f, Lisp_Object filter) { struct image_cache *c = FRAME_IMAGE_CACHE (f); + struct image_store *s = FRAME_IMAGE_STORE (f); - if (c && !f->inhibit_clear_image_cache) + if (c && s && !f->inhibit_clear_image_cache) { ptrdiff_t i, nfreed = 0; @@ -2340,13 +2375,15 @@ clear_image_cache (struct frame *f, Lisp_Object filter) if (!NILP (filter)) { /* Filter image cache. */ - for (i = 0; i < c->used; ++i) + for (i = 0; i < s->used; ++i) { - struct image *img = c->images[i]; - if (img && (EQ (Qt, filter) - || !NILP (Fmember (filter, img->dependencies)))) + struct image *img = s->images[i]; + if (img && (img->cache == c) + && (EQ (Qt, filter) + || !NILP (Fmember (filter, img->dependencies)))) { - free_image (f, img); + free_image (c, f, img); + s->images[i] = NULL; ++nfreed; } } @@ -2358,8 +2395,8 @@ clear_image_cache (struct frame *f, Lisp_Object filter) double delay; ptrdiff_t nimages = 0; - for (i = 0; i < c->used; ++i) - if (c->images[i]) + for (i = 0; i < s->used; ++i) + if (s->images[i] && s->images[i]->cache == c) nimages++; /* If the number of cached images has grown unusually large, @@ -2372,12 +2409,13 @@ clear_image_cache (struct frame *f, Lisp_Object filter) t = current_timespec (); old = timespec_sub (t, dtotimespec (delay)); - for (i = 0; i < c->used; ++i) + for (i = 0; i < s->used; ++i) { - struct image *img = c->images[i]; - if (img && timespec_cmp (img->timestamp, old) < 0) + struct image *img = s->images[i]; + if (img && img->cache == c + && timespec_cmp (img->timestamp, old) < 0) { - free_image (f, img); + free_image (c, f, img); ++nfreed; } } @@ -2405,6 +2443,57 @@ clear_image_cache (struct frame *f, Lisp_Object filter) } } +void +clear_user_image_cache (struct frame *f) +{ + struct image_cache *c = FRAME_USER_IMAGE_CACHE (f); + struct image_store *s = FRAME_IMAGE_STORE (f); + + if (c && s && !f->inhibit_clear_image_cache) + { + ptrdiff_t i, nfreed = 0; + struct timespec t = current_timespec (); + + /* Block input so that we won't be interrupted by a SIGIO + while being in an inconsistent state. */ + block_input (); + + /* Filter image cache based on image's time to live. */ + for (i = 0; i < s->used; ++i) + { + struct image *img = s->images[i]; + if (img && img->cache == c) + { + if (((img->eol).tv_sec >= 0) && timespec_cmp (t, img->eol) > 0) + { + free_image (c, f, img); + ++nfreed; + } + } + } + + /* We may be clearing the image cache because, for example, + Emacs was iconified for a longer period of time. In that + case, current matrices may still contain references to + images freed above. So, clear these matrices. */ + if (nfreed) + { + Lisp_Object tail, frame; + + FOR_EACH_FRAME (tail, frame) + { + struct frame *fr = XFRAME (frame); + if (FRAME_USER_IMAGE_CACHE (fr) == c) + clear_current_matrices (fr); + } + + windows_or_buffers_changed = 19; + } + + unblock_input (); + } +} + void clear_image_caches (Lisp_Object filter) { @@ -2415,7 +2504,10 @@ clear_image_caches (Lisp_Object filter) Lisp_Object tail, frame; FOR_EACH_FRAME (tail, frame) if (FRAME_WINDOW_P (XFRAME (frame))) - clear_image_cache (XFRAME (frame), filter); + { + clear_image_cache (XFRAME (frame), filter); + clear_user_image_cache (XFRAME (frame)); + } } DEFUN ("clear-image-cache", Fclear_image_cache, Sclear_image_cache, @@ -2444,7 +2536,11 @@ DEFUN ("clear-image-cache", Fclear_image_cache, Sclear_image_cache, if (! (NILP (filter) || FRAMEP (filter))) clear_image_caches (filter); else - clear_image_cache (decode_window_system_frame (filter), Qt); + { + struct frame *decoded_frame = decode_window_system_frame (filter); + clear_image_cache (decoded_frame, Qt); + clear_user_image_cache (decoded_frame); + } /* Also clear the animation caches. */ image_prune_animation_caches (true); @@ -2501,17 +2597,18 @@ image_size_in_bytes (struct image *img) } static size_t -image_frame_cache_size (struct frame *f) +image_frame_cache_size (struct image_cache *c, struct frame *f) { - struct image_cache *c = FRAME_IMAGE_CACHE (f); if (!c) return 0; + struct image_store *s = FRAME_IMAGE_STORE (f); size_t total = 0; - for (ptrdiff_t i = 0; i < c->used; ++i) + for (ptrdiff_t i = 0; i < s->used; ++i) { - struct image *img = c->images[i]; - total += img ? image_size_in_bytes (img) : 0; + struct image *img = s->images[i]; + if (img && img->cache == c) + total += image_size_in_bytes (img); } return total; } @@ -3495,6 +3592,8 @@ lookup_image (struct frame *f, Lisp_Object spec, int face_id) unsigned long background = face->background; int font_size = face->font->pixel_size; char *font_family = SSDATA (face->lface[LFACE_FAMILY_INDEX]); + struct image_cache *c; + Lisp_Object ttl = image_spec_value (spec, QCttl, NULL); /* F must be a window-system frame, and SPEC must be a valid image specification. */ @@ -3503,11 +3602,17 @@ lookup_image (struct frame *f, Lisp_Object spec, int face_id) /* Look up SPEC in the hash table of the image cache. */ hash = sxhash (filter_image_spec (spec)); - img = search_image_cache (f, spec, hash, foreground, background, + if (NILP (ttl)) + c = FRAME_IMAGE_CACHE (f); + else /* SPEC as a ttl so lookup into the user's cache. */ + c = FRAME_USER_IMAGE_CACHE (f); + + img = search_image_cache (c, spec, hash, foreground, background, font_size, font_family, false); + if (img && img->load_failed_p) { - free_image (f, img); + free_image (c, f, img); img = NULL; } @@ -3516,7 +3621,12 @@ lookup_image (struct frame *f, Lisp_Object spec, int face_id) { block_input (); img = make_image (spec, hash); - cache_image (f, img); + /* If image's end of life is set store it in the user's image + cache instead. */ + if ((img->eol).tv_sec != 0) + user_cache_image (f, img); + else + cache_image (f, img); img->face_foreground = foreground; img->face_background = background; img->face_font_size = font_size; @@ -3608,6 +3718,37 @@ lookup_image (struct frame *f, Lisp_Object spec, int face_id) return img->id; } +void +do_cache_image (struct image_cache *c, struct frame *f, + struct image *img) +{ + struct image_store *s = FRAME_IMAGE_STORE (f); + ptrdiff_t i; + + /* Find a free slot in the store. */ + for (i = 0; i < s->used; ++i) + if (s->images[i] == NULL) + break; + + /* If no free slot found, maybe enlarge s->images. */ + if (i == s->used && s->used == s->size) + s->images = xpalloc (s->images, &s->size, 1, -1, sizeof *s->images); + + /* Add IMG to s->images, and assign IMG an id. */ + s->images[i] = img; + img->id = i; + if (i == s->used) + ++s->used; + + /* Add IMG to the cache's hash table. */ + i = img->hash % IMAGE_CACHE_BUCKETS_SIZE; + img->next = c->buckets[i]; + if (img->next) + img->next->prev = img; + img->prev = NULL; + c->buckets[i] = img; + img->cache = c; +} /* Cache image IMG in the image cache of frame F. */ @@ -3615,7 +3756,9 @@ lookup_image (struct frame *f, Lisp_Object spec, int face_id) cache_image (struct frame *f, struct image *img) { struct image_cache *c = FRAME_IMAGE_CACHE (f); - ptrdiff_t i; + + if (!FRAME_IMAGE_STORE (f)) + FRAME_IMAGE_STORE (f) = share_image_store (f); if (!c) { @@ -3623,28 +3766,24 @@ cache_image (struct frame *f, struct image *img) c->refcount++; } - /* Find a free slot in c->images. */ - for (i = 0; i < c->used; ++i) - if (c->images[i] == NULL) - break; + do_cache_image (c, f, img); +} - /* If no free slot found, maybe enlarge c->images. */ - if (i == c->used && c->used == c->size) - c->images = xpalloc (c->images, &c->size, 1, -1, sizeof *c->images); +static void +user_cache_image (struct frame *f, struct image *img) +{ + struct image_cache *c = FRAME_USER_IMAGE_CACHE (f); - /* Add IMG to c->images, and assign IMG an id. */ - c->images[i] = img; - img->id = i; - if (i == c->used) - ++c->used; + if (!FRAME_IMAGE_STORE (f)) + FRAME_IMAGE_STORE (f) = share_image_store (f); - /* Add IMG to the cache's hash table. */ - i = img->hash % IMAGE_CACHE_BUCKETS_SIZE; - img->next = c->buckets[i]; - if (img->next) - img->next->prev = img; - img->prev = NULL; - c->buckets[i] = img; + if (!c) + { + c = FRAME_USER_IMAGE_CACHE (f) = make_image_cache (); + c->refcount++; + } + + do_cache_image (c, f, img); } @@ -3762,14 +3901,16 @@ mark_image (struct image *img) void -mark_image_cache (struct image_cache *c) +mark_image_store (struct frame *f) { - if (c) + struct image_store *s = FRAME_IMAGE_STORE (f); + + if (s) { ptrdiff_t i; - for (i = 0; i < c->used; ++i) - if (c->images[i]) - mark_image (c->images[i]); + for (i = 0; i < s->used; ++i) + if (s->images[i]) + mark_image (s->images[i]); } #if defined HAVE_WEBP || defined HAVE_GIF @@ -12647,23 +12788,23 @@ gs_load (struct frame *f, struct image *img) void x_kill_gs_process (Pixmap pixmap, struct frame *f) { - struct image_cache *c = FRAME_IMAGE_CACHE (f); + struct image_store *s = FRAME_IMAGE_STORE (f); ptrdiff_t i; struct image *img; /* Find the image containing PIXMAP. */ - for (i = 0; i < c->used; ++i) - if (c->images[i]->pixmap == pixmap) + for (i = 0; i < s->used; ++i) + if (s->images[i]->pixmap == pixmap) break; /* Should someone in between have cleared the image cache, for instance, give up. */ - if (i == c->used) + if (i == s->used) return; /* Kill the GS process. We should have found PIXMAP in the image cache and its image should contain a process object. */ - img = c->images[i]; + img = s->images[i]; eassert (PROCESSP (img->lisp_data)); Fkill_process (img->lisp_data, Qnil); img->lisp_data = Qnil; @@ -12793,11 +12934,14 @@ DEFUN ("image-cache-size", Fimage_cache_size, Simage_cache_size, 0, 0, 0, { Lisp_Object tail, frame; size_t total = 0; + struct frame *f; FOR_EACH_FRAME (tail, frame) - if (FRAME_WINDOW_P (XFRAME (frame))) - total += image_frame_cache_size (XFRAME (frame)); - + { + f = XFRAME (frame); + if (FRAME_WINDOW_P (f)) + total += image_frame_cache_size (FRAME_IMAGE_CACHE (f), f); + } #if defined (HAVE_WEBP) || defined (HAVE_GIF) struct anim_cache *pcache = anim_cache; while (pcache) @@ -12810,6 +12954,24 @@ DEFUN ("image-cache-size", Fimage_cache_size, Simage_cache_size, 0, 0, 0, return make_int (total); } +DEFUN ("user-image-cache-size", Fuser_image_cache_size, Suser_image_cache_size, 0, 0, 0, + doc: /* Return the size of the user's image cache. */) + (void) +{ + Lisp_Object tail, frame; + size_t total = 0; + struct frame *f; + + FOR_EACH_FRAME (tail, frame) + { + f = XFRAME (frame); + if (FRAME_WINDOW_P (f)) + total += image_frame_cache_size (FRAME_USER_IMAGE_CACHE (f), f); + } + + return make_int (total); +} + DEFUN ("init-image-library", Finit_image_library, Sinit_image_library, 1, 1, 0, doc: /* Initialize image library implementing image type TYPE. @@ -12979,6 +13141,7 @@ syms_of_image (void) DEFSYM (QCcolor_adjustment, ":color-adjustment"); DEFSYM (QCmask, ":mask"); DEFSYM (QCflip, ":flip"); + DEFSYM (QCttl, ":ttl"); /* Other symbols. */ DEFSYM (Qlaplace, "laplace"); @@ -13142,6 +13305,7 @@ syms_of_image (void) defsubr (&Simage_mask_p); defsubr (&Simage_metadata); defsubr (&Simage_cache_size); + defsubr (&Suser_image_cache_size); defsubr (&Simagep); #ifdef GLYPH_DEBUG diff --git a/src/xfaces.c b/src/xfaces.c index e248279e9b7..bea592fe7a8 100644 --- a/src/xfaces.c +++ b/src/xfaces.c @@ -636,6 +636,25 @@ x_free_gc (struct frame *f, struct android_gc *gc) #ifdef HAVE_WINDOW_SYSTEM +struct image_store * +share_image_store (struct frame *f) +{ + Lisp_Object tail, frame; + struct image_store *store; + + FOR_EACH_FRAME (tail, frame) + { + struct frame *x = XFRAME (frame); + + if (FRAME_TERMINAL (x) == FRAME_TERMINAL (f) + && FRAME_IMAGE_STORE (x)) + return FRAME_IMAGE_STORE (x); + } + + store = make_image_store (); + return store; +} + /* Find an existing image cache registered for a frame on F's display and with a `scaling_col_width' of F's FRAME_COLUMN_WIDTH, or, in the absence of an eligible image cache, allocate an image cache with the -- 2.46.2