From 219bfea874b237caa763a31f3e9261733fab8e68 Mon Sep 17 00:00:00 2001 From: Po Lu Date: Wed, 29 Mar 2023 20:14:43 +0800 Subject: [PATCH] Improve rules for enumerating user fonts * doc/emacs/android.texi (Android Fonts): Document distortable font replacement rules. * src/sfntfont.c (sfnt_replace_fonts_p): New function. (sfnt_enum_font_1): Call it. --- doc/emacs/android.texi | 25 ++++++++++++++--- src/sfntfont.c | 64 ++++++++++++++++++++++++++++++++++++++++-- 2 files changed, 82 insertions(+), 7 deletions(-) diff --git a/doc/emacs/android.texi b/doc/emacs/android.texi index c92700980de..97f72e98cee 100644 --- a/doc/emacs/android.texi +++ b/doc/emacs/android.texi @@ -534,10 +534,11 @@ menu in the system settings, but this procedure may vary by device. named @code{sfnt-android} and @code{android}. Upon startup, Emacs enumerates all the TrueType format fonts in the -directory @file{/system/fonts}, and the @file{fonts} directory inside -the Emacs home directory. Emacs assumes there will always be a font -named ``Droid Sans Mono'', and then defaults to using this font. -These fonts are then displayed by the @code{sfnt-android} font driver. +directory @file{/system/fonts}, and the @file{fonts} directory +(@dfn{user fonts directory}) inside the Emacs home directory. Emacs +assumes there will always be a font named ``Droid Sans Mono'', and +then defaults to using this font. These fonts are then displayed by +the @code{sfnt-android} font driver. When running on Android, Emacs currently lacks support for OpenType fonts. This means that only a subset of the fonts installed on the @@ -551,6 +552,22 @@ metrics provided by the Android platform. In that case, Emacs uses the ``Monospace'' typeface configured on your system; this should always be Droid Sans Mono. +@cindex TrueType GX fonts, android +@cindex distortable fonts, android + + Like on X systems, Emacs supports distortable fonts under Android. +These fonts (also termed ``TrueType GX fonts'', ``variable fonts'', +and ``multiple master fonts'') provide multiple different styles +(``Bold'', ``Italic'', etc) using a single font file. + +When a user-installed distortable font is found, each font that a +previously discovered font provided will no longer be used. In +addition, any previously specified distortable fonts with the same +family name are also removed. When a conventional font is found, any +previous conventional font with the same style and family will be +removed; distortable fonts with the same family will no longer be +used to provide that style. + @node Android Troubleshooting @section What to do when something goes wrong on Android @cindex troubleshooting, android diff --git a/src/sfntfont.c b/src/sfntfont.c index 99ba6bb1001..c9d48f640af 100644 --- a/src/sfntfont.c +++ b/src/sfntfont.c @@ -827,6 +827,63 @@ sfnt_grok_registry (int fd, struct sfnt_font_desc *desc, xfree (subtables); } +/* Return whether or not the font description PREV conflicts with the + newer font description DESC, and should be removed from the list of + system fonts. + + If PREV is a variable font, potentially adjust its list of + instances. */ + +static bool +sfnt_replace_fonts_p (struct sfnt_font_desc *prev, + struct sfnt_font_desc *desc) +{ + int i, width, weight, slant, count_instance; + Lisp_Object tem; + bool family_equal_p; + + family_equal_p = !NILP (Fstring_equal (prev->family, + desc->family)); + + if ((!NILP (desc->instances) + || !NILP (Fstring_equal (prev->style, desc->style))) + && family_equal_p) + return true; + + if (NILP (prev->instances) || !family_equal_p) + return false; + + /* Look through instances in PREV to see if DESC provides the same + thing. */ + + count_instance = 0; + for (i = 0; i < ASIZE (prev->instances); ++i) + { + tem = AREF (prev->instances, i); + + if (NILP (tem)) + continue; + + width = XFIXNUM (AREF (tem, 2)); + weight = XFIXNUM (AREF (tem, 3)); + slant = XFIXNUM (AREF (tem, 4)); + + if (desc->width == width + && desc->weight == weight + && desc->slant == slant) + { + /* Remove this instance. */ + ASET (prev->instances, i, Qnil); + continue; + } + + count_instance++; + } + + /* Remove this desc if there are no more instances. */ + return count_instance < 1; +} + /* Enumerate the offset subtable SUBTABLES in the file FD, whose file name is FILE. OFFSET should be the offset of the subtable within the font file, and is recorded for future use. Value is 1 upon @@ -959,14 +1016,15 @@ sfnt_enum_font_1 (int fd, const char *file, desc->next = system_fonts; system_fonts = desc; - /* Remove any fonts which have the same style as this one. */ + /* Remove any fonts which have the same style as this one. For + distortable fonts, only remove overlapping styles, unless this is + also a distortable font. */ next = &system_fonts->next; prev = *next; for (; *next; prev = *next) { - if (!NILP (Fstring_equal (prev->style, desc->style)) - && !NILP (Fstring_equal (prev->family, desc->family))) + if (sfnt_replace_fonts_p (prev, desc)) { *next = prev->next; xfree (prev); -- 2.39.2