fontconfig: Branch 'main' - 3 commits

GitLab Mirror gitlab-mirror at kemper.freedesktop.org
Thu Jun 5 03:06:14 UTC 2025


 Cargo.lock                       |   12 -
 Cargo.toml                       |    6 
 fc-fontations/meson.build        |   14 -
 fc-fontations/mod.rs             |    7 
 fc-fontations/name_records.rs    |  378 +++++++++++++++++++++++++++++++++++++++
 fc-fontations/names.rs           |   62 +++---
 test/test_fontations_ft_query.py |    4 
 7 files changed, 435 insertions(+), 48 deletions(-)

New commits:
commit e5f3180c61a479961a171840a15d445a3f059f4e
Merge: 685f2ec f57fce6
Author: Akira TAGOH <akira at tagoh.org>
Date:   Thu Jun 5 03:06:11 2025 +0000

    Merge branch 'nameIdFixes' into 'main'
    
    [Fontations] Fix order of name entries
    
    See merge request fontconfig/fontconfig!413

commit f57fce6093bb86c554b8b058a160d2a251a0e75c
Author: Dominik Röttsches <drott at chromium.org>
Date:   Tue May 6 17:54:55 2025 +0300

    [Fontations] Match name id append order to FreeType indexer
    
    Implement equivalent ordering behavior extracted from logic in
    fcfreetype.c. fcfreetype.c orders by platform id, name, encoding, language.
    Then searches in that sorted list to append entries by specific
    platform order and name id order.
    
    Combine this into one sorting order for name ids, which we process
    linearly after sorting by priority.

diff --git a/fc-fontations/meson.build b/fc-fontations/meson.build
index e0285b5..0cdbbd6 100644
--- a/fc-fontations/meson.build
+++ b/fc-fontations/meson.build
@@ -14,6 +14,8 @@ if (fontations.enabled())
       '--raw-line= ',
       '--raw-line=pub mod fcint;',
     ],
+    # FC_NO_MT=1 is added here to reduce required headers in bindings generation.
+    # It does not mean a functional change in multi-threading behavior.
     c_args : ['-DBINDGEN_IGNORE_VISIBILITY=1', '-DFC_NO_MT=1'],
   )
 
@@ -29,6 +31,8 @@ if (fontations.enabled())
       '--raw-line= ',
       '--raw-line=pub use crate::FcCharSet; pub use crate::FcLangSet;',
     ],
+    # FC_NO_MT=1 is added here to reduce required headers in bindings generation.
+    # It does not mean a functional change in multi-threading behavior.
     c_args : ['-DBINDGEN_IGNORE_VISIBILITY=1', '-DFC_NO_MT=1'],
   )
 
diff --git a/fc-fontations/mod.rs b/fc-fontations/mod.rs
index 4fba651..76d1945 100644
--- a/fc-fontations/mod.rs
+++ b/fc-fontations/mod.rs
@@ -28,6 +28,7 @@ mod charset;
 mod foundries;
 mod instance_enumerate;
 mod lang;
+mod name_records;
 mod names;
 mod pattern_bindings;
 
@@ -40,9 +41,9 @@ use names::add_names;
 use fc_fontations_bindgen::{
     fcint::{
         FcFreeTypeLangSet, FC_CAPABILITY_OBJECT, FC_CHARSET_OBJECT, FC_COLOR_OBJECT,
-        FC_DECORATIVE_OBJECT, FC_FILE_OBJECT, FC_FONTFORMAT_OBJECT,
-        FC_FONTVERSION_OBJECT, FC_FONT_HAS_HINT_OBJECT, FC_FONT_WRAPPER_OBJECT, FC_FOUNDRY_OBJECT,
-        FC_LANG_OBJECT, FC_OUTLINE_OBJECT, FC_SCALABLE_OBJECT, FC_SYMBOL_OBJECT,
+        FC_DECORATIVE_OBJECT, FC_FILE_OBJECT, FC_FONTFORMAT_OBJECT, FC_FONTVERSION_OBJECT,
+        FC_FONT_HAS_HINT_OBJECT, FC_FONT_WRAPPER_OBJECT, FC_FOUNDRY_OBJECT, FC_LANG_OBJECT,
+        FC_OUTLINE_OBJECT, FC_SCALABLE_OBJECT, FC_SYMBOL_OBJECT,
     },
     FcFontSet, FcFontSetAdd, FcPattern,
 };
