fontconfig: Branch 'main' - 7 commits

GitLab Mirror gitlab-mirror at kemper.freedesktop.org
Tue Jun 10 04:23:51 UTC 2025


 fc-fontations/attributes.rs      |  180 +++++++++++++++++++++++++++++++++++++--
 fc-fontations/bitmap.rs          |   50 ++++++++++
 fc-fontations/capabilities.rs    |   12 +-
 fc-fontations/meson.build        |    2 
 fc-fontations/mod.rs             |    8 +
 fc-fontations/names.rs           |   10 +-
 test/test_fontations_ft_query.py |   37 --------
 7 files changed, 252 insertions(+), 47 deletions(-)

New commits:
commit 61d7990e27b097a0f7d7bf2406713251ce895fd8
Merge: 043f3e6 00aaf39
Author: Akira TAGOH <akira at tagoh.org>
Date:   Tue Jun 10 04:23:48 2025 +0000

    Merge branch 'bitmapStrikeSizeWip' into 'main'
    
    [Fontations] Match all indexing properties with FreeType
    
    See merge request fontconfig/fontconfig!423

commit 00aaf393a16c200abab6a663e905d7ee225c42ec
Author: Dominik Röttsches <drott at chromium.org>
Date:   Mon Jun 9 18:33:53 2025 +0300

    [Fontations] Remove pattern filter from tests
    
    The spacing property was the last specific property which needed to be
    added and made compatible with FreeType. With that, on the 219 test
    fonts, we get equivalent indexing results with FreeType. (*^▽^*)

diff --git a/test/test_fontations_ft_query.py b/test/test_fontations_ft_query.py
index 5f3ddfb..3e90285 100644
--- a/test/test_fontations_ft_query.py
+++ b/test/test_fontations_ft_query.py
@@ -24,7 +24,7 @@ def list_test_fonts():
     return font_files
 
 
-def run_fc_query(font_file, format_string, with_fontations=False):
+def run_fc_query(font_file, with_fontations=False):
     fc_query_path = builddir() / "fc-query" / "fc-query"
 
     env = os.environ.copy()
@@ -52,46 +52,14 @@ def run_fc_query(font_file, format_string, with_fontations=False):
 def test_fontations_freetype_fcquery_equal(font_file):
     print(f"Testing with: {font_file}")  # Example usage
 
-    supported_format_entitites = [
-        "antialias",
-        "capability",
-        "charset",
-        "color",
-        "family",
-        "familylang",
-        "file",
-        "fontformat",
-        "fonthashint",
-        "fontwrapper",
-        "foundry",
-        "fullname",
-        "fullnamelang",
-        "lang",
-        "namedinstance",
-        "order",
-        "outline",
-        "scalable",
-        "size",
-        "slant",
-        "spacing",
-        "symbol",
-        "variable",
-        "version",
-        "weight",
-        "width",
-    ]
-    format_string = ":".join(
-        "%{" + entity + "}" for entity in supported_format_entitites
-    )
-
     font_path = Path(font_file)
 
     if not font_path.exists():
         pytest.skip(f"Font file not found: {font_file}")  # Skip if file missing
 
-    result_freetype = run_fc_query(font_file, format_string).stdout.strip().splitlines()
+    result_freetype = run_fc_query(font_file).stdout.strip().splitlines()
     result_fontations = (
-        run_fc_query(font_file, format_string, with_fontations=True)
+        run_fc_query(font_file, with_fontations=True)
         .stdout.strip()
         .splitlines()
     )
commit cc4734cf3d974071c52b29a6936c6c46962f8e90
Author: Dominik Röttsches <drott at chromium.org>
Date:   Mon Jun 9 18:29:34 2025 +0300

    [Fontations] No style element for variable instance

