1
0
mirror of https://git.savannah.gnu.org/git/emacs.git synced 2024-11-21 06:55:39 +00:00

Correctly cache images when frames vary in their font metrics

* src/alloc.c (mark_frame): Mark this frame's image cache, if it
exist.
(mark_terminals): Cease marking T->image_cache.

* src/androidfns.c (unwind_create_frame, Fx_create_frame)
(android_create_tip_frame):

* src/haikufns.c (unwind_create_frame, haiku_create_frame)
(haiku_create_tip_frame):

* src/nsfns.m (unwind_create_frame):

* src/pgtkfns.c (unwind_create_frame, Fx_create_frame)
(x_create_tip_frame):

* src/xfns.c (unwind_create_frame, Fx_create_frame)
(x_create_tip_frame):

* src/w32fns.c (unwind_create_frame, Fx_create_frame)
(w32_create_tip_frame): Remove adjustments of the frame image
cache's reference count rendered redundant by the assignment of
image caches to individual frames rather than terminals.

* src/dispextern.h (struct image_cache) <scaling_col_width>: New
field.

* src/frame.c (gui_set_font): In lieu of clearing F's image
cache unconditionally, establish whether the column width as
considered by compute_image_size has changed, and if so, adjust
or reassign the frame's image cache.
(make_frame): Clear F->image_cache.

* src/frame.h (struct frame) <image_cache>: New field.
(FRAME_IMAGE_CACHE): Return F->image_cache.

* src/image.c (make_image_cache): Clear C->scaling_col_width.
(cache_image): Adjust to new means of assigning image caches to
frames.

* src/termhooks.h (struct terminal) <image_cache>: Delete field.

* src/xfaces.c (init_frame_faces): Do image cache assignment
with all new frames.
This commit is contained in:
Po Lu 2024-06-20 17:03:36 +08:00
parent 374f4235d5
commit cebca072c3
13 changed files with 92 additions and 160 deletions

View File

@ -7055,6 +7055,13 @@ mark_frame (struct Lisp_Vector *ptr)
for (tem = f->conversion.actions; tem; tem = tem->next)
mark_object (tem->data);
#endif
#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));
#endif /* HAVE_WINDOW_SYSTEM */
}
static void
@ -7515,12 +7522,6 @@ mark_terminals (void)
for (t = terminal_list; t; t = t->next_terminal)
{
eassert (t->name != NULL);
#ifdef HAVE_WINDOW_SYSTEM
/* If a terminal object is reachable from a stacpro'ed object,
it might have been marked already. Make sure the image cache
gets marked. */
mark_image_cache (t->image_cache);
#endif /* HAVE_WINDOW_SYSTEM */
if (!vectorlike_marked_p (&t->header))
mark_vectorlike (&t->header);
}

View File

