Merge pull request #5497 from storytold/fix/sec-font-name-records

Fonts: cap the name records and decoded bytes read per name id
This commit is contained in:
BFlat
2026-11-04 11:13:41 +07:00
committed by GitHub
+29 -1
View File
@@ -76,9 +76,23 @@ pub(super) fn name(font: &skrifa::FontRef<'_>, ids: &[StringId]) -> Option<Strin
/// The most distinct legacy family (and style) names of a font used as keys.
pub(super) const MAX_LEGACY_NAMES: usize = 64;
/// Records can share their encoded bytes, so a small table names many long strings: stop at this
/// many records or decoded bytes (real fonts have a few dozen short names per id).
const MAX_NAME_RECORDS: usize = 1024;
const MAX_NAME_BYTES: usize = 1 << 20;
/// Every localized string of `id`, with its language.
pub(super) fn localized(font: &skrifa::FontRef<'_>, id: StringId) -> Vec<(Option<String>, String)> {
font.localized_strings(id).map(|s| (s.language().map(str::to_owned), s.to_string())).filter(|(_, s)| !s.is_empty()).collect()
let mut bytes = 0usize;
font.localized_strings(id)
.take(MAX_NAME_RECORDS)
.map(|s| (s.language().map(str::to_owned), s.to_string()))
.take_while(|(_, s)| {
bytes = bytes.saturating_add(s.len());
bytes <= MAX_NAME_BYTES
})
.filter(|(_, s)| !s.is_empty())
.collect()
}
/// Whether a name-table language tag is English (Illustrator's "Show Font Names in English").
@@ -119,3 +133,17 @@ pub(super) fn norm_chars(s: &str) -> impl Iterator<Item = char> + '_ {
pub(super) fn norm(s: &str) -> String {
norm_chars(s).collect()
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn a_name_table_of_many_records_is_cut_short() {
let many: Vec<(u16, &str)> = (0..2000).map(|_| (1, "Short")).collect();
let name = crate::test_fonts::name_table(&many).unwrap_or_default();
let font = crate::fontdb::sfnt_of(&[(b"name", &name)]).unwrap_or_default();
let font = skrifa::FontRef::new(&font).unwrap();
assert_eq!(localized(&font, StringId::FAMILY_NAME).len(), MAX_NAME_RECORDS);
}
}