fonts: Have CoreTextFontCache::core_text_font return a PlatformFont (#38758)

This will make it easier in a followup to include the normalized font
variations in the return value. This also make
`PlatformFont::ensure_h_kern_subtable` work on the instance instead of
being a struct method. Finally, all `PlatformFont` methods are combined
into a single impl block.

Testing: This should not change behavior and is thus covered by existing
tests.

Signed-off-by: Martin Robinson <mrobinson@igalia.com>
This commit is contained in:
Martin Robinson 2025-08-18 05:32:20 -07:00 committed by GitHub
parent 6fdf40dce7
commit 5c885d61ad
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 45 additions and 36 deletions

View file

@ -17,6 +17,7 @@ use core_text::font_descriptor::kCTFontURLAttribute;
use parking_lot::RwLock;
use crate::FontData;
use crate::platform::font::PlatformFont;
use crate::system_font_service::FontIdentifier;
/// A cache of `CTFont` to avoid having to create `CTFont` instances over and over. It is
@ -36,7 +37,7 @@ impl CoreTextFontCache {
font_identifier: FontIdentifier,
data: Option<&FontData>,
pt_size: f64,
) -> Option<CTFont> {
) -> Option<PlatformFont> {
//// If you pass a zero font size to one of the Core Text APIs, it'll replace it with
//// 12.0. We don't want that! (Issue #10492.)
let clamped_pt_size = pt_size.max(0.01);
@ -49,7 +50,7 @@ impl CoreTextFontCache {
.get(&font_identifier)
.and_then(|identifier_cache| identifier_cache.get(&au_size))
{
return Some(core_text_font.clone());
return Some(PlatformFont::new_with_ctfont(core_text_font.clone()));
}
}
@ -60,7 +61,7 @@ impl CoreTextFontCache {
// on the cache has been acquired, the cache was populated with the data that we need. Thus
// check again and return the CTFont if it is is already cached.
if let Some(core_text_font) = identifier_cache.get(&au_size) {
return Some(core_text_font.clone());
return Some(PlatformFont::new_with_ctfont(core_text_font.clone()));
}
let core_text_font = match font_identifier {
@ -98,6 +99,6 @@ impl CoreTextFontCache {
};
identifier_cache.insert(au_size, core_text_font.clone());
Some(core_text_font)
Some(PlatformFont::new_with_ctfont(core_text_font))
}
}

View file

@ -70,10 +70,43 @@ unsafe impl Sync for PlatformFont {}
unsafe impl Send for PlatformFont {}
impl PlatformFont {
pub(crate) fn new_with_ctfont(ctfont: CTFont) -> Self {
Self {
ctfont,
h_kern_subtable: None,
}
}
fn new(
font_identifier: FontIdentifier,
data: Option<&FontData>,
requested_size: Option<Au>,
) -> Result<PlatformFont, &'static str> {
let size = match requested_size {
Some(s) => s.to_f64_px(),
None => 0.0,
};
let Some(mut platform_font) =
CoreTextFontCache::core_text_font(font_identifier, data, size)
else {
return Err("Could not generate CTFont for FontTemplateData");
};
platform_font.load_h_kern_subtable();
Ok(platform_font)
}
/// Cache all the data needed for basic horizontal kerning. This is used only as a fallback or
/// fast path (when the GPOS table is missing or unnecessary) so it needn't handle every case.
fn find_h_kern_subtable(&self) -> Option<CachedKernTable> {
let font_table = self.table_for_tag(KERN)?;
fn load_h_kern_subtable(&mut self) {
if self.h_kern_subtable.is_some() {
return;
}
let Some(font_table) = self.table_for_tag(KERN) else {
return;
};
let mut result = CachedKernTable {
font_table,
pair_data_range: 0..0,
@ -89,7 +122,7 @@ impl PlatformFont {
let table = result.font_table.buffer();
let version = BigEndian::read_u16(table);
if version != 0 {
return None;
return;
}
let num_subtables = BigEndian::read_u16(&table[2..]);
let mut start = 4;
@ -102,7 +135,7 @@ impl PlatformFont {
// Found a matching subtable.
if !result.pair_data_range.is_empty() {
debug!("Found multiple horizontal kern tables. Disable fast path.");
return None;
return;
}
// Read the subtable header.
let subtable_start = start + SUBTABLE_HEADER_LEN;
@ -112,7 +145,7 @@ impl PlatformFont {
result.pair_data_range = pair_data_start..end;
if result.pair_data_range.len() != n_pairs * KERN_PAIR_LEN {
debug!("Bad data in kern header. Disable fast path.");
return None;
return;
}
let pt_per_font_unit =
@ -122,10 +155,9 @@ impl PlatformFont {
start = end;
}
}
if !result.pair_data_range.is_empty() {
Some(result)
} else {
None
self.h_kern_subtable = Some(result);
}
}
}
@ -164,30 +196,6 @@ impl fmt::Debug for CachedKernTable {
}
}
impl PlatformFont {
fn new(
font_identifier: FontIdentifier,
data: Option<&FontData>,
requested_size: Option<Au>,
) -> Result<PlatformFont, &'static str> {
let size = match requested_size {
Some(s) => s.to_f64_px(),
None => 0.0,
};
let Some(core_text_font) = CoreTextFontCache::core_text_font(font_identifier, data, size)
else {
return Err("Could not generate CTFont for FontTemplateData");
};
let mut handle = PlatformFont {
ctfont: core_text_font.clone_with_font_size(size),
h_kern_subtable: None,
};
handle.h_kern_subtable = handle.find_h_kern_subtable();
Ok(handle)
}
}
impl PlatformFontMethods for PlatformFont {
fn new_from_data(
font_identifier: FontIdentifier,