fontconfig: Branch 'main' - 3 commits

GitLab Mirror gitlab-mirror at kemper.freedesktop.org
Mon Mar 31 12:05:52 UTC 2025


 .gitlab-ci/build.sh                          |   12 +
 fc-fontations/mod.rs                         |   33 ++-
 fc-fontations/pattern_bindings/fc_wrapper.rs |  123 +++++++++++++
 fc-fontations/pattern_bindings/mod.rs        |  254 +++++++++++++++++++++++++++
 4 files changed, 417 insertions(+), 5 deletions(-)

New commits:
commit 31252db1e652d63ab34d3a63c22aea16dce23db4
Merge: 564a8a9 738eb8a
Author: Akira TAGOH <akira at tagoh.org>
Date:   Mon Mar 31 12:05:49 2025 +0000

    Merge branch 'patternBindings' into 'main'
    
    [Fontations] Add internal PatternBuilder abstraction
    
    See merge request fontconfig/fontconfig!371

commit 738eb8a73ab05301163479ddab7ceebab88907bb
Author: Dominik Röttsches <drott at chromium.org>
Date:   Tue Mar 18 12:33:09 2025 +0200

    [Fontations] Add internal PatternBuilder abstraction
    
    Rust abstraction for creating FcPatterns. Implements Drop methods for
    handling memory of destroying FontConfig-side allocated objects
    where needed for complex pattern objects.
    Used in the Fontations backend, not exposed as external API.
    
    Changelog: added

diff --git a/fc-fontations/mod.rs b/fc-fontations/mod.rs
index b3a82a6..3929924 100644
--- a/fc-fontations/mod.rs
+++ b/fc-fontations/mod.rs
@@ -1,5 +1,31 @@
+/*
+ * fontconfig/fc-fontations/mod.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.
+ */
+
 extern crate fc_fontations_bindgen;
 
