all messages for Emacs-related lists mirrored at yhetil.org
 help / color / mirror / code / Atom feed
From: Tim Ruffing <dev@real-or-random.org>
To: Eli Zaretskii <eliz@gnu.org>, Tim Ruffing <dev@real-or-random.org>
Cc: 73752@debbugs.gnu.org, xuan@xlk.me,
	mituharu@math.s.chiba-u.ac.jp, visuweshm@gmail.com
Subject: bug#73752: 29.4; Ligatures are randomly rendered with extra spaces
Date: Thu, 07 Nov 2024 03:12:19 +0100	[thread overview]
Message-ID: <d10abd0eeaa7112c94333a9e7f1e1a4c3d974875.camel@timruffing.de> (raw)
In-Reply-To: <86ikt0se1l.fsf@gnu.org>

[-- Attachment #1: Type: text/plain, Size: 2648 bytes --]

On Wed, 2024-11-06 at 15:11 +0200, Eli Zaretskii wrote:
> 
> 
> Thanks.  Can you try calling hb_font_destroy in
> ftcrhbfont_end_hb_font
> and setting ftcrfont_info->hb_font to NULL right after that?  If that
> solves the problem, we could at least install this for now, until we
> have a better solution (if one exists).

Yes, that appears to work. And I don't think there's an obvious better
solution. See attached patch.

And I think I understand the root cause now:

What the cairo backend persists is a cairo_font_face_t, from which it
will obtain an FT_Face on demand using cairo_ft_scaled_font_lock_face
(and cairo_ft_scaled_font_unlock_face), e.g., to pass it to
hb_ft_font_create_referenced to create a hb_font_t. The lock/unlock
interface implies that we should not keep a reference to the FT_Face in
hb_font_t after cairo_ft_scaled_font_unlock_face, and so we should not
persist the hb_font_t.

Here's an unconfirmed theory what actually happens under the hood: 

Cairo internally caches an unscaled FT_Face and scales it on demand to
a specific size. That means that cairo_ft_scaled_font_lock_face will
scale the one FT_Face to which we still hold possibly multiple
references (one for each size) inside the hb_font_t object. Since we
call cairo_ft_scaled_font_lock_face every time before accessing the
hb_font_t, we happen to see the scaled version with the correct size
every time. So far we were lucky.

But Cairo's cache is limited to (currently) 10 elements [1]. As a
result, if many fonts are used, Cairo will evict a random cached
FT_Face, and later create a new one if requested via 
cairo_ft_scaled_font_lock_face. In that case, we hold a reference to
the outdated FT_Face, which won't be scaled any longer by
cairo_ft_scaled_font_lock_face, and thus we pass a face with the wrong
size to harfbuzz. 

The caching logic also explains why removing the unlock call makes the
problem disappear: Cairo won't evict the FT_Face of locked
cairo_scaled_font_t objects, even if this means going over 10.

This suggests that removing the cairo_ft_scaled_font_unlock_face call
is another fix, probably slightly more efficient, but also somewhat
frivolous. The docs explicitly say this: "Since the FT_Face object can
be shared between multiple cairo_scaled_font_t objects, you must not
lock any other font objects until you unlock this one." Though, if you
look at the implementation, they release the mutex explicitly, so there
can't be any deadlocks in the end. (Not suggesting we should rely on
this...)

[1] See MAX_OPEN_FACES in src/cairo-ft-font.c in the Cairo source code.