diff --git a/fc-fontations/name_records.rs b/fc-fontations/name_records.rs
new file mode 100644
index 0000000..08cce97
--- /dev/null
+++ b/fc-fontations/name_records.rs
@@ -0,0 +1,378 @@
+/*
+ * fontconfig/fc-fontations/name_records.rs
+ *
+ * Copyright 2025 Google LLC.
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and its
+ * documentation for any purpose is hereby granted without fee, provided that
+ * the above copyright notice appear in all copies and that both that
+ * copyright notice and this permission notice appear in supporting
+ * documentation, and that the name of the author(s) not be used in
+ * advertising or publicity pertaining to distribution of the software without
+ * specific, written prior permission.  The authors make no
+ * representations about the suitability of this software for any purpose.  It
+ * is provided "as is" without express or implied warranty.
+ *
+ * THE AUTHOR(S) DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
+ * EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
+ * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
+ * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+use font_types::NameId;
+use read_fonts::tables::cmap::PlatformId;
+use read_fonts::tables::name::{Name, NameRecord};
+
+// Compare platform_order[] in fcfreetype.c.
+// https://learn.microsoft.com/en-us/typography/opentype/spec/name#platform-encoding-and-language-ids
+const PLATFORM_ORDER: [PlatformId; 4] = [
+    PlatformId::Windows,
+    PlatformId::Unicode,
+    PlatformId::Macintosh,
+    PlatformId::ISO, // deprecated.
+];
+
+// Compare name_order[] in fcfreetype.c.
+const NAME_ID_ORDER: [NameId; 10] = [
+    NameId::WWS_FAMILY_NAME,
+    NameId::TYPOGRAPHIC_FAMILY_NAME,
+    NameId::FAMILY_NAME,
+    NameId::COMPATIBLE_FULL_NAME,
+    NameId::FULL_NAME,
+    NameId::WWS_SUBFAMILY_NAME,
+    NameId::TYPOGRAPHIC_SUBFAMILY_NAME,
+    NameId::SUBFAMILY_NAME,
+    NameId::TRADEMARK,
+    NameId::MANUFACTURER,
+];
+
+pub struct FcSortedNameRecords<'a> {
+    name: &'a Name<'a>,
+    sorted_record_indices: std::vec::IntoIter<u16>,
+}
+
+impl<'a> FcSortedNameRecords<'a> {
+    pub fn new(name: &'a Name) -> Self {
+        let mut sorted_name_id_indices: Vec<u16> = (0..name.name_record().len() as u16).collect();
+        Self::sort_name_records(name, &mut sorted_name_id_indices);
+        Self {
+            name,
+            sorted_record_indices: sorted_name_id_indices.into_iter(),
+        }
+    }
+
+    // In instances of this comparison function, return Greater for an id a that
+    // is higher priorty than id b, Less for one that is lower priority.
+    fn cmp_id_ordered<T>(priorities: &[T], a: &T, b: &T) -> std::cmp::Ordering
+    where
+        T: std::cmp::Ord,
+    {
+        match (
+            priorities.iter().position(|x| *x == *a),
+            priorities.iter().position(|x| *x == *b),
+        ) {
+            (Some(pos_a), Some(pos_b)) => pos_a.cmp(&pos_b).reverse(),
+            (Some(_), None) => std::cmp::Ordering::Greater,
+            (None, Some(_)) => std::cmp::Ordering::Less,
+            (None, None) => a.cmp(b).reverse(),
+        }
+    }
+
+    fn language_cmp_english_first(a: (u16, u16), b: (u16, u16)) -> std::cmp::Ordering {
+        const MS_ENGLISH_US: (u16, u16) = (0x409, 3);
+        const MAC_ENGLISH: (u16, u16) = (0, 1);
+
+        match (a, b) {
+            (MS_ENGLISH_US, MS_ENGLISH_US) | (MAC_ENGLISH, MAC_ENGLISH) => {
+                std::cmp::Ordering::Equal
+            }
+            (MS_ENGLISH_US, _) | (MAC_ENGLISH, _) => std::cmp::Ordering::Greater,
+            (_, MS_ENGLISH_US) | (_, MAC_ENGLISH) => std::cmp::Ordering::Less,
+            _ => a.cmp(&b),
+        }
+    }
+
+    fn sort_name_records(name: &'a Name, indices: &mut [u16]) {
+        indices.sort_by(|a, b| {
+            let name_record_a = name.name_record()[*a as usize];
+            let name_record_b = name.name_record()[*b as usize];
+
+            Self::cmp_id_ordered(
+                &PLATFORM_ORDER,
+                &PlatformId::new(name_record_a.platform_id()),
+                &PlatformId::new(name_record_b.platform_id()),
+            )
+            .then(Self::cmp_id_ordered(
+                &NAME_ID_ORDER,
+                &name_record_a.name_id(),
+                &name_record_b.name_id(),
+            ))
+            .then(
+                name_record_a
+                    .encoding_id()
+                    .cmp(&name_record_b.encoding_id()),
+            )
+            .then(Self::language_cmp_english_first(
+                (name_record_a.language_id(), name_record_a.platform_id()),
+                (name_record_b.language_id(), name_record_b.platform_id()),
+            ))
+        });
+        // Return in descending order, from most important to least important.
+        indices.reverse();
+    }
+}
+
+impl<'a> Iterator for FcSortedNameRecords<'a> {
+    type Item = NameRecord;
+
+    fn next(&mut self) -> Option<Self::Item> {
+        let record_index = self.sorted_record_indices.next()?;
+        Some(self.name.name_record()[record_index as usize])
+    }
+}
+
+#[cfg(test)]
+mod test {
+    use crate::name_records::FcSortedNameRecords;
+    use read_fonts::TableProvider;
+    use std::{env, fs, path::PathBuf};
+
+    fn get_test_font_bytes() -> Option<Vec<u8>> {
+        let base_path_str = env::var("builddir").unwrap_or(String::from("build/"));
+        let file_path = PathBuf::from(base_path_str)
+            .join("testfonts/roboto-flex-fonts/fonts/variable/RobotoFlex[GRAD,XOPQ,XTRA,YOPQ,YTAS,YTDE,YTFI,YTLC,YTUC,opsz,slnt,wdth,wght].ttf");
+
+        let file_contents: Vec<u8> = fs::read(&file_path).ok()?;
+        Some(file_contents)
+    }
+
+    #[test]
+    fn test_sort_name_records() {
+        let font_bytes = get_test_font_bytes().expect("Could not read test font file.");
+        let font = read_fonts::FontRef::new(font_bytes.as_slice()).unwrap();
+        let name_table = font.name().unwrap();
+        let sorted_records = FcSortedNameRecords::new(&name_table);
+        let sorted_platform_ids = sorted_records
+            .map(|entry| {
+                (
+                    entry.platform_id(),
+                    entry.name_id().to_u16(),
+                    entry.encoding_id(),
+                    entry.language_id(),
+                )
+            })
+            .collect::<Vec<_>>();
+        assert_eq!(
+            sorted_platform_ids,
+            [
+                (3, 1, 1, 1033),
+                (3, 4, 1, 1033),
+                (3, 2, 1, 1033),
+                (3, 7, 1, 1033),
+                (3, 8, 1, 1033),
+                (3, 0, 1, 1033),
+                (3, 3, 1, 1033),
+                (3, 5, 1, 1033),
+                (3, 6, 1, 1033),
+                (3, 9, 1, 1033),
+                (3, 11, 1, 1033),
+                (3, 12, 1, 1033),
+                (3, 13, 1, 1033),
+                (3, 14, 1, 1033),
+                (3, 25, 1, 1033),
+                (3, 256, 1, 1033),
+                (3, 257, 1, 1033),
+                (3, 258, 1, 1033),
+                (3, 259, 1, 1033),
+                (3, 260, 1, 1033),
+                (3, 261, 1, 1033),
+                (3, 262, 1, 1033),
+                (3, 263, 1, 1033),
+                (3, 264, 1, 1033),
+                (3, 265, 1, 1033),
+                (3, 266, 1, 1033),
+                (3, 267, 1, 1033),
+                (3, 268, 1, 1033),
+                (3, 269, 1, 1033),
+                (3, 270, 1, 1033),
+                (3, 271, 1, 1033),
+                (3, 272, 1, 1033),
+                (3, 273, 1, 1033),
+                (3, 274, 1, 1033),
+                (3, 275, 1, 1033),
+                (3, 276, 1, 1033),
+                (3, 277, 1, 1033),
+                (3, 278, 1, 1033),
+                (3, 279, 1, 1033),
+                (3, 280, 1, 1033),
+                (3, 281, 1, 1033),
+                (3, 282, 1, 1033),
+                (3, 283, 1, 1033),
+                (3, 284, 1, 1033),
+                (3, 285, 1, 1033),
+                (3, 286, 1, 1033),
+                (3, 287, 1, 1033),
+                (3, 288, 1, 1033),
+                (3, 289, 1, 1033),
+                (3, 290, 1, 1033),
+                (3, 291, 1, 1033),
+                (3, 292, 1, 1033),
+                (3, 293, 1, 1033),
+                (3, 294, 1, 1033),
+                (3, 295, 1, 1033),
+                (3, 296, 1, 1033),
+                (3, 297, 1, 1033),
+                (3, 298, 1, 1033),
+                (3, 299, 1, 1033),
+                (3, 300, 1, 1033),
+                (3, 301, 1, 1033),
+                (3, 302, 1, 1033),
+                (3, 303, 1, 1033),
+                (3, 304, 1, 1033),
+                (3, 305, 1, 1033),
+                (3, 306, 1, 1033),
+                (3, 307, 1, 1033),
+                (3, 308, 1, 1033),
+                (3, 309, 1, 1033),
+                (3, 310, 1, 1033),
+                (3, 311, 1, 1033),
+                (3, 312, 1, 1033),
+                (3, 313, 1, 1033),
+                (3, 314, 1, 1033),
+                (3, 315, 1, 1033),
+                (3, 316, 1, 1033),
+                (3, 317, 1, 1033),
+                (3, 318, 1, 1033),
+                (3, 319, 1, 1033),
+                (3, 320, 1, 1033),
+                (3, 321, 1, 1033),
+                (3, 322, 1, 1033),
+                (3, 323, 1, 1033),
+                (3, 324, 1, 1033),
+                (3, 325, 1, 1033),
+                (3, 326, 1, 1033),
+                (3, 327, 1, 1033),
+                (3, 328, 1, 1033),
+                (3, 329, 1, 1033),
+                (3, 330, 1, 1033),
+                (3, 331, 1, 1033),
+                (3, 332, 1, 1033),
+                (3, 333, 1, 1033),
+                (3, 334, 1, 1033),
+                (3, 335, 1, 1033),
+                (3, 336, 1, 1033),
+                (3, 337, 1, 1033),
+                (3, 338, 1, 1033),
+                (3, 339, 1, 1033),
+                (3, 340, 1, 1033),
+                (3, 341, 1, 1033),
+                (3, 342, 1, 1033),
+                (3, 343, 1, 1033),
+                (3, 344, 1, 1033),
+                (3, 345, 1, 1033),
+                (3, 346, 1, 1033),
+                (3, 347, 1, 1033),
+                (3, 348, 1, 1033),
+                (3, 349, 1, 1033),
+                (1, 25, 0, 0),
+                (1, 256, 0, 0),
+                (1, 257, 0, 0),
+                (1, 258, 0, 0),
+                (1, 259, 0, 0),
+                (1, 260, 0, 0),
+                (1, 261, 0, 0),
+                (1, 262, 0, 0),
+                (1, 263, 0, 0),
+                (1, 264, 0, 0),
+                (1, 265, 0, 0),
+                (1, 266, 0, 0),
+                (1, 267, 0, 0),
+                (1, 268, 0, 0),
+                (1, 269, 0, 0),
+                (1, 270, 0, 0),
+                (1, 271, 0, 0),
+                (1, 272, 0, 0),
+                (1, 273, 0, 0),
+                (1, 274, 0, 0),
+                (1, 275, 0, 0),
+                (1, 276, 0, 0),
+                (1, 277, 0, 0),
+                (1, 278, 0, 0),
+                (1, 279, 0, 0),
+                (1, 280, 0, 0),
+                (1, 281, 0, 0),
+                (1, 282, 0, 0),
+                (1, 283, 0, 0),
+                (1, 284, 0, 0),
+                (1, 285, 0, 0),
+                (1, 286, 0, 0),
+                (1, 287, 0, 0),
+                (1, 288, 0, 0),
+                (1, 289, 0, 0),
+                (1, 290, 0, 0),
+                (1, 291, 0, 0),
+                (1, 292, 0, 0),
+                (1, 293, 0, 0),
+                (1, 294, 0, 0),
+                (1, 295, 0, 0),
+                (1, 296, 0, 0),
+                (1, 297, 0, 0),
+                (1, 298, 0, 0),
+                (1, 299, 0, 0),
+                (1, 300, 0, 0),
+                (1, 301, 0, 0),
+                (1, 302, 0, 0),
+                (1, 303, 0, 0),
+                (1, 304, 0, 0),
+                (1, 305, 0, 0),
+                (1, 306, 0, 0),
+                (1, 307, 0, 0),
+                (1, 308, 0, 0),
+                (1, 309, 0, 0),
+                (1, 310, 0, 0),
+                (1, 311, 0, 0),
+                (1, 312, 0, 0),
+                (1, 313, 0, 0),
+                (1, 314, 0, 0),
+                (1, 315, 0, 0),
+                (1, 316, 0, 0),
+                (1, 317, 0, 0),
+                (1, 318, 0, 0),
+                (1, 319, 0, 0),
+                (1, 320, 0, 0),
+                (1, 321, 0, 0),
+                (1, 322, 0, 0),
+                (1, 323, 0, 0),
+                (1, 324, 0, 0),
+                (1, 325, 0, 0),
+                (1, 326, 0, 0),
+                (1, 327, 0, 0),
+                (1, 328, 0, 0),
+                (1, 329, 0, 0),
+                (1, 330, 0, 0),
+                (1, 331, 0, 0),
+                (1, 332, 0, 0),
+                (1, 333, 0, 0),
+                (1, 334, 0, 0),
+                (1, 335, 0, 0),
+                (1, 336, 0, 0),
+                (1, 337, 0, 0),
+                (1, 338, 0, 0),
+                (1, 339, 0, 0),
+                (1, 340, 0, 0),
+                (1, 341, 0, 0),
+                (1, 342, 0, 0),
+                (1, 343, 0, 0),
+                (1, 344, 0, 0),
+                (1, 345, 0, 0),
+                (1, 346, 0, 0),
+                (1, 347, 0, 0),
+                (1, 348, 0, 0),
+                (1, 349, 0, 0)
+            ]
+        );
+    }
+}
diff --git a/fc-fontations/names.rs b/fc-fontations/names.rs
index 80fb980..cc70a9c 100644
--- a/fc-fontations/names.rs
+++ b/fc-fontations/names.rs
@@ -1,5 +1,5 @@
 /*
- * fontconfig/fc-fontations/mod.rs
+ * fontconfig/fc-fontations/names.rs
  *
  * Copyright 2025 Google LLC.
  *
@@ -22,6 +22,7 @@
  * PERFORMANCE OF THIS SOFTWARE.
  */
 
