fc-fontations/attributes.rs | 24 +++++++- fc-fontations/capabilities.rs | 105 ++++++++++++++++++++++++++++++++++++ fc-fontations/instance_enumerate.rs | 2 fc-fontations/mod.rs | 14 ++++ src/fcfreetype.c | 6 +- test/test_fontations_ft_query.py | 1 6 files changed, 146 insertions(+), 6 deletions(-) New commits: commit c0118a3bea1d3857d5be13b4ae575c638decb9a3 Merge: 3454d29 bf3fbad Author: Akira TAGOH <akira@xxxxxxxxx> Date: Mon May 12 12:12:04 2025 +0000 Merge branch 'capabilities' into 'main' [Fontations] Add Capabilities to Pattern See merge request fontconfig/fontconfig!403 commit bf3fbad0ffa955a63bc7b515da002d363cf4d5fc Author: Dominik Röttsches <drott@xxxxxxxxxxxx> Date: Thu May 8 15:01:30 2025 +0300 [Fontations] Process and append font capabilities to Pattern * Touches capability: pattern object in FreeType: an extra space between `ttable:Silf` and the remaining OT-based capability indicators was removed. Changelog: changed diff --git a/fc-fontations/capabilities.rs b/fc-fontations/capabilities.rs new file mode 100644 index 0000000..87966c2 --- /dev/null +++ b/fc-fontations/capabilities.rs @@ -0,0 +1,105 @@ +/* + * fontconfig/fc-fontations/capabilities.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::Tag; +use read_fonts::tables::layout::ScriptRecord; +use read_fonts::TableProvider; +use skrifa::FontRef; +use std::ffi::CString; + +// Mimicking issue in FreeType indexer inserting two delimiting spaces. +const SILF_CAPABILITIES_PREFIX: &str = "ttable:Silf "; +const SILF_TAG: Tag = Tag::new(b"Silf"); + +fn capabilities_string<T: IntoIterator<Item = Tag>>(tags: T, has_silf: bool) -> Option<CString> { + let mut deduplicated_tags: Vec<Tag> = tags.into_iter().collect::<Vec<_>>(); + deduplicated_tags.sort(); + deduplicated_tags.dedup(); + let mut capabilities = deduplicated_tags + .into_iter() + .map(|tag| format!("otlayout:{}", tag)) + .collect::<Vec<_>>() + .join(" "); + + has_silf.then(|| capabilities.insert_str(0, SILF_CAPABILITIES_PREFIX)); + CString::new(capabilities).ok() +} + +fn gsub_tags<'a>(font: &'a FontRef) -> Option<&'a [ScriptRecord]> { + Some(font.gsub().ok()?.script_list().ok()?.script_records()) +} + +fn gpos_tags<'a>(font: &'a FontRef) -> Option<&'a [ScriptRecord]> { + Some(font.gpos().ok()?.script_list().ok()?.script_records()) +} + +pub fn make_capabilities(font: &FontRef) -> Option<CString> { + let has_silf = font.table_data(SILF_TAG).is_some(); + capabilities_string( + gsub_tags(font) + .into_iter() + .flatten() + .chain(gpos_tags(font).into_iter().flatten()) + .map(|script_record| script_record.script_tag()), + has_silf, + ) +} + +#[cfg(test)] +mod test { + use super::capabilities_string; + use font_types::Tag; + #[test] + fn capabilities() { + let tags = [Tag::new(b"DFLT"), Tag::new(b"cyrl"), Tag::new(b"grek")]; + assert_eq!( + "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"), + Tag::new(b"cyrl"), + Tag::new(b"grek"), + ]; + + assert_eq!( + "otlayout:DFLT otlayout:cyrl otlayout:grek", + capabilities_string(tags, false).unwrap().to_str().unwrap() + ); + } + + #[test] + fn graphite_capabilities() { + let tags = [Tag::new(b"grek")]; + assert_eq!( + "ttable:Silf otlayout:grek", + capabilities_string(tags, true).unwrap().to_str().unwrap() + ); + } +} diff --git a/fc-fontations/mod.rs b/fc-fontations/mod.rs index 3f43266..72f5ac7 100644 --- a/fc-fontations/mod.rs +++ b/fc-fontations/mod.rs @@ -23,19 +23,22 @@ */ mod attributes; +mod capabilities; mod foundries; mod instance_enumerate; mod names; mod pattern_bindings; use attributes::append_style_elements; +use capabilities::make_capabilities; use foundries::make_foundry; use names::add_names; use fc_fontations_bindgen::{ fcint::{ - FC_COLOR_OBJECT, FC_DECORATIVE_OBJECT, FC_FONTFORMAT_OBJECT, FC_FONTVERSION_OBJECT, - FC_FONT_HAS_HINT_OBJECT, FC_FOUNDRY_OBJECT, FC_OUTLINE_OBJECT, FC_SCALABLE_OBJECT, + FC_CAPABILITY_OBJECT, FC_COLOR_OBJECT, FC_DECORATIVE_OBJECT, FC_FONTFORMAT_OBJECT, + FC_FONTVERSION_OBJECT, FC_FONT_HAS_HINT_OBJECT, FC_FOUNDRY_OBJECT, FC_OUTLINE_OBJECT, + FC_SCALABLE_OBJECT, }, FcFontSet, FcFontSetAdd, FcPattern, }; @@ -172,6 +175,13 @@ fn build_patterns_for_font( foundry_string.into(), )); + if let Some(capabilities) = make_capabilities(font) { + pattern.append_element(PatternElement::new( + FC_CAPABILITY_OBJECT as i32, + capabilities.into(), + )); + }; + let version = font .head() .ok() diff --git a/src/fcfreetype.c b/src/fcfreetype.c index c030612..e9df07b 100644 --- a/src/fcfreetype.c +++ b/src/fcfreetype.c @@ -493,6 +493,8 @@ static const FcMacRomanFake fcMacRomanFake[] = { { TT_MS_LANGID_ENGLISH_UNITED_STATES, "ASCII" }, }; +static const char fcSilfCapability[] = "ttable:Silf"; + static FcChar8 * FcFontCapabilities (FT_Face face); @@ -2662,14 +2664,14 @@ FcFontCapabilities (FT_Face face) goto bail; maxsize = (((FT_ULong)gpos_count + (FT_ULong)gsub_count) * OTLAYOUT_LEN + - (issilgraphitefont ? 13 : 0)); + (issilgraphitefont ? strlen(fcSilfCapability) : 0)); complex_ = malloc (sizeof (FcChar8) * maxsize); if (!complex_) goto bail; complex_[0] = '\0'; if (issilgraphitefont) - strcpy ((char *)complex_, "ttable:Silf "); + strcpy ((char *)complex_, fcSilfCapability); while ((indx1 < gsub_count) || (indx2 < gpos_count)) { if (indx1 == gsub_count) { diff --git a/test/test_fontations_ft_query.py b/test/test_fontations_ft_query.py index 37a2aab..b7baf0b 100644 --- a/test/test_fontations_ft_query.py +++ b/test/test_fontations_ft_query.py @@ -65,6 +65,7 @@ def test_fontations_freetype_fcquery_equal(font_file): "weight", "width", "slant", + "capability", ] format_string = ":".join( "%{" + entity + "}" for entity in supported_format_entitites commit b4ca3b1fc7c8449a372ca16a44de91a305d3cbb4 Author: Dominik Röttsches <drott@xxxxxxxxxxxx> Date: Thu May 8 14:50:08 2025 +0300 Amend license headers diff --git a/fc-fontations/attributes.rs b/fc-fontations/attributes.rs index 41c853b..be12b83 100644 --- a/fc-fontations/attributes.rs +++ b/fc-fontations/attributes.rs @@ -1,4 +1,26 @@ -extern crate fc_fontations_bindgen; +/* + * fontconfig/fc-fontations/attributes.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::{ diff --git a/fc-fontations/instance_enumerate.rs b/fc-fontations/instance_enumerate.rs index 6f13bf9..84deb08 100644 --- a/fc-fontations/instance_enumerate.rs +++ b/fc-fontations/instance_enumerate.rs @@ -1,5 +1,5 @@ /* - * fontconfig/fc-fontations/mod.rs + * fontconfig/fc-fontations/instance_enumerate.rs * * Copyright 2025 Google LLC. *