summaryrefslogtreecommitdiff
path: root/src/font/loader.rs
diff options
context:
space:
mode:
authorLaurenz <laurmaedje@gmail.com>2019-10-09 19:45:40 +0200
committerLaurenz <laurmaedje@gmail.com>2019-10-09 19:46:42 +0200
commitf22a3070001e9c8db6fcc7b83b036111a6559a3d (patch)
treea14c437a2ef71b08af5847c4f38330f668f724c2 /src/font/loader.rs
parentb96a7e0cf3c97463ecb746d859b675541a427774 (diff)
Extract into separate repository 🧱
Diffstat (limited to 'src/font/loader.rs')
-rw-r--r--src/font/loader.rs165
1 files changed, 0 insertions, 165 deletions
diff --git a/src/font/loader.rs b/src/font/loader.rs
deleted file mode 100644
index a0e2dce1..00000000
--- a/src/font/loader.rs
+++ /dev/null
@@ -1,165 +0,0 @@
-//! Loading of fonts matching queries.
-
-use std::cell::{RefCell, Ref};
-use std::collections::HashMap;
-use std::fmt::{self, Debug, Formatter};
-
-use super::{Font, FontInfo, FontClass, FontProvider};
-
-
-/// Serves fonts matching queries.
-pub struct FontLoader<'p> {
- /// The font providers.
- providers: Vec<Box<dyn FontProvider + 'p>>,
- /// The internal state. Uses interior mutability because the loader works behind
- /// an immutable reference to ease usage.
- state: RefCell<FontLoaderState>,
-}
-
-/// Internal state of the font loader (seperated to wrap it in a `RefCell`).
-struct FontLoaderState {
- /// The loaded fonts alongside their external indices. Some fonts may not
- /// have external indices because they were loaded but did not contain the
- /// required character. However, these are still stored because they may
- /// be needed later. The index is just set to `None` then.
- fonts: Vec<(Option<usize>, Font)>,
- /// Allows to retrieve a font (index) quickly if a query was submitted before.
- query_cache: HashMap<FontQuery, usize>,
- /// Allows to re-retrieve loaded fonts by their info instead of loading them again.
- info_cache: HashMap<FontInfo, usize>,
- /// Indexed by external indices (the ones inside the tuples in the `fonts` vector)
- /// and maps to internal indices (the actual indices into the vector).
- inner_index: Vec<usize>,
-}
-
-impl<'p> FontLoader<'p> {
- /// Create a new font loader.
- pub fn new() -> FontLoader<'p> {
- FontLoader {
- providers: vec![],
- state: RefCell::new(FontLoaderState {
- query_cache: HashMap::new(),
- info_cache: HashMap::new(),
- inner_index: vec![],
- fonts: vec![],
- }),
- }
- }
-
- /// Add a font provider to this loader.
- pub fn add_font_provider<P: FontProvider + 'p>(&mut self, provider: P) {
- self.providers.push(Box::new(provider));
- }
-
- /// Returns the font (and its index) best matching the query, if there is any.
- pub fn get(&self, query: FontQuery) -> Option<(usize, Ref<Font>)> {
- // Load results from the cache, if we had the exact same query before.
- let state = self.state.borrow();
- if let Some(&index) = state.query_cache.get(&query) {
- // The font must have an external index already because it is in the query cache.
- // It has been served before.
- let extern_index = state.fonts[index].0.unwrap();
- let font = Ref::map(state, |s| &s.fonts[index].1);
-
- return Some((extern_index, font));
- }
- drop(state);
-
- // The outermost loop goes over the fallbacks because we want to serve the
- // font that matches the first possible class.
- for class in &query.fallback {
- // For each class now go over all fonts from all font providers.
- for provider in &self.providers {
- for info in provider.available().iter() {
- let viable = info.classes.contains(class);
- let matches = viable && query.classes.iter()
- .all(|class| info.classes.contains(class));
-
- if matches {
- let mut state = self.state.borrow_mut();
-
- // Check if we have already loaded this font before, otherwise,
- // we will load it from the provider.
- let index = if let Some(&index) = state.info_cache.get(info) {
- index
- } else if let Some(mut source) = provider.get(info) {
- let mut program = Vec::new();
- source.read_to_end(&mut program).ok()?;
- let font = Font::new(program).ok()?;
-
- // Insert it into the storage and cache it by its info.
- let index = state.fonts.len();
- state.info_cache.insert(info.clone(), index);
- state.fonts.push((None, font));
-
- index
- } else {
- // Strangely, this provider lied and cannot give us the promised font.
- continue;
- };
-
- // Proceed if this font has the character we need.
- let has_char = state.fonts[index].1.mapping.contains_key(&query.character);
- if has_char {
- // This font is suitable, thus we cache the query result.
- state.query_cache.insert(query, index);
-
- // Now we have to find out the external index of it or assign
- // a new one if it has none.
- let external_index = state.fonts[index].0.unwrap_or_else(|| {
- // We have to assign an external index before serving.
- let new_index = state.inner_index.len();
- state.inner_index.push(index);
- state.fonts[index].0 = Some(new_index);
- new_index
- });
-
- // Release the mutable borrow to be allowed to borrow immutably.
- drop(state);
-
- // Finally, get a reference to the actual font.
- let font = Ref::map(self.state.borrow(), |s| &s.fonts[index].1);
- return Some((external_index, font));
- }
- }
- }
- }
- }
-
- // Not a single match!
- None
- }
-
- /// Return the font previously loaded at this index.
- /// Panics if the index is not assigned.
- #[inline]
- pub fn get_with_index(&self, index: usize) -> Ref<Font> {
- let state = self.state.borrow();
- let internal = state.inner_index[index];
- Ref::map(state, |s| &s.fonts[internal].1)
- }
-}
-
-impl Debug for FontLoader<'_> {
- fn fmt(&self, f: &mut Formatter) -> fmt::Result {
- let state = self.state.borrow();
- f.debug_struct("FontLoader")
- .field("providers", &self.providers.len())
- .field("fonts", &state.fonts)
- .field("query_cache", &state.query_cache)
- .field("info_cache", &state.info_cache)
- .field("inner_index", &state.inner_index)
- .finish()
- }
-}
-
-/// A query for a font with specific properties.
-#[derive(Debug, Clone, Eq, PartialEq, Hash)]
-pub struct FontQuery {
- /// Which character is needed.
- pub character: char,
- /// Which classes the font has to be part of.
- pub classes: Vec<FontClass>,
- /// The font matching the leftmost class in this sequence should be returned.
- pub fallback: Vec<FontClass>,
-}