[-- Attachment #2: 0001-Fix-additional-spacing-in-compositions-Cairo-backend.patch --]
[-- Type: text/x-patch, Size: 1225 bytes --]

From b52b47453665fbc088dcd570ffb79ac755dfbe8f Mon Sep 17 00:00:00 2001
From: Tim Ruffing <dev@real-or-random.org>
Date: Thu, 7 Nov 2024 03:09:09 +0100
Subject: [PATCH] Fix additional spacing in compositions (Cairo backend)

* src/ftcrfont.c (ftcrhbfont_end_hb_font): Don't persist the result of
cairo_ft_scaled_font_lock_face in violation of the API contract.
(Bug#73752)
---
 src/ftcrfont.c | 7 +++++++
 1 file changed, 7 insertions(+)

diff --git a/src/ftcrfont.c b/src/ftcrfont.c
index 3700154e44a..ee111d18763 100644
--- a/src/ftcrfont.c
+++ b/src/ftcrfont.c
@@ -708,6 +708,13 @@ ftcrhbfont_end_hb_font (struct font *font, hb_font_t *hb_font)
   struct font_info *ftcrfont_info = (struct font_info *) font;
   cairo_scaled_font_t *scaled_font = ftcrfont_info->cr_scaled_font;
 
+  eassert (hb_font == ftcrfont_info->hb_font);
+  /* ftcrfont_info->hb_font holds a reference to the FT_Face returned by
+     cairo_ft_scaled_font_lock_face. Keeping it around after the
+     matching unlock call would violate the API contract (Bug#73752). */
+  hb_font_destroy (ftcrfont_info->hb_font);
+  ftcrfont_info->hb_font = NULL;
+
   cairo_ft_scaled_font_unlock_face (scaled_font);
   ftcrfont_info->ft_size = NULL;
 }
-- 
2.47.0


  reply	other threads:[~2024-11-07  2:12 UTC|newest]

Thread overview: 90+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2024-10-11 16:18 bug#73752: 29.4; Ligatures are randomly rendered with extra spaces xuan
2024-10-12  8:02 ` Eli Zaretskii
2024-10-12 16:09   ` Yixuan Chen
2024-10-27 10:21     ` Eli Zaretskii
2024-10-27 16:19       ` Visuwesh
2024-10-27 17:19         ` Eli Zaretskii
2024-10-27 17:27           ` Eli Zaretskii
2024-10-27 17:39             ` Yixuan Chen
2024-10-27 17:43               ` Eli Zaretskii
2024-10-27 17:46                 ` Yixuan Chen
2024-10-27 19:14                   ` Eli Zaretskii
2024-10-27 19:36                     ` Yixuan Chen
2024-10-27 19:44                       ` Eli Zaretskii
2024-10-27 19:47                         ` Yixuan Chen
2024-10-27 20:11                           ` Eli Zaretskii
2024-10-27 19:41                     ` Yixuan Chen
2024-10-27 20:07                       ` Eli Zaretskii
2024-10-27 20:32                         ` Yixuan Chen
2024-10-28 14:25                           ` Eli Zaretskii
2024-10-28 14:44                             ` Yixuan Chen
2024-10-28 14:47                               ` Yixuan Chen
2024-10-28 15:05                               ` Eli Zaretskii
2024-10-28 15:20                                 ` Yixuan Chen
2024-10-28 17:19                                   ` Eli Zaretskii
2024-10-28 17:26                                     ` Eli Zaretskii
2024-10-28 17:28                                     ` Yixuan Chen
2024-10-28 18:41                                       ` Eli Zaretskii
2024-10-28  4:26             ` Visuwesh
2024-10-28 14:59               ` Eli Zaretskii
2024-10-28 15:24                 ` Yixuan Chen
2024-10-28 16:18                 ` Visuwesh
2024-10-28 17:13                   ` Eli Zaretskii
2024-10-29 10:59                     ` Visuwesh
2024-10-29 13:04                       ` Eli Zaretskii
2024-10-29 13:54                         ` Visuwesh
2024-10-29 14:00                           ` Visuwesh
2024-10-29 15:38                           ` Eli Zaretskii
2024-10-29 16:46                             ` Visuwesh
2024-10-29 17:45                               ` Eli Zaretskii
2024-10-30  5:43                                 ` Visuwesh
2024-10-29 16:51                             ` Eli Zaretskii
2024-10-27 17:29           ` Yixuan Chen
2024-10-29 23:14 ` Tim Ruffing
2024-10-30 15:12   ` Eli Zaretskii
2024-10-30 15:45     ` Eli Zaretskii
     [not found]     ` <mvmikt9zkcq.fsf@suse.de>
2024-10-30 15:47       ` Eli Zaretskii
2024-10-30 17:34         ` Tim Ruffing
2024-10-30 17:46           ` Eli Zaretskii
2024-10-30 18:00             ` Tim Ruffing
2024-10-30 18:57               ` Eli Zaretskii
2024-10-31  1:39                 ` Tim Ruffing
2024-10-31  2:36                   ` Yixuan Chen
2024-10-31  2:46                     ` Yixuan Chen
2024-10-31  7:44                       ` Eli Zaretskii
2024-10-31  9:42                   ` Eli Zaretskii
2024-11-01 17:05                     ` Eli Zaretskii
2024-11-02  3:34                       ` Tim Ruffing
2024-11-02  9:52                         ` Eli Zaretskii
2024-11-02 10:39                           ` Visuwesh
2024-11-02 12:07                             ` Eli Zaretskii
2024-11-02 13:29                               ` Visuwesh
2024-11-02 16:47                                 ` Eli Zaretskii
2024-11-02 17:04                                   ` Visuwesh
2024-11-02 17:18                                     ` Eli Zaretskii
2024-11-02 17:31                                       ` Visuwesh
2024-11-02 17:34                                         ` Eli Zaretskii
2024-11-02 17:39                                           ` Visuwesh
2024-11-02 17:44                                             ` Eli Zaretskii
2024-11-02 17:54                                               ` Visuwesh
2024-11-02 18:02                                                 ` Visuwesh
2024-11-02 18:27                                                   ` Eli Zaretskii
2024-11-04  0:11                                                     ` Tim Ruffing
2024-11-04 17:45                                                       ` Eli Zaretskii
2024-11-04 18:02                                                         ` Visuwesh
2024-11-04 23:33                                                         ` Tim Ruffing
2024-11-04 23:47                                                           ` Tim Ruffing
2024-11-06 12:02                                                           ` Tim Ruffing
2024-11-06 13:11                                                             ` Eli Zaretskii
2024-11-07  2:12                                                               ` Tim Ruffing [this message]
2024-11-07  7:05                                                                 ` Eli Zaretskii
2024-11-07 13:45                                                                   ` Visuwesh
2024-11-07 14:40                                                                     ` Eli Zaretskii
2024-11-07 15:13                                                                       ` Visuwesh
2024-11-07 15:49                                                                         ` Eli Zaretskii
2024-11-07 16:00                                                                           ` Visuwesh
2024-11-08  8:08                                                                       ` Eli Zaretskii
2024-11-06 14:50                                                         ` Visuwesh
2024-11-02 10:32                       ` Visuwesh
2024-10-31  8:12             ` Visuwesh
2024-10-31  9:43               ` Eli Zaretskii

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=d10abd0eeaa7112c94333a9e7f1e1a4c3d974875.camel@timruffing.de \
    --to=dev@real-or-random.org \
    --cc=73752@debbugs.gnu.org \
    --cc=eliz@gnu.org \
    --cc=mituharu@math.s.chiba-u.ac.jp \
    --cc=visuweshm@gmail.com \
    --cc=xuan@xlk.me \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
Code repositories for project(s) associated with this external index

	https://git.savannah.gnu.org/cgit/emacs.git
	https://git.savannah.gnu.org/cgit/emacs/org-mode.git

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.