+mod pattern_bindings;
+
 use fc_fontations_bindgen::{
     fcint::{FcPatternCreate, FcPatternObjectAddBool, FC_COLOR_OBJECT},
     FcFontSet, FcFontSetAdd,
diff --git a/fc-fontations/pattern_bindings/fc_wrapper.rs b/fc-fontations/pattern_bindings/fc_wrapper.rs
new file mode 100644
index 0000000..e3ad063
--- /dev/null
+++ b/fc-fontations/pattern_bindings/fc_wrapper.rs
@@ -0,0 +1,123 @@
+/*
+ * fontconfig/fc-fontations/pattern_bindings/fc_wrapper.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 fc_fontations_bindgen::fcint::{
+    FcPattern, FcPatternCreate, FcPatternDestroy, FcRange, FcRangeCopy, FcRangeCreateDouble,
+    FcRangeDestroy,
+};
+
+macro_rules! wrap_fc_object {
+    (
+        $wrapper_name:ident,
+        $wrapped_type:ident,
+        $destroy_fn:ident
+        $(, $copy_fn:ident)?
+    ) => {
+        #[allow(unused)]
+        #[derive(Debug)]
+        pub struct $wrapper_name {
+            inner: *mut $wrapped_type,
+        }
+
+        impl $wrapper_name {
+            #[allow(unused)]
+            pub fn from_raw(ptr: *mut $wrapped_type) -> Self {
+                Self { inner: ptr }
+            }
+
+            #[allow(unused)]
+            pub fn into_raw(self) -> *mut $wrapped_type {
+                let ptr = self.inner;
+                std::mem::forget(self);
+                ptr
+            }
+
+            #[allow(unused)]
+            pub fn as_ptr(&self) -> *mut $wrapped_type {
+                assert!(!self.inner.is_null());
+                self.inner
+            }
+        }
+
+        impl Drop for $wrapper_name {
+            fn drop(&mut self) {
+                unsafe {
+                    $destroy_fn(self.inner);
+                }
+            }
+        }
+
+        $(
+            impl Clone for $wrapper_name {
+                fn clone(&self) -> Self {
+                    Self {
+                        inner: unsafe { $copy_fn(self.inner) },
+                    }
+                }
+            }
+        )?
+    };
+}
+
+wrap_fc_object! {
+    FcRangeWrapper,
+    FcRange,
+    FcRangeDestroy,
+    FcRangeCopy
+}
+
+impl FcRangeWrapper {
+    #[allow(unused)]
+    pub fn new(min: f64, max: f64) -> Option<Self> {
+        unsafe {
+            let ptr = FcRangeCreateDouble(min, max);
+            if ptr.is_null() {
+                None
+            } else {
+                Some(Self { inner: ptr })
+            }
+        }
+    }
+}
+
+wrap_fc_object! {
+    FcPatternWrapper,
+    FcPattern,
+    FcPatternDestroy
+}
+
+impl FcPatternWrapper {
+    #[allow(unused)]
+    pub fn new() -> Option<Self> {
+        // Corrected new function for FcPattern
+        unsafe {
+            let ptr = FcPatternCreate();
+            if ptr.is_null() {
+                None
+            } else {
+                Some(Self { inner: ptr })
+            }
+        }
+    }
+}
diff --git a/fc-fontations/pattern_bindings/mod.rs b/fc-fontations/pattern_bindings/mod.rs
new file mode 100644
index 0000000..0174487
--- /dev/null
+++ b/fc-fontations/pattern_bindings/mod.rs
@@ -0,0 +1,254 @@
+/*
+ * fontconfig/fc-fontations/pattern_bindings/mod.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.
+ */
+
+ extern crate fc_fontations_bindgen;
+
+mod fc_wrapper;
+
+use std::ffi::CString;
+use std::fmt::Debug;
+
+use fc_fontations_bindgen::fcint::{
+    FcPattern, FcPatternObjectAddBool, FcPatternObjectAddDouble, FcPatternObjectAddInteger,
+    FcPatternObjectAddRange, FcPatternObjectAddString, FC_FAMILY_OBJECT,
+};
+
+use self::fc_wrapper::{FcPatternWrapper, FcRangeWrapper};
+
+#[allow(unused)]
+#[derive(Debug)]
+pub enum PatternValue {
+    String(CString),
+    Boolean(bool),
+    Integer(i32),
+    Double(f64),
+    Range(FcRangeWrapper),
+}
+
+#[derive(Debug)]
+pub struct PatternElement {
+    object_id: i32,
+    value: PatternValue,
+}
+
+impl PatternElement {
+    #[allow(unused)]
+    fn new(object_id: i32, value: PatternValue) -> Self {
+        Self { object_id, value }
+    }
+}
+
+#[derive(Debug, Clone)]
+struct PatternAddError;
+
+impl std::fmt::Display for PatternAddError {
+    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
+        write!(f, "Failed to add object to Fontconfig pattern.")
+    }
+}
+
+impl PatternElement {
+    fn append_to_fc_pattern(self, pattern: *mut FcPattern) -> Result<(), PatternAddError> {
+        let pattern_add_success = match self.value {
+            PatternValue::String(string) => unsafe {
+                FcPatternObjectAddString(pattern, self.object_id, string.as_ptr() as *const u8)
+            },
+            PatternValue::Boolean(value) => unsafe {
+                FcPatternObjectAddBool(pattern, self.object_id, value as i32)
+            },
+            PatternValue::Integer(value) => unsafe {
+                FcPatternObjectAddInteger(pattern, self.object_id, value)
+            },
+            PatternValue::Double(value) => unsafe {
+                FcPatternObjectAddDouble(pattern, self.object_id, value)
+            },
+            PatternValue::Range(value) => unsafe {
+                FcPatternObjectAddRange(pattern, self.object_id, value.into_raw())
+            },
+        } == 1;
+        if pattern_add_success {
+            return Ok(());
+        }
+        Err(PatternAddError)
+    }
+}
+
+#[derive(Default, Debug)]
+pub struct FcPatternBuilder {
+    elements: Vec<PatternElement>,
+}
+
+impl FcPatternBuilder {
+    #[allow(unused)]
+    pub fn new() -> Self {
+        Self::default()
+    }
+
+    #[allow(unused)]
+    pub fn append_element(&mut self, element: PatternElement) {
+        self.elements.push(element);
+    }
+
+    #[allow(unused)]
+    pub fn create_fc_pattern(&mut self) -> Option<FcPatternWrapper> {
+        let pattern = FcPatternWrapper::new()?;
+
+        let mut family_name_encountered = false;
+
+        const FAMILY_ID: i32 = FC_FAMILY_OBJECT as i32;
+        for element in self.elements.drain(0..) {
+            if let PatternElement {
+                object_id: FAMILY_ID,
+                value: PatternValue::String(ref fam_name),
+            } = element
+            {
+                if !fam_name.is_empty() {
+                    family_name_encountered = true;
+                }
+            }
+            element.append_to_fc_pattern(pattern.as_ptr()).ok()?;
+        }
+
+        if !family_name_encountered {
+            return None;
+        }
+
+        Some(pattern)
+    }
+}
+
+#[cfg(test)]
+mod test {
+    use std::ffi::CString;
+
+    use super::{FcPatternBuilder, FcRangeWrapper, PatternElement, PatternValue};
+    use fc_fontations_bindgen::fcint::{
+        FcPatternObjectGetBool, FcPatternObjectGetDouble, FcPatternObjectGetInteger,
+        FcPatternObjectGetRange, FcPatternObjectGetString, FcRange, FC_COLOR_OBJECT,
+        FC_FAMILY_OBJECT, FC_SLANT_OBJECT, FC_WEIGHT_OBJECT, FC_WIDTH_OBJECT,
+    };
+
+    #[test]
+    fn verify_pattern_bindings() {
+        let mut pattern_builder = FcPatternBuilder::new();
+
+        // Add a bunch of test properties.
+        pattern_builder.append_element(PatternElement::new(
+            FC_COLOR_OBJECT as i32,
+            PatternValue::Boolean(true),
+        ));
+        pattern_builder.append_element(PatternElement::new(
+            FC_WEIGHT_OBJECT as i32,
+            PatternValue::Double(800.),
+        ));
+        pattern_builder.append_element(PatternElement::new(
+            FC_SLANT_OBJECT as i32,
+            PatternValue::Integer(15),
+        ));
+
+        pattern_builder.append_element(PatternElement::new(
+            FC_WIDTH_OBJECT as i32,
+            PatternValue::Range(FcRangeWrapper::new(100., 400.).unwrap()),
+        ));
+
+        pattern_builder.append_element(PatternElement::new(
+            FC_FAMILY_OBJECT as i32,
+            PatternValue::String(CString::new("TestFont").unwrap()),
+        ));
+
+        let pattern = pattern_builder.create_fc_pattern().unwrap();
+
+        let fontconfig_pattern = pattern.as_ptr();
+        unsafe {
+            // Verify color properties.
+            let mut result: i32 = 0;
+            let get_result =
+                FcPatternObjectGetBool(fontconfig_pattern, FC_COLOR_OBJECT as i32, 0, &mut result);
+            assert_eq!(get_result, 0);
+            assert_eq!(result, 1);
+
+            // Verify weight value.
+            let mut weight_result: f64 = 0.;
+            let get_result = FcPatternObjectGetDouble(
+                fontconfig_pattern,
+                FC_WEIGHT_OBJECT as i32,
+                0,
+                &mut weight_result,
+            );
+            assert_eq!(get_result, 0);
+            assert_eq!(weight_result, 800.0);
+
+            // Verify that weight is not a range.
+            let range_result: *mut *mut FcRange = std::mem::zeroed();
+            assert_eq!(
+                FcPatternObjectGetRange(
+                    fontconfig_pattern,
+                    FC_WEIGHT_OBJECT as i32,
+                    0,
+                    range_result
+                ),
+                2
+            );
+
+            // Verify slant.
+            let mut slant_result: i32 = 0;
+            let get_result = FcPatternObjectGetInteger(
+                fontconfig_pattern,
+                FC_SLANT_OBJECT as i32,
+                0,
+                &mut slant_result,
+            );
+            assert_eq!(get_result, 0);
+            assert_eq!(slant_result, 15);
+
+            // Verify width.
+            let mut width_result: *mut FcRange = std::mem::zeroed();
+            let get_result = FcPatternObjectGetRange(
+                fontconfig_pattern,
+                FC_WIDTH_OBJECT as i32,
+                0,
+                &mut width_result,
+            );
+            assert_eq!(get_result, 0);
+            assert_eq!((*width_result).begin, 100.);
+            assert_eq!((*width_result).end, 400.);
+
+            // Verify family name.
+            let mut family_result: *mut u8 = std::mem::zeroed();
+            let get_result = FcPatternObjectGetString(
+                fontconfig_pattern,
+                FC_FAMILY_OBJECT as i32,
+                0,
+                &mut family_result,
+            );
+            assert_eq!(get_result, 0);
+            assert_eq!(
+                std::ffi::CStr::from_ptr(family_result as *const i8)
+                    .to_str()
+                    .unwrap(),
+                "TestFont"
+            );
+        }
+    }
+}
commit 5d8833ed65208c811c82d4855ce2c874684075a9
Author: Dominik Röttsches <drott at chromium.org>
Date:   Mon Mar 24 11:00:51 2025 +0200

    Upgrade bindgen in Fontations enabled Rust builds
    
    Fixes issues with Rust constant generation for FC_.*_OBJECT type constants.

