tinymist_world/font/
memory.rs

1use std::sync::Arc;
2
3use rayon::iter::ParallelIterator;
4use typst::foundations::Bytes;
5use typst::text::{FontBook, FontInfo};
6
7use crate::debug_loc::{DataSource, MemoryDataSource};
8use crate::font::{BufferFontLoader, FontResolverImpl, FontSlot};
9
10/// A memory font searcher.
11#[derive(Debug)]
12pub struct MemoryFontSearcher {
13    pub fonts: Vec<(FontInfo, FontSlot)>,
14}
15
16impl Default for MemoryFontSearcher {
17    fn default() -> Self {
18        Self::new()
19    }
20}
21
22impl MemoryFontSearcher {
23    /// Creates an in-memory searcher.
24    pub fn new() -> Self {
25        Self { fonts: vec![] }
26    }
27
28    /// Adds an in-memory font.
29    pub fn add_memory_font(&mut self, data: Bytes) {
30        self.add_memory_fonts(rayon::iter::once(data));
31    }
32
33    /// Adds in-memory fonts.
34    pub fn add_memory_fonts(&mut self, data: impl ParallelIterator<Item = Bytes>) {
35        let source = DataSource::Memory(MemoryDataSource {
36            name: "<memory>".to_owned(),
37        });
38        self.extend_bytes(data.map(|data| (data, Some(source.clone()))));
39    }
40
41    /// Adds a number of raw font resources.
42    ///
43    /// Note: if you would like to reuse font resources across builds, use
44    /// [`Self::extend_bytes`] instead.
45    pub fn extend(&mut self, items: impl IntoIterator<Item = (FontInfo, FontSlot)>) {
46        self.fonts.extend(items);
47    }
48
49    /// Adds a number of font data to the font resolver. The builder will reuse
50    /// the existing font resources according to the bytes.
51    pub fn extend_bytes(
52        &mut self,
53        items: impl ParallelIterator<Item = (Bytes, Option<DataSource>)>,
54    ) {
55        let loaded = items.flat_map(|(data, desc)| {
56            let count = ttf_parser::fonts_in_collection(&data).unwrap_or(1);
57
58            let desc = desc.map(Arc::new);
59
60            (0..count)
61                .flat_map(|index| {
62                    let info = FontInfo::new(&data, index)?;
63                    let mut slot = FontSlot::new(BufferFontLoader {
64                        buffer: Some(data.clone()),
65                        index,
66                    });
67                    if let Some(desc) = desc.clone() {
68                        slot = slot.with_describe_arc(desc);
69                    }
70
71                    Some((info, slot))
72                })
73                .collect::<Vec<_>>()
74        });
75
76        self.extend(loaded.collect::<Vec<_>>());
77    }
78
79    /// Builds a FontResolverImpl.
80    pub fn build(self) -> FontResolverImpl {
81        let slots = self.fonts.iter().map(|(_, slot)| slot.clone()).collect();
82        let book = FontBook::from_infos(self.fonts.into_iter().map(|(info, _)| info));
83        FontResolverImpl::new(Vec::new(), book, slots)
84    }
85}
86
87#[deprecated(note = "use [`MemoryFontSearcher`] instead")]
88pub type MemoryFontBuilder = MemoryFontSearcher;