tinymist_world/font/
memory.rs

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