Fix loading raw data from .ttc files on macos (#38753)

# Objective

Ensure that functionality which uses the raw font data (such as
rendering text to canvas) works correctly on macOS when the specified
font is a system font that lives in an OpenType Collection (`.ttc`)
file.

## Changes made

- The `read_data_from_file` in each backend now returns a `index: u32`
in addition to `data: Vec<u8>`
- The `data` field on the `Font` type has been renamed to `raw` and the
`data` method on the `Font` type has been renamed to `raw_font`. This
allows the index to be cached as computing is moderately expensive on
macOS (on the order of 100 microseconds).
- Both of the above now store/return a `struct RawFont` instead of a
`FontData` where `RawFont` is defined as `struct RawFont { data:
FontData, index: u32 }`.
- The users of the `data` method have been updated to use the cached
index from `data` rather than calling `.index()` each time.

---------

Signed-off-by: Nico Burns <nico@nicoburns.com>
This commit is contained in:
Nico Burns 2025-08-19 12:57:48 +01:00 committed by GitHub
parent 3225d19907
commit 39629560c8
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
13 changed files with 164 additions and 76 deletions

View file

@ -15,8 +15,8 @@ use style::values::specified::font::FontStretchKeyword;
use webrender_api::NativeFontHandle;
use crate::{
EmojiPresentationPreference, FallbackFontSelectionOptions, FontIdentifier, FontTemplate,
FontTemplateDescriptor, LowercaseFontFamilyName,
EmojiPresentationPreference, FallbackFontSelectionOptions, FontData, FontDataAndIndex,
FontIdentifier, FontTemplate, FontTemplateDescriptor, LowercaseFontFamilyName,
};
pub fn for_each_available_family<F>(mut callback: F)
@ -67,14 +67,19 @@ impl LocalFontIdentifier {
}
}
pub(crate) fn read_data_from_file(&self) -> Option<Vec<u8>> {
pub(crate) fn font_data_and_index(&self) -> Option<FontDataAndIndex> {
let font = FontCollection::system()
.font_from_descriptor(&self.font_descriptor)
.ok()??;
let face = font.create_font_face();
let index = face.get_index();
let files = face.get_files();
assert!(!files.is_empty());
Some(files[0].get_font_file_bytes())
let data = files[0].get_font_file_bytes();
let data = FontData::from_bytes(&data);
Some(FontDataAndIndex { data, index })
}
}