+use skrifa::string::LocalizedString;
 use skrifa::{string::StringId, MetadataProvider};
 
 use fc_fontations_bindgen::fcint::{
@@ -29,26 +30,27 @@ use fc_fontations_bindgen::fcint::{
     FC_INVALID_OBJECT, FC_POSTSCRIPT_NAME_OBJECT, FC_STYLELANG_OBJECT, FC_STYLE_OBJECT,
 };
 
-use crate::{FcPatternBuilder, InstanceMode, PatternElement};
-use read_fonts::FontRef;
+use crate::{name_records::FcSortedNameRecords, FcPatternBuilder, InstanceMode, PatternElement};
+use read_fonts::{FontRef, TableProvider};
 use std::ffi::CString;
 
 use std::collections::HashSet;
 
-fn objects_for_id(string_id: StringId) -> (i32, i32) {
+fn object_ids_for_name_id(string_id: StringId) -> Option<(i32, i32)> {
     match string_id {
         StringId::FAMILY_NAME | StringId::WWS_FAMILY_NAME | StringId::TYPOGRAPHIC_FAMILY_NAME => {
-            (FC_FAMILY_OBJECT as i32, FC_FAMILYLANG_OBJECT as i32)
+            Some((FC_FAMILY_OBJECT as i32, FC_FAMILYLANG_OBJECT as i32))
+        }
+        StringId::FULL_NAME => Some((FC_FULLNAME_OBJECT as i32, FC_FULLNAMELANG_OBJECT as i32)),
+        StringId::POSTSCRIPT_NAME => {
+            Some((FC_POSTSCRIPT_NAME_OBJECT as i32, FC_INVALID_OBJECT as i32))
         }
-        StringId::FULL_NAME => (FC_FULLNAME_OBJECT as i32, FC_FULLNAMELANG_OBJECT as i32),
-        StringId::POSTSCRIPT_NAME => (FC_POSTSCRIPT_NAME_OBJECT as i32, FC_INVALID_OBJECT as i32),
         StringId::SUBFAMILY_NAME
         | StringId::WWS_SUBFAMILY_NAME
         | StringId::TYPOGRAPHIC_SUBFAMILY_NAME => {
-            (FC_STYLE_OBJECT as i32, FC_STYLELANG_OBJECT as i32)
+            Some((FC_STYLE_OBJECT as i32, FC_STYLELANG_OBJECT as i32))
         }
-
-        _ => panic!("No equivalent FontConfig objects found for StringId."),
+        _ => None,
     }
 }
 
@@ -123,28 +125,24 @@ pub fn add_names(
     pattern: &mut FcPatternBuilder,
     had_decorative: &mut bool,
 ) {
-    // Order of these is important for matching FreeType. Or we might need to sort these descending to achieve the same result.
-    let string_ids = &[
-        StringId::WWS_FAMILY_NAME,
-        StringId::TYPOGRAPHIC_FAMILY_NAME,
-        StringId::FAMILY_NAME,
-        StringId::FULL_NAME,
-        StringId::POSTSCRIPT_NAME,
-        StringId::TYPOGRAPHIC_SUBFAMILY_NAME,
-        StringId::SUBFAMILY_NAME,
-        StringId::WWS_SUBFAMILY_NAME,
-    ];
-
     let mut already_encountered_names: HashSet<(i32, String)> = HashSet::new();
-    for string_id in string_ids.iter() {
-        let object_ids = objects_for_id(*string_id);
-        for string in font.localized_strings(*string_id) {
-            let name = if string.to_string().is_empty() {
+    let name_table = font.name();
+    if name_table.is_err() {
+        return;
+    }
+    let name_table = name_table.unwrap();
+
+    for name_record in FcSortedNameRecords::new(&name_table) {
+        let string_id = name_record.name_id();
+        if let Some(object_ids) = object_ids_for_name_id(string_id) {
+            let localized = LocalizedString::new(&name_table, &name_record);
+
+            let name = if localized.to_string().is_empty() {
                 None
             } else {
-                CString::new(string.to_string()).ok()
+                CString::new(localized.to_string()).ok()
             };
-            let language = string.language().or(Some("und")).and_then(|lang| {
+            let language = localized.language().or(Some("und")).and_then(|lang| {
                 let lang = if lang.starts_with("zh") {
                     lang
                 } else {
@@ -155,15 +153,17 @@ pub fn add_names(
 
             // Instance postscript name.
             let name = match (instance_mode, string_id) {
-                (InstanceMode::Named(instance), &StringId::POSTSCRIPT_NAME) => {
+                (InstanceMode::Named(instance), StringId::POSTSCRIPT_NAME) => {
                     mangle_postscript_name_for_named_instance(font, instance).or(name)
                 }
-                (InstanceMode::Named(instance), &StringId::SUBFAMILY_NAME) => {
+                (InstanceMode::Named(instance), StringId::SUBFAMILY_NAME) => {
                     mangle_subfamily_name_for_named_instance(font, instance).or(name)
                 }
-                (InstanceMode::Named(instance), &StringId::FULL_NAME) => {
+                (InstanceMode::Named(instance), StringId::FULL_NAME) => {
                     mangle_full_name_for_named_instance(font, instance).or(name)
                 }
+                (InstanceMode::Variable, StringId::FULL_NAME)
+                | (InstanceMode::Variable, StringId::POSTSCRIPT_NAME) => None,
                 _ => name,
             };
 
diff --git a/test/test_fontations_ft_query.py b/test/test_fontations_ft_query.py
index 643f2e9..3b59acf 100644
--- a/test/test_fontations_ft_query.py
+++ b/test/test_fontations_ft_query.py
@@ -55,6 +55,9 @@ def test_fontations_freetype_fcquery_equal(font_file):
     supported_format_entitites = [
         "family",
         "familylang",
+        "fullname",
+        "fullnamelang",
+        "postscriptname",
         "outline",
         "scalable",
         "fontformat",
@@ -71,6 +74,7 @@ def test_fontations_freetype_fcquery_equal(font_file):
         "symbol",
         "fontwrapper",
         "file",
+        "variable",
     ]
     format_string = ":".join(
         "%{" + entity + "}" for entity in supported_format_entitites
commit 305f834802b13ed5aa5b5f879ce6e9fb4f77f222
Author: Dominik Röttsches <drott at chromium.org>
Date:   Wed May 28 12:55:41 2025 +0300

    [Fontations] Roll Fontations, Skrifa to 0.31.3
    
    Includes Fontations change that makes LocalizedString::new()
    public, which is needed for the name id order changes.

diff --git a/Cargo.lock b/Cargo.lock
index 7fd4167..e067695 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -44,9 +44,9 @@ dependencies = [
 
 [[package]]
 name = "font-types"
-version = "0.8.4"
+version = "0.9.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1fa6a5e5a77b5f3f7f9e32879f484aa5b3632ddfbe568a16266c904a6f32cdaf"
+checksum = "02a596f5713680923a2080d86de50fe472fb290693cf0f701187a1c8b36996b7"
 dependencies = [
  "bytemuck",
 ]
@@ -77,9 +77,9 @@ dependencies = [
 
 [[package]]
 name = "read-fonts"
-version = "0.28.0"
+version = "0.29.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "600e807b48ac55bad68a8cb75cc3c7739f139b9248f7e003e01e080f589b5288"
+checksum = "6f96bfbb7df43d34a2b7b8582fcbcb676ba02a763265cb90bc8aabfd62b57d64"
 dependencies = [
  "bytemuck",
  "font-types",
@@ -87,9 +87,9 @@ dependencies = [
 
 [[package]]
 name = "skrifa"
-version = "0.30.0"
+version = "0.31.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "6fa1e5622e4f7b98877e8a19890efddcac1230cec6198bd9de91ec0e00010dc8"
+checksum = "dbeb4ca4399663735553a09dd17ce7e49a0a0203f03b706b39628c4d913a8607"
 dependencies = [
  "bytemuck",
  "read-fonts",
diff --git a/Cargo.toml b/Cargo.toml
index d758e69..15592fa 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -6,9 +6,9 @@ edition = "2021"
 [dependencies]
 fc-fontations-bindgen = { path = "./fc-fontations-bindgen" }
 libc = "0.2.150"
-read-fonts = { version = "0.28", features = [ "experimental_traverse" ]}
-font-types = { version = "0.8", features = ["bytemuck"]}
-skrifa = "0.30"
+read-fonts = { version = "0.29", features = [ "experimental_traverse" ]}
+font-types = { version = "0.9", features = ["bytemuck"]}
+skrifa = "0.31.3"
 bytemuck = { version = "1.19.0" , features = [ 'derive', 'min_const_generics'] }
 bytemuck_derive = "1"
 
diff --git a/fc-fontations/meson.build b/fc-fontations/meson.build
index 2d7af87..e0285b5 100644
--- a/fc-fontations/meson.build
+++ b/fc-fontations/meson.build
@@ -14,7 +14,7 @@ if (fontations.enabled())
       '--raw-line= ',
       '--raw-line=pub mod fcint;',
     ],
-    c_args : ['-DBINDGEN_IGNORE_VISIBILITY=1'],
+    c_args : ['-DBINDGEN_IGNORE_VISIBILITY=1', '-DFC_NO_MT=1'],
   )
 
   generated_fcint = rust.bindgen(
@@ -29,7 +29,7 @@ if (fontations.enabled())
       '--raw-line= ',
       '--raw-line=pub use crate::FcCharSet; pub use crate::FcLangSet;',
     ],
-    c_args : ['-DBINDGEN_IGNORE_VISIBILITY=1'],
+    c_args : ['-DBINDGEN_IGNORE_VISIBILITY=1', '-DFC_NO_MT=1'],
   )
 
   bindgen_lib = static_library(
@@ -50,9 +50,9 @@ if (fontations.enabled())
     link_with: [bindgen_lib, pattern_lib, fontations_query_lib],
     rust_abi: 'c',
     dependencies: [
-      dependency('skrifa-0.30-rs'),
-      dependency('read-fonts-0.28-rs'),
-      dependency('font-types-0.8-rs'),
+      dependency('skrifa-0.31-rs'),
+      dependency('read-fonts-0.29-rs'),
+      dependency('font-types-0.9-rs'),
       dependency('libc-0.2-rs'),
     ],
     install: true,


More information about the Fontconfig mailing list