diff --git a/.gitlab-ci/build.sh b/.gitlab-ci/build.sh
index 55a0722..db4accc 100755
--- a/.gitlab-ci/build.sh
+++ b/.gitlab-ci/build.sh
@@ -111,6 +111,18 @@ elif [ x"$buildsys" == "xmeson" ]; then
     pip install tomli
     for i in "${enable[@]}"; do
         buildopt+=(-D$i=enabled)
+
+        # Update bindgen on Fontations builds to improve support for constants in fcint.h
+        if [[ "$i" == "fontations" ]]; then
+            cargo install bindgen-cli
+            # Prepend the cargo bin directory to PATH
+            if [[ -d "$HOME/.cargo/bin" ]]; then
+                export PATH="$HOME/.cargo/bin:$PATH"
+                echo "Cargo bin directory added to PATH."
+            else
+                echo "Cargo bin directory not found."
+            fi
+        fi
     done
     for i in "${disable[@]}"; do
         buildopt+=(-D$i=disabled)
diff --git a/fc-fontations/mod.rs b/fc-fontations/mod.rs
index 1a9be87..b3a82a6 100644
--- a/fc-fontations/mod.rs
+++ b/fc-fontations/mod.rs
@@ -1,7 +1,7 @@
 extern crate fc_fontations_bindgen;
 
 use fc_fontations_bindgen::{
-    fcint::{FcPatternCreate, FcPatternObjectAddBool},
+    fcint::{FcPatternCreate, FcPatternObjectAddBool, FC_COLOR_OBJECT},
     FcFontSet, FcFontSetAdd,
 };
 
@@ -20,10 +20,7 @@ pub unsafe extern "C" fn add_patterns_to_fontset(
     let empty_pattern = FcPatternCreate();
     // Test call to ensure that an FcPrivate API function FcPatternObjectAddBool
     // is accessible and can be linked to.
-    // TODO(drott): This should be FC_COLOR_OBJECT imported from fcint.h,
-    // but there's a separate bindgen issue that needs to be sorted out.
-    const COLOR_OBJECT: i32 = 46;
-    FcPatternObjectAddBool(empty_pattern, COLOR_OBJECT, 0 as i32);
+    FcPatternObjectAddBool(empty_pattern, FC_COLOR_OBJECT as i32, 0_i32);
     if !font_set.is_null() {
         FcFontSetAdd(
             font_set,


More information about the Fontconfig mailing list