diff --git a/fc-fontations/names.rs b/fc-fontations/names.rs
index cc70a9c..ae7fded 100644
--- a/fc-fontations/names.rs
+++ b/fc-fontations/names.rs
@@ -162,8 +162,14 @@ pub fn add_names(
                 (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,
+                (
+                    InstanceMode::Variable,
+                    StringId::SUBFAMILY_NAME
+                    | StringId::WWS_SUBFAMILY_NAME
+                    | StringId::TYPOGRAPHIC_SUBFAMILY_NAME
+                    | StringId::FULL_NAME
+                    | StringId::POSTSCRIPT_NAME,
+                ) => None,
                 _ => name,
             };
 
diff --git a/test/test_fontations_ft_query.py b/test/test_fontations_ft_query.py
index 54bd655..5f3ddfb 100644
--- a/test/test_fontations_ft_query.py
+++ b/test/test_fontations_ft_query.py
@@ -32,7 +32,7 @@ def run_fc_query(font_file, format_string, with_fontations=False):
         env["FC_FONTATIONS"] = ""
 
     result = subprocess.run(
-        [fc_query_path, '-f', format_string, font_file],
+        [fc_query_path, font_file],
         stdout=subprocess.PIPE,
         env=env,
         stderr=subprocess.PIPE,
commit dc597c4e9a565d0fd54c24b018434a0981295806
Author: Dominik Röttsches <drott at chromium.org>
Date:   Thu Jun 5 22:54:39 2025 +0300

    [Fontations] Add spacing property

diff --git a/fc-fontations/attributes.rs b/fc-fontations/attributes.rs
index 8f28f98..092ccfe 100644
--- a/fc-fontations/attributes.rs
+++ b/fc-fontations/attributes.rs
@@ -25,13 +25,14 @@
 use fc_fontations_bindgen::{
     fcint::{
         FC_INDEX_OBJECT, FC_NAMED_INSTANCE_OBJECT, FC_SIZE_OBJECT, FC_SLANT_OBJECT,
-        FC_VARIABLE_OBJECT, FC_WEIGHT_OBJECT, FC_WIDTH_OBJECT,
+        FC_SPACING_OBJECT, FC_VARIABLE_OBJECT, FC_WEIGHT_OBJECT, FC_WIDTH_OBJECT,
     },
-    FcWeightFromOpenTypeDouble, FC_SLANT_ITALIC, FC_SLANT_OBLIQUE, FC_SLANT_ROMAN, FC_WEIGHT_BLACK,
-    FC_WEIGHT_BOLD, FC_WEIGHT_EXTRABOLD, FC_WEIGHT_EXTRALIGHT, FC_WEIGHT_LIGHT, FC_WEIGHT_MEDIUM,
-    FC_WEIGHT_NORMAL, FC_WEIGHT_SEMIBOLD, FC_WEIGHT_THIN, FC_WIDTH_CONDENSED, FC_WIDTH_EXPANDED,
-    FC_WIDTH_EXTRACONDENSED, FC_WIDTH_EXTRAEXPANDED, FC_WIDTH_NORMAL, FC_WIDTH_SEMICONDENSED,
-    FC_WIDTH_SEMIEXPANDED, FC_WIDTH_ULTRACONDENSED, FC_WIDTH_ULTRAEXPANDED,
+    FcWeightFromOpenTypeDouble, FC_DUAL, FC_MONO, FC_SLANT_ITALIC, FC_SLANT_OBLIQUE,
+    FC_SLANT_ROMAN, FC_WEIGHT_BLACK, FC_WEIGHT_BOLD, FC_WEIGHT_EXTRABOLD, FC_WEIGHT_EXTRALIGHT,
+    FC_WEIGHT_LIGHT, FC_WEIGHT_MEDIUM, FC_WEIGHT_NORMAL, FC_WEIGHT_SEMIBOLD, FC_WEIGHT_THIN,
+    FC_WIDTH_CONDENSED, FC_WIDTH_EXPANDED, FC_WIDTH_EXTRACONDENSED, FC_WIDTH_EXTRAEXPANDED,
+    FC_WIDTH_NORMAL, FC_WIDTH_SEMICONDENSED, FC_WIDTH_SEMIEXPANDED, FC_WIDTH_ULTRACONDENSED,
+    FC_WIDTH_ULTRAEXPANDED,
 };
 
 use crate::{
@@ -41,6 +42,9 @@ use crate::{
 use read_fonts::TableProvider;
 use skrifa::{
     attribute::{Attributes, Stretch, Style, Weight},
+    instance::Location,
+    metrics::GlyphMetrics,
+    prelude::{LocationRef, Size},
     AxisCollection, FontRef, MetadataProvider, NamedInstance, Tag,
 };
 
@@ -120,6 +124,7 @@ struct AttributesToPattern<'a> {
     attributes: Attributes,
     axes: AxisCollection<'a>,
     named_instance: Option<NamedInstance<'a>>,
+    font_ref: FontRef<'a>,
 }
 
 impl<'a> AttributesToPattern<'a> {
@@ -128,12 +133,14 @@ impl<'a> AttributesToPattern<'a> {
             InstanceMode::Named(index) => font.named_instances().get(*index as usize),
             _ => None,
         };
+
         Self {
             weight_from_os2: fc_weight_from_os2(font),
             width_from_os2: fc_width_from_os2(font),
             attributes: Attributes::new(font),
             axes: font.axes(),
             named_instance,
+            font_ref: font.clone(),
         }
     }
 
@@ -259,6 +266,84 @@ impl<'a> AttributesToPattern<'a> {
             FcRangeWrapper::new(opsz_axis.min_value() as f64, opsz_axis.max_value() as f64)?.into(),
         ))
     }
+
+    // Determine FontConfig spacing property.
+    // In fcfreetype.c FcFreeTypeSpacing a heuristic checks whether the glyphs
+    //  for a bitmap font are "approximately equal".
+    // For this purpose, fcfreetype.c selects the strike size closest to 16 px,
+    // then iterates over available glyphs and checks whether the advance width
+    // is within a relative tolerance of 1/33.
+    // We'll do this based on skrifa advances here - if needed, this can be
+    // moved to selecting a particular bitmap strike size and compare pixel
+    // widths.
+    fn spacing_from_advances(advances: impl Iterator<Item = f32>) -> Option<i32> {
+        let mut encountered_advances = Vec::new();
+
+        let approximately_equal =
+            |a: f32, b: f32| (a - b).abs() / a.abs().max(b.abs()) <= 1.0 / 33.0;
+
+        'outer: for advance in advances {
+            let mut may_push: Option<f32> = None;
+            if encountered_advances.is_empty() {
+                encountered_advances.push(advance);
+                continue;
+            }
+
+            for encountered in encountered_advances.iter() {
+                if encountered_advances.len() >= 3 {
+                    break 'outer;
+                }
+                if approximately_equal(advance, *encountered) {
+                    may_push = None;
+                    break;
+                }
+                may_push = Some(advance);
+            }
+            if let Some(push) = may_push {
+                encountered_advances.push(push);
+            }
+        }
+
+        match encountered_advances.len() {
+            1 => Some(FC_MONO as i32),
+            2 if approximately_equal(
+                encountered_advances[0].min(encountered_advances[1]) * 2.0,
+                encountered_advances[0].max(encountered_advances[1]),
+            ) =>
+            {
+                Some(FC_DUAL as i32)
+            }
+
+            _ => None,
+        }
+    }
+
+    fn spacing(&self) -> Option<PatternElement> {
+        let mut location = Location::default();
+        if let Some(instance) = &self.named_instance {
+            location = instance.location().clone();
+        };
+
+        let glyph_metrics = GlyphMetrics::new(
+            &self.font_ref,
+            Size::new(16.0),
+            LocationRef::from(&location),
+        );
+
+        let advances = self
+            .font_ref
+            .charmap()
+            .mappings()
+            .map(|(_codepoint, gid)| {
+                glyph_metrics
+                    .advance_width(gid)
+                    .and_then(|adv| if adv > 0.0 { Some(adv) } else { None })
+            })
+            .flatten();
+
+        Self::spacing_from_advances(advances)
+            .map(|spacing| PatternElement::new(FC_SPACING_OBJECT as i32, spacing.into()))
+    }
 }
 
 pub fn append_style_elements(
@@ -273,6 +358,10 @@ pub fn append_style_elements(
 
     let attributes_converter = AttributesToPattern::new(font, &instance_mode);
 
+    if let Some(spacing) = attributes_converter.spacing() {
+        pattern.append_element(spacing);
+    }
+
     match instance_mode {
         InstanceMode::Default => {
             pattern.append_element(attributes_converter.static_weight());
@@ -351,3 +440,78 @@ pub fn append_style_elements(
         }
     }
 }
+
+#[cfg(test)]
+mod test {
+    use crate::attributes::AttributesToPattern;
+    use fc_fontations_bindgen::{FC_DUAL, FC_MONO};
+
+    const THRESHOLD_FACTOR_DOWN: f32 = 1.0 - 1.0 / 33.0;
+    const THRESHOLD_FACTOR_UP: f32 = 1.0 + 1.0 / 33.0;
+
+    fn assert_spacing(advances: impl Iterator<Item = f32>, expectation: Option<i32>) {
+        assert_eq!(
+            AttributesToPattern::spacing_from_advances(advances),
+            expectation
+        );
+    }
+
+    #[test]
+    fn spacing_mono() {
+        assert_spacing([10.0].iter().cloned(), Some(FC_MONO as i32));
+
+        assert_spacing(
+            [
+                10.0,
+                10.0,
+                10.0,
+                10.0 * THRESHOLD_FACTOR_UP,
+                10.0 * THRESHOLD_FACTOR_DOWN,
+            ]
+            .iter()
+            .cloned(),
+            Some(FC_MONO as i32),
+        );
+    }
+
+    #[test]
+    fn spacing_proportional() {
+        assert_spacing(
+            [10.0, 10.0 * THRESHOLD_FACTOR_UP + 0.01].iter().cloned(),
+            None,
+        );
+
+        assert_spacing(
+            [10.0, 10.0 * THRESHOLD_FACTOR_DOWN - 0.01].iter().cloned(),
+            None,
+        );
+
+        assert_spacing([10.0, 15.0].iter().cloned(), None);
+
+        assert_spacing([10.0, 15.0, 20.0].iter().cloned(), None);
+    }
+
+    #[test]
+    fn advances_dual() {
+        assert_spacing([10.0, 20.0].iter().cloned(), Some(FC_DUAL as i32));
+
+        assert_spacing(
+            [10.0, 20.0, 10.0, 20.0, 10.0, 20.0].iter().cloned(),
+            Some(FC_DUAL as i32),
+        );
+
+        assert_spacing(
+            [
+                10.0,
+                20.0 * THRESHOLD_FACTOR_UP,
+                10.0,
+                20.0,
+                10.0 * THRESHOLD_FACTOR_DOWN,
+                20.0,
+            ]
+            .iter()
+            .cloned(),
+            Some(FC_DUAL as i32),
+        );
+    }
+}
diff --git a/fc-fontations/bitmap.rs b/fc-fontations/bitmap.rs
index 13a227b..149c07f 100644
--- a/fc-fontations/bitmap.rs
+++ b/fc-fontations/bitmap.rs
@@ -32,12 +32,7 @@ use fc_fontations_bindgen::fcint::{FC_ANTIALIAS_OBJECT, FC_PIXEL_SIZE_OBJECT};
 pub fn add_pixel_size(pattern: &mut FcPatternBuilder, font: &FontRef) {
     let strikes = BitmapStrikes::new(font);
 
-    if strikes.len() > 0 {
-        pattern.append_element(PatternElement::new(
-            FC_ANTIALIAS_OBJECT as i32,
-            false.into(),
-        ));
-    }
+    let has_strikes = strikes.len() > 0;
 
     for strike in strikes.iter() {
         pattern.append_element(PatternElement::new(
@@ -45,4 +40,11 @@ pub fn add_pixel_size(pattern: &mut FcPatternBuilder, font: &FontRef) {
             (strike.ppem() as f64).into(),
         ));
     }
+
+    if has_strikes {
+        pattern.append_element(PatternElement::new(
+            FC_ANTIALIAS_OBJECT as i32,
+            false.into(),
+        ));
+    }
 }
diff --git a/fc-fontations/meson.build b/fc-fontations/meson.build
index 0cdbbd6..9a9ae70 100644
--- a/fc-fontations/meson.build
+++ b/fc-fontations/meson.build
@@ -9,7 +9,7 @@ if (fontations.enabled())
     include_directories : [ '../' ],
     args : [
       '--merge-extern-blocks',
-      '--allowlist-item=(FcCharSet.*|FC_(SLANT|WEIGHT|WIDTH)_.*|FcFontSet(Add|Create|Destroy).*|FcLangSet(Create|Destroy|Copy|Add|HasLang)|FcWeightFromOpenType.*)',
+      '--allowlist-item=(FcCharSet.*|FC_(SLANT|WEIGHT|WIDTH)_.*|FcFontSet(Add|Create|Destroy).*|FcLangSet(Create|Destroy|Copy|Add|HasLang)|FcWeightFromOpenType.*|FC_DUAL|FC_MONO)',
       '--raw-line=#![allow(nonstandard_style,unused)]',
       '--raw-line= ',
       '--raw-line=pub mod fcint;',
diff --git a/fc-fontations/mod.rs b/fc-fontations/mod.rs
index f197f33..88d23e7 100644
--- a/fc-fontations/mod.rs
+++ b/fc-fontations/mod.rs
@@ -40,7 +40,6 @@ use foundries::make_foundry;
 use lang::exclusive_lang;
 use names::add_names;
 
-
 use fc_fontations_bindgen::{
     fcint::{
         FcFreeTypeLangSet, FC_CAPABILITY_OBJECT, FC_CHARSET_OBJECT, FC_COLOR_OBJECT,
diff --git a/test/test_fontations_ft_query.py b/test/test_fontations_ft_query.py
index da428d1..54bd655 100644
--- a/test/test_fontations_ft_query.py
+++ b/test/test_fontations_ft_query.py
@@ -73,6 +73,7 @@ def test_fontations_freetype_fcquery_equal(font_file):
         "scalable",
         "size",
         "slant",
+        "spacing",
         "symbol",
         "variable",
         "version",
commit 1468de2be59d84f5bc0c02072dc4efaf53c49c05
Author: Dominik Röttsches <drott at chromium.org>
Date:   Mon Jun 9 16:49:11 2025 +0300

    [Fontations] Fix size element and enable more element tests
    
    Fix the default size for a variable font, enable size, and lang
    pattern elements.

diff --git a/fc-fontations/attributes.rs b/fc-fontations/attributes.rs
index be12b83..8f28f98 100644
--- a/fc-fontations/attributes.rs
+++ b/fc-fontations/attributes.rs
@@ -285,6 +285,10 @@ pub fn append_style_elements(
                 ttc_index.unwrap_or_default().into(),
             ));
 
+            if let Some(size) = attributes_converter.default_size() {
+                pattern.append_element(size);
+            }
+
             pattern.append_element(PatternElement::new(
                 FC_NAMED_INSTANCE_OBJECT as i32,
                 false.into(),
diff --git a/fc-fontations/mod.rs b/fc-fontations/mod.rs
index 88d23e7..f197f33 100644
--- a/fc-fontations/mod.rs
+++ b/fc-fontations/mod.rs
@@ -40,6 +40,7 @@ use foundries::make_foundry;
 use lang::exclusive_lang;
 use names::add_names;
 
+
 use fc_fontations_bindgen::{
     fcint::{
         FcFreeTypeLangSet, FC_CAPABILITY_OBJECT, FC_CHARSET_OBJECT, FC_COLOR_OBJECT,
diff --git a/test/test_fontations_ft_query.py b/test/test_fontations_ft_query.py
index 09b4c00..da428d1 100644
--- a/test/test_fontations_ft_query.py
+++ b/test/test_fontations_ft_query.py
@@ -53,6 +53,7 @@ def test_fontations_freetype_fcquery_equal(font_file):
     print(f"Testing with: {font_file}")  # Example usage
 
     supported_format_entitites = [
+        "antialias",
         "capability",
         "charset",
         "color",
@@ -63,11 +64,17 @@ def test_fontations_freetype_fcquery_equal(font_file):
         "fonthashint",
         "fontwrapper",
         "foundry",
-        "langset",
+        "fullname",
+        "fullnamelang",
+        "lang",
+        "namedinstance",
+        "order",
         "outline",
         "scalable",
+        "size",
         "slant",
         "symbol",
+        "variable",
         "version",
         "weight",
         "width",
commit c817a0302c5d826d53aab24fe238deb143870903
Author: Dominik Röttsches <drott at chromium.org>
Date:   Wed Jun 4 16:32:33 2025 +0200

    [Fontations] Add pixel size information

diff --git a/fc-fontations/bitmap.rs b/fc-fontations/bitmap.rs
new file mode 100644
index 0000000..13a227b
--- /dev/null
+++ b/fc-fontations/bitmap.rs
@@ -0,0 +1,48 @@
+/*
+ * fontconfig/fc-fontations/bitmap.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 skrifa::FontRef;
+
+use skrifa::bitmap::BitmapStrikes;
+
+use crate::pattern_bindings::{FcPatternBuilder, PatternElement};
+use fc_fontations_bindgen::fcint::{FC_ANTIALIAS_OBJECT, FC_PIXEL_SIZE_OBJECT};
+
+pub fn add_pixel_size(pattern: &mut FcPatternBuilder, font: &FontRef) {
+    let strikes = BitmapStrikes::new(font);
+
+    if strikes.len() > 0 {
+        pattern.append_element(PatternElement::new(
+            FC_ANTIALIAS_OBJECT as i32,
+            false.into(),
+        ));
+    }
+
+    for strike in strikes.iter() {
+        pattern.append_element(PatternElement::new(
+            FC_PIXEL_SIZE_OBJECT as i32,
+            (strike.ppem() as f64).into(),
+        ));
+    }
+}
diff --git a/fc-fontations/capabilities.rs b/fc-fontations/capabilities.rs
index 87966c2..a19345d 100644
--- a/fc-fontations/capabilities.rs
+++ b/fc-fontations/capabilities.rs
@@ -43,6 +43,9 @@ fn capabilities_string<T: IntoIterator<Item = Tag>>(tags: T, has_silf: bool) ->
         .join(" ");
 
     has_silf.then(|| capabilities.insert_str(0, SILF_CAPABILITIES_PREFIX));
+    if capabilities.is_empty() {
+        return None;
+    }
     CString::new(capabilities).ok()
 }
 
@@ -77,10 +80,6 @@ mod test {
             "otlayout:DFLT otlayout:cyrl otlayout:grek",
             capabilities_string(tags, false).unwrap().to_str().unwrap()
         );
-        assert_eq!(
-            "",
-            capabilities_string([], false).unwrap().to_str().unwrap()
-        );
         let tags = [
             Tag::new(b"DFLT"),
             Tag::new(b"cyrl"),
@@ -94,6 +93,11 @@ mod test {
         );
     }
 
+    #[test]
+    fn empty_capabilities() {
+        assert_eq!(None, capabilities_string([], false));
+    }
+
     #[test]
     fn graphite_capabilities() {
         let tags = [Tag::new(b"grek")];
diff --git a/fc-fontations/mod.rs b/fc-fontations/mod.rs
index 76d1945..88d23e7 100644
--- a/fc-fontations/mod.rs
+++ b/fc-fontations/mod.rs
@@ -23,6 +23,7 @@
  */
 
 mod attributes;
+mod bitmap;
 mod capabilities;
 mod charset;
 mod foundries;
@@ -33,6 +34,7 @@ mod names;
 mod pattern_bindings;
 
 use attributes::append_style_elements;
+use bitmap::add_pixel_size;
 use capabilities::make_capabilities;
 use foundries::make_foundry;
 use lang::exclusive_lang;
@@ -43,7 +45,7 @@ use fc_fontations_bindgen::{
         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_ORDER_OBJECT, FC_OUTLINE_OBJECT, FC_SCALABLE_OBJECT, FC_SYMBOL_OBJECT,
     },
     FcFontSet, FcFontSetAdd, FcPattern,
 };
@@ -272,6 +274,10 @@ fn build_patterns_for_font(
         version.into(),
     ));
 
+    add_pixel_size(&mut pattern, font);
+
+    pattern.append_element(PatternElement::new(FC_ORDER_OBJECT as i32, 0.into()));
+
     // So far the pattern elements applied to te whole font file, in the below,
     // clone the current pattern state and add instance specific
     // attributes. FontConfig for variable fonts produces a pattern for the
diff --git a/test/test_fontations_ft_query.py b/test/test_fontations_ft_query.py
index aaa55e2..09b4c00 100644
--- a/test/test_fontations_ft_query.py
+++ b/test/test_fontations_ft_query.py
@@ -32,7 +32,7 @@ def run_fc_query(font_file, format_string, with_fontations=False):
         env["FC_FONTATIONS"] = ""
 
     result = subprocess.run(
-        [fc_query_path, "-f", format_string, font_file],
+        [fc_query_path, '-f', format_string, font_file],
         stdout=subprocess.PIPE,
         env=env,
         stderr=subprocess.PIPE,
@@ -75,7 +75,6 @@ def test_fontations_freetype_fcquery_equal(font_file):
     format_string = ":".join(
         "%{" + entity + "}" for entity in supported_format_entitites
     )
-    print(format_string)
 
     font_path = Path(font_file)
 
commit d9fa1abb5194eb0e99630950d3b8e80edd6187a4
Author: Dominik Röttsches <drott at chromium.org>
Date:   Wed Jun 4 15:25:45 2025 +0200

    Sort test pattern elements

diff --git a/test/test_fontations_ft_query.py b/test/test_fontations_ft_query.py
index 3b59acf..aaa55e2 100644
--- a/test/test_fontations_ft_query.py
+++ b/test/test_fontations_ft_query.py
@@ -53,28 +53,24 @@ def test_fontations_freetype_fcquery_equal(font_file):
     print(f"Testing with: {font_file}")  # Example usage
 
     supported_format_entitites = [
+        "capability",
+        "charset",
+        "color",
         "family",
         "familylang",
-        "fullname",
-        "fullnamelang",
-        "postscriptname",
-        "outline",
-        "scalable",
+        "file",
         "fontformat",
-        "color",
         "fonthashint",
+        "fontwrapper",
         "foundry",
+        "langset",
+        "outline",
+        "scalable",
+        "slant",
+        "symbol",
         "version",
         "weight",
         "width",
-        "slant",
-        "capability",
-        "charset",
-        "langset",
-        "symbol",
-        "fontwrapper",
-        "file",
-        "variable",
     ]
     format_string = ":".join(
         "%{" + entity + "}" for entity in supported_format_entitites


More information about the Fontconfig mailing list