@ -32,9 +32,6 @@ along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */
#ifndef ANDROID_STUBIFY
/* Some kind of reference count for the image cache. */
static ptrdiff_t image_cache_refcount;
/* The frame of the currently visible tooltip, or nil if none. */
static Lisp_Object tip_frame;
@ -654,17 +651,6 @@ unwind_create_frame (Lisp_Object frame)
/* If frame is ``official'', nothing to do. */
if (NILP (Fmemq (frame, Vframe_list)))
{
/* If the frame's image cache refcount is still the same as our
private shadow variable, it means we are unwinding a frame
for which we didn't yet call init_frame_faces, where the
refcount is incremented. Therefore, we increment it here, so
that free_frame_faces, called in x_free_frame_resources
below, will not mistakenly decrement the counter that was not
incremented yet to account for this new frame. */
if (FRAME_IMAGE_CACHE (f) != NULL
&& FRAME_IMAGE_CACHE (f)->refcount == image_cache_refcount)
FRAME_IMAGE_CACHE (f)->refcount++;
android_free_frame_resources (f);
free_glyphs (f);
return Qt;
@ -944,10 +930,6 @@ DEFUN ("x-create-frame", Fx_create_frame, Sx_create_frame,
register_font_driver (&androidfont_driver, f);
register_font_driver (&android_sfntfont_driver, f);
image_cache_refcount = (FRAME_IMAGE_CACHE (f)
? FRAME_IMAGE_CACHE (f)->refcount
: 0);
gui_default_parameter (f, parms, Qfont_backend, Qnil,
"fontBackend", "FontBackend", RES_TYPE_STRING);
@ -2023,9 +2005,6 @@ android_create_tip_frame (struct android_display_info *dpyinfo,
register_font_driver (&androidfont_driver, f);
register_font_driver (&android_sfntfont_driver, f);
image_cache_refcount
= FRAME_IMAGE_CACHE (f) ? FRAME_IMAGE_CACHE (f)->refcount : 0;
gui_default_parameter (f, parms, Qfont_backend, Qnil,
"fontBackend", "FontBackend", RES_TYPE_STRING);

View File

@ -3292,6 +3292,11 @@ struct image_cache
/* Reference count (number of frames sharing this cache). */
ptrdiff_t refcount;
/* Column width by which images whose QCscale property is Qdefault
will be scaled, which is 10 or FRAME_COLUMN_WIDTH of each frame
assigned this image cache, whichever is greater. */
int scaling_col_width;
};
/* Size of bucket vector of image caches. Should be prime. */
@ -3708,6 +3713,9 @@ int smaller_face (struct frame *, int, int);
int face_with_height (struct frame *, int, int);
int lookup_derived_face (struct window *, struct frame *,
Lisp_Object, int, bool);
#ifdef HAVE_WINDOW_SYSTEM
extern struct image_cache *share_image_cache (struct frame *f);
#endif /* HAVE_WINDOW_SYSTEM */
void init_frame_faces (struct frame *);
void free_frame_faces (struct frame *);
void recompute_basic_faces (struct frame *);

View File

@ -983,6 +983,8 @@ make_frame (bool mini_p)
f->tooltip = false;
f->was_invisible = false;
f->child_frame_border_width = -1;
f->face_caches = NULL;
f->image_cache = NULL;
f->last_tab_bar_item = -1;
#ifndef HAVE_EXT_TOOL_BAR
f->last_tool_bar_item = -1;
@ -4732,7 +4734,7 @@ void
gui_set_font (struct frame *f, Lisp_Object arg, Lisp_Object oldval)
{
Lisp_Object font_object;
int fontset = -1;
int fontset = -1, iwidth;
/* Set the frame parameter back to the old value because we may
fail to use ARG as the new parameter value. */
@ -4811,9 +4813,33 @@ gui_set_font (struct frame *f, Lisp_Object arg, Lisp_Object oldval)
/* Recalculate toolbar height. */
f->n_tool_bar_rows = 0;
/* Clean F's image cache of images whose values derive from the font
width. */
clear_image_cache (f, Qauto);
/* Re-initialize F's image cache. Since `set_new_font_hook' might
have changed the frame's column width, by which images are scaled,
it might likewise need to be assigned a different image cache, or
have its existing cache adjusted, if by coincidence it is its sole
user. */
iwidth = max (10, FRAME_COLUMN_WIDTH (f));
if (FRAME_IMAGE_CACHE (f)
&& (iwidth != FRAME_IMAGE_CACHE (f)->scaling_col_width))
{
eassert (FRAME_IMAGE_CACHE (f)->refcount >= 1);
if (FRAME_IMAGE_CACHE (f)->refcount == 1)
{
/* This frame is the only user of this image cache. */
FRAME_IMAGE_CACHE (f)->scaling_col_width = iwidth;
/* Clean F's image cache of images whose values are derived
from the font width. */
clear_image_cache (f, Qauto);
}
else
{
/* Release the current image cache, and reuse or allocate a
new image cache with IWIDTH. */
FRAME_IMAGE_CACHE (f)->refcount--;
FRAME_IMAGE_CACHE (f) = share_image_cache (f);
}
}
/* Ensure we redraw it. */
clear_current_matrices (f);

View File

@ -288,6 +288,12 @@ struct frame
/* Cache of realized faces. */
struct face_cache *face_cache;
#ifdef HAVE_WINDOW_SYSTEM
/* Cache of realized images, which may be shared with other
frames. */
struct image_cache *image_cache;
#endif /* HAVE_WINDOW_SYSTEM */
/* Tab-bar item index of the item on which a mouse button was pressed. */
int last_tab_bar_item;
@ -909,7 +915,7 @@ default_pixels_per_inch_y (void)
#define FRAME_KBOARD(f) ((f)->terminal->kboard)
/* Return a pointer to the image cache of frame F. */
#define FRAME_IMAGE_CACHE(F) ((F)->terminal->image_cache)
#define FRAME_IMAGE_CACHE(F) ((F)->image_cache)
#define XFRAME(p) \
(eassert (FRAMEP (p)), XUNTAG (p, Lisp_Vectorlike, struct frame))

View File

@ -73,9 +73,6 @@ static Lisp_Object tip_last_parms;
static void haiku_explicitly_set_name (struct frame *, Lisp_Object, Lisp_Object);
static void haiku_set_title (struct frame *, Lisp_Object, Lisp_Object);
/* The number of references to an image cache. */
static ptrdiff_t image_cache_refcount;
static Lisp_Object
get_geometry_from_preferences (struct haiku_display_info *dpyinfo,
Lisp_Object parms)
@ -627,29 +624,8 @@ unwind_create_frame (Lisp_Object frame)
/* If frame is ``official'', nothing to do. */
if (NILP (Fmemq (frame, Vframe_list)))
{
#if defined GLYPH_DEBUG && defined ENABLE_CHECKING
struct haiku_display_info *dpyinfo = FRAME_DISPLAY_INFO (f);
#endif
/* If the frame's image cache refcount is still the same as our
private shadow variable, it means we are unwinding a frame
for which we didn't yet call init_frame_faces, where the
refcount is incremented. Therefore, we increment it here, so
that free_frame_faces, called in free_frame_resources later,
will not mistakenly decrement the counter that was not
incremented yet to account for this new frame. */
if (FRAME_IMAGE_CACHE (f) != NULL
&& FRAME_IMAGE_CACHE (f)->refcount == image_cache_refcount)
FRAME_IMAGE_CACHE (f)->refcount++;
haiku_free_frame_resources (f);
free_glyphs (f);
#if defined GLYPH_DEBUG && defined ENABLE_CHECKING
/* Check that reference counts are indeed correct. */
if (dpyinfo->terminal->image_cache)
eassert (dpyinfo->terminal->image_cache->refcount == image_cache_refcount);
#endif
}
}
@ -807,9 +783,6 @@ haiku_create_frame (Lisp_Object parms)
#endif
register_font_driver (&haikufont_driver, f);
image_cache_refcount =
FRAME_IMAGE_CACHE (f) ? FRAME_IMAGE_CACHE (f)->refcount : 0;
gui_default_parameter (f, parms, Qfont_backend, Qnil,
"fontBackend", "FontBackend", RES_TYPE_STRING);
@ -1098,9 +1071,6 @@ haiku_create_tip_frame (Lisp_Object parms)
#endif
register_font_driver (&haikufont_driver, f);
image_cache_refcount =
FRAME_IMAGE_CACHE (f) ? FRAME_IMAGE_CACHE (f)->refcount : 0;
gui_default_parameter (f, parms, Qfont_backend, Qnil,
"fontBackend", "FontBackend", RES_TYPE_STRING);

View File

@ -2195,6 +2195,8 @@ make_image_cache (void)
c->used = c->refcount = 0;
c->images = xmalloc (c->size * sizeof *c->images);
c->buckets = xzalloc (IMAGE_CACHE_BUCKETS_SIZE * sizeof *c->buckets);
/* This value should never be encountered. */
c->scaling_col_width = -1;
return c;
}
@ -3620,7 +3622,10 @@ cache_image (struct frame *f, struct image *img)
ptrdiff_t i;
if (!c)
c = FRAME_IMAGE_CACHE (f) = make_image_cache ();
{
c = FRAME_IMAGE_CACHE (f) = share_image_cache (f);
c->refcount++;
}
/* Find a free slot in c->images. */
for (i = 0; i < c->used; ++i)

View File

@ -87,8 +87,6 @@ Updated by Christian Limpach (chris@nice.ch)
static Lisp_Object as_script, *as_result;
static int as_status;
static ptrdiff_t image_cache_refcount;
static struct ns_display_info *ns_display_info_for_name (Lisp_Object);
/* ==========================================================================
@ -1137,29 +1135,8 @@ Turn the input menu (an NSMenu) into a lisp list for tracking on lisp side.
/* If frame is ``official'', nothing to do. */
if (NILP (Fmemq (frame, Vframe_list)))
{
#if defined GLYPH_DEBUG && defined ENABLE_CHECKING
struct ns_display_info *dpyinfo = FRAME_DISPLAY_INFO (f);
#endif
/* If the frame's image cache refcount is still the same as our
private shadow variable, it means we are unwinding a frame
for which we didn't yet call init_frame_faces, where the
refcount is incremented. Therefore, we increment it here, so
that free_frame_faces, called in ns_free_frame_resources
below, will not mistakenly decrement the counter that was not
incremented yet to account for this new frame. */
if (FRAME_IMAGE_CACHE (f) != NULL
&& FRAME_IMAGE_CACHE (f)->refcount == image_cache_refcount)
FRAME_IMAGE_CACHE (f)->refcount++;
ns_free_frame_resources (f);
free_glyphs (f);
#if defined GLYPH_DEBUG && defined ENABLE_CHECKING
/* Check that reference counts are indeed correct. */
eassert (dpyinfo->terminal->image_cache->refcount == image_cache_refcount);
#endif
return Qt;
}

View File

@ -38,8 +38,6 @@ along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */
#include "xsettings.h"
#include "atimer.h"
static ptrdiff_t image_cache_refcount;
static int x_decode_color (struct frame *f, Lisp_Object color_name,
int mono_color);
static struct pgtk_display_info *pgtk_display_info_for_name (Lisp_Object);
@ -1019,17 +1017,6 @@ unwind_create_frame (Lisp_Object frame)
/* If frame is ``official'', nothing to do. */
if (NILP (Fmemq (frame, Vframe_list)))
{
/* If the frame's image cache refcount is still the same as our
private shadow variable, it means we are unwinding a frame
for which we didn't yet call init_frame_faces, where the
refcount is incremented. Therefore, we increment it here, so
that free_frame_faces, called in x_free_frame_resources
below, will not mistakenly decrement the counter that was not
incremented yet to account for this new frame. */
if (FRAME_IMAGE_CACHE (f) != NULL
&& FRAME_IMAGE_CACHE (f)->refcount == image_cache_refcount)
FRAME_IMAGE_CACHE (f)->refcount++;
pgtk_free_frame_resources (f);
free_glyphs (f);
return Qt;
@ -1389,9 +1376,6 @@ This function is an internal primitive--use `make-frame' instead. */ )
register_font_driver (&ftcrhbfont_driver, f);
#endif /* HAVE_HARFBUZZ */
image_cache_refcount =
FRAME_IMAGE_CACHE (f) ? FRAME_IMAGE_CACHE (f)->refcount : 0;
gui_default_parameter (f, parms, Qfont_backend, Qnil,
"fontBackend", "FontBackend", RES_TYPE_STRING);
@ -2746,9 +2730,6 @@ x_create_tip_frame (struct pgtk_display_info *dpyinfo, Lisp_Object parms, struct
register_font_driver (&ftcrhbfont_driver, f);
#endif /* HAVE_HARFBUZZ */
image_cache_refcount =
FRAME_IMAGE_CACHE (f) ? FRAME_IMAGE_CACHE (f)->refcount : 0;
gui_default_parameter (f, parms, Qfont_backend, Qnil,
"fontBackend", "FontBackend", RES_TYPE_STRING);

View File

@ -523,11 +523,6 @@ struct terminal
/* The terminal's keyboard object. */
struct kboard *kboard;
#ifdef HAVE_WINDOW_SYSTEM
/* Cache of images. */
struct image_cache *image_cache;
#endif /* HAVE_WINDOW_SYSTEM */
/* Device-type dependent data shared amongst all frames on this terminal. */
union display_info
{

View File

@ -270,7 +270,6 @@ unsigned int msh_mousewheel = 0;
static unsigned menu_free_timer = 0;
#ifdef GLYPH_DEBUG
static ptrdiff_t image_cache_refcount;
static int dpyinfo_refcount;
#endif
@ -5918,17 +5917,6 @@ unwind_create_frame (Lisp_Object frame)
{
#ifdef GLYPH_DEBUG
struct w32_display_info *dpyinfo = FRAME_DISPLAY_INFO (f);
/* If the frame's image cache refcount is still the same as our
private shadow variable, it means we are unwinding a frame
for which we didn't yet call init_frame_faces, where the
refcount is incremented. Therefore, we increment it here, so
that free_frame_faces, called in w32_free_frame_resources
below, will not mistakenly decrement the counter that was not
incremented yet to account for this new frame. */
if (FRAME_IMAGE_CACHE (f) != NULL
&& FRAME_IMAGE_CACHE (f)->refcount == image_cache_refcount)
FRAME_IMAGE_CACHE (f)->refcount++;
#endif
w32_free_frame_resources (f);
@ -5937,10 +5925,6 @@ unwind_create_frame (Lisp_Object frame)
#ifdef GLYPH_DEBUG
/* Check that reference counts are indeed correct. */
eassert (dpyinfo->reference_count == dpyinfo_refcount);
eassert ((dpyinfo->terminal->image_cache == NULL
&& image_cache_refcount == 0)
|| (dpyinfo->terminal->image_cache != NULL
&& dpyinfo->terminal->image_cache->refcount == image_cache_refcount));
#endif
return Qt;
}
@ -6128,8 +6112,6 @@ DEFUN ("x-create-frame", Fx_create_frame, Sx_create_frame,
record_unwind_protect (do_unwind_create_frame, frame);
#ifdef GLYPH_DEBUG
image_cache_refcount =
FRAME_IMAGE_CACHE (f) ? FRAME_IMAGE_CACHE (f)->refcount : 0;
dpyinfo_refcount = dpyinfo->reference_count;
#endif /* GLYPH_DEBUG */
@ -7222,8 +7204,6 @@ w32_create_tip_frame (struct w32_display_info *dpyinfo, Lisp_Object parms)
f->tooltip = true;
#ifdef GLYPH_DEBUG
image_cache_refcount =
FRAME_IMAGE_CACHE (f) ? FRAME_IMAGE_CACHE (f)->refcount : 0;
dpyinfo_refcount = dpyinfo->reference_count;
#endif /* GLYPH_DEBUG */
FRAME_KBOARD (f) = kb;

View File

@ -634,6 +634,37 @@ x_free_gc (struct frame *f, struct android_gc *gc)
Frames and faces
***********************************************************************/
#ifdef HAVE_WINDOW_SYSTEM
/* 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
same width value. */
struct image_cache *
share_image_cache (struct frame *f)
{
int width = max (10, FRAME_COLUMN_WIDTH (f));
Lisp_Object tail, frame;
struct image_cache *cache;
FOR_EACH_FRAME (tail, frame)
{
struct frame *x = XFRAME (frame);
if (FRAME_TERMINAL (x) == FRAME_TERMINAL (f)
&& FRAME_IMAGE_CACHE (x)
&& FRAME_IMAGE_CACHE (x)->scaling_col_width == width)
return FRAME_IMAGE_CACHE (x);
}
cache = make_image_cache ();
cache->scaling_col_width = width;
return cache;
}
#endif /* HAVE_WINDOW_SYSTEM */
/* Initialize face cache and basic faces for frame F. */
void
@ -644,14 +675,10 @@ init_frame_faces (struct frame *f)
FRAME_FACE_CACHE (f) = make_face_cache (f);
#ifdef HAVE_WINDOW_SYSTEM
/* Make the image cache. */
/* Make or share an image cache. */
if (FRAME_WINDOW_P (f))
{
/* We initialize the image cache when creating the first frame
on a terminal, and not during terminal creation. This way,
`x-open-connection' on a tty won't create an image cache. */
if (FRAME_IMAGE_CACHE (f) == NULL)
FRAME_IMAGE_CACHE (f) = make_image_cache ();
FRAME_IMAGE_CACHE (f) = share_image_cache (f);
++FRAME_IMAGE_CACHE (f)->refcount;
}
#endif /* HAVE_WINDOW_SYSTEM */

View File

@ -127,7 +127,6 @@ extern LWLIB_ID widget_id_tick;
#define MAXREQUEST(dpy) (XMaxRequestSize (dpy))
static ptrdiff_t image_cache_refcount;
#ifdef GLYPH_DEBUG
static int dpyinfo_refcount;
#endif
@ -4754,29 +4753,12 @@ unwind_create_frame (Lisp_Object frame)
/* If frame is ``official'', nothing to do. */
if (NILP (Fmemq (frame, Vframe_list)))
{
#if defined GLYPH_DEBUG && defined ENABLE_CHECKING
struct x_display_info *dpyinfo = FRAME_DISPLAY_INFO (f);
#endif
/* If the frame's image cache refcount is still the same as our
private shadow variable, it means we are unwinding a frame
for which we didn't yet call init_frame_faces, where the
refcount is incremented. Therefore, we increment it here, so
that free_frame_faces, called in x_free_frame_resources
below, will not mistakenly decrement the counter that was not
incremented yet to account for this new frame. */
if (FRAME_IMAGE_CACHE (f) != NULL
&& FRAME_IMAGE_CACHE (f)->refcount == image_cache_refcount)
FRAME_IMAGE_CACHE (f)->refcount++;
x_free_frame_resources (f);
free_glyphs (f);
#if defined GLYPH_DEBUG && defined ENABLE_CHECKING
/* Check that reference counts are indeed correct. */
eassert (dpyinfo->reference_count == dpyinfo_refcount);
eassert (dpyinfo->terminal->image_cache->refcount == image_cache_refcount);
#endif
#endif /* GLYPH_DEBUG && ENABLE_CHECKING */
return Qt;
}
@ -5112,9 +5094,6 @@ This function is an internal primitive--use `make-frame' instead. */)
#endif /* HAVE_FREETYPE */
#endif /* not USE_CAIRO */
register_font_driver (&xfont_driver, f);
image_cache_refcount =
FRAME_IMAGE_CACHE (f) ? FRAME_IMAGE_CACHE (f)->refcount : 0;
#ifdef GLYPH_DEBUG
dpyinfo_refcount = dpyinfo->reference_count;
#endif /* GLYPH_DEBUG */
@ -8484,8 +8463,6 @@ x_create_tip_frame (struct x_display_info *dpyinfo, Lisp_Object parms)
#endif /* not USE_CAIRO */
register_font_driver (&xfont_driver, f);
image_cache_refcount =
FRAME_IMAGE_CACHE (f) ? FRAME_IMAGE_CACHE (f)->refcount : 0;
#ifdef GLYPH_DEBUG
dpyinfo_refcount = dpyinfo->reference_count;
#endif /* GLYPH_DEBUG */