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

@ -12,6 +12,7 @@ name = "fonts_traits"
path = "lib.rs"
[dependencies]
ipc-channel = { workspace = true }
malloc_size_of = { workspace = true }
malloc_size_of_derive = { workspace = true }
range = { path = "../../range" }

View file

@ -6,6 +6,7 @@
use std::sync::Arc;
use ipc_channel::ipc::IpcSharedMemory;
use malloc_size_of_derive::MallocSizeOf;
use range::{RangeIndex, int_range_index};
use serde::{Deserialize, Serialize};
@ -18,3 +19,42 @@ int_range_index! {
}
pub type StylesheetWebFontLoadFinishedCallback = Arc<dyn Fn(bool) + Send + Sync + 'static>;
/// A data structure to store data for fonts. Data is stored internally in an
/// [`IpcSharedMemory`] handle, so that it can be sent without serialization
/// across IPC channels.
#[derive(Clone, MallocSizeOf)]
pub struct FontData(#[conditional_malloc_size_of] pub(crate) Arc<IpcSharedMemory>);
impl FontData {
pub fn from_bytes(bytes: &[u8]) -> Self {
Self(Arc::new(IpcSharedMemory::from_bytes(bytes)))
}
pub fn as_ipc_shared_memory(&self) -> Arc<IpcSharedMemory> {
self.0.clone()
}
}
impl AsRef<[u8]> for FontData {
fn as_ref(&self) -> &[u8] {
&self.0
}
}
/// Raw font data and an index
///
/// If the font data is of a TTC (TrueType collection) file, then the index of a specific font within
/// the collection. If the font data is for is single font then the index will always be 0.
#[derive(Clone)]
pub struct FontDataAndIndex {
/// The raw font file data (.ttf, .otf, .ttc, etc)
pub data: FontData,
/// The index of the font within the file (0 if the file is not a ttc)
pub index: u32,
}
#[derive(Copy, Clone, PartialEq)]
pub enum FontDataError {
FailedToLoad,
}