Re-export font_kit primitives from a new `fonts` module

Antonio Scandurra created

...also, rename the old `fonts` to `font_cache`.

Change summary

gpui/src/elements/label.rs     |   3 
gpui/src/elements/line_box.rs  |   3 
gpui/src/font_cache.rs         | 154 +++++++++++++++++++++++++++++++++++
gpui/src/fonts.rs              | 157 -----------------------------------
gpui/src/lib.rs                |   3 
gpui/src/platform/mac/fonts.rs |   7 -
gpui/src/platform/mod.rs       |   3 
gpui/src/presenter.rs          |   2 
zed/src/editor/buffer_view.rs  |   6 
zed/src/settings.rs            |   2 
10 files changed, 169 insertions(+), 171 deletions(-)

Detailed changes

gpui/src/elements/label.rs 🔗

@@ -1,6 +1,7 @@
 use crate::{
     color::ColorU,
-    fonts::{FamilyId, Properties},
+    font_cache::FamilyId,
+    fonts::Properties,
     geometry::vector::{vec2f, Vector2F},
     text_layout::Line,
     AfterLayoutContext, Element, Event, EventContext, LayoutContext, PaintContext, SizeConstraint,

gpui/src/elements/line_box.rs 🔗

@@ -1,5 +1,6 @@
 use crate::{
-    fonts::{FamilyId, FontId, Properties},
+    font_cache::FamilyId,
+    fonts::{FontId, Properties},
     geometry::vector::{vec2f, Vector2F},
     AfterLayoutContext, Element, ElementBox, Event, EventContext, LayoutContext, PaintContext,
     SizeConstraint,

gpui/src/font_cache.rs 🔗

@@ -0,0 +1,154 @@
+use crate::{
+    fonts::{FontId, Metrics, Properties},
+    geometry::vector::{vec2f, Vector2F},
+    platform,
+};
+use anyhow::{anyhow, Result};
+use parking_lot::{RwLock, RwLockUpgradableReadGuard};
+use std::{collections::HashMap, sync::Arc};
+
+#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)]
+pub struct FamilyId(usize);
+
+struct Family {
+    name: String,
+    font_ids: Vec<FontId>,
+}
+
+pub struct FontCache(RwLock<FontCacheState>);
+
+pub struct FontCacheState {
+    fonts: Arc<dyn platform::FontSystem>,
+    families: Vec<Family>,
+    font_selections: HashMap<FamilyId, HashMap<Properties, FontId>>,
+    metrics: HashMap<FontId, Metrics>,
+}
+
+unsafe impl Send for FontCache {}
+
+impl FontCache {
+    pub fn new(fonts: Arc<dyn platform::FontSystem>) -> Self {
+        Self(RwLock::new(FontCacheState {
+            fonts,
+            families: Vec::new(),
+            font_selections: HashMap::new(),
+            metrics: HashMap::new(),
+        }))
+    }
+
+    pub fn load_family(&self, names: &[&str]) -> Result<FamilyId> {
+        for name in names {
+            let state = self.0.upgradable_read();
+
+            if let Some(ix) = state.families.iter().position(|f| f.name == *name) {
+                return Ok(FamilyId(ix));
+            }
+
+            let mut state = RwLockUpgradableReadGuard::upgrade(state);
+
+            if let Ok(font_ids) = state.fonts.load_family(name) {
+                if font_ids.is_empty() {
+                    continue;
+                }
+
+                let family_id = FamilyId(state.families.len());
+                for font_id in &font_ids {
+                    if state.fonts.glyph_for_char(*font_id, 'm').is_none() {
+                        return Err(anyhow!("font must contain a glyph for the 'm' character"));
+                    }
+                }
+
+                state.families.push(Family {
+                    name: String::from(*name),
+                    font_ids,
+                });
+                return Ok(family_id);
+            }
+        }
+
+        Err(anyhow!(
+            "could not find a non-empty font family matching one of the given names"
+        ))
+    }
+
+    pub fn default_font(&self, family_id: FamilyId) -> FontId {
+        self.select_font(family_id, &Properties::default()).unwrap()
+    }
+
+    pub fn select_font(&self, family_id: FamilyId, properties: &Properties) -> Result<FontId> {
+        let inner = self.0.upgradable_read();
+        if let Some(font_id) = inner
+            .font_selections
+            .get(&family_id)
+            .and_then(|f| f.get(properties))
+        {
+            Ok(*font_id)
+        } else {
+            let mut inner = RwLockUpgradableReadGuard::upgrade(inner);
+            let family = &inner.families[family_id.0];
+            let font_id = inner
+                .fonts
+                .select_font(&family.font_ids, properties)
+                .unwrap_or(family.font_ids[0]);
+
+            inner
+                .font_selections
+                .entry(family_id)
+                .or_default()
+                .insert(properties.clone(), font_id);
+            Ok(font_id)
+        }
+    }
+
+    pub fn metric<F, T>(&self, font_id: FontId, f: F) -> T
+    where
+        F: FnOnce(&Metrics) -> T,
+        T: 'static,
+    {
+        let state = self.0.upgradable_read();
+        if let Some(metrics) = state.metrics.get(&font_id) {
+            f(metrics)
+        } else {
+            let metrics = state.fonts.font_metrics(font_id);
+            let metric = f(&metrics);
+            let mut state = RwLockUpgradableReadGuard::upgrade(state);
+            state.metrics.insert(font_id, metrics);
+            metric
+        }
+    }
+
+    pub fn bounding_box(&self, font_id: FontId, font_size: f32) -> Vector2F {
+        let bounding_box = self.metric(font_id, |m| m.bounding_box);
+        let width = self.scale_metric(bounding_box.width(), font_id, font_size);
+        let height = self.scale_metric(bounding_box.height(), font_id, font_size);
+        vec2f(width, height)
+    }
+
+    pub fn em_width(&self, font_id: FontId, font_size: f32) -> f32 {
+        let state = self.0.read();
+        let glyph_id = state.fonts.glyph_for_char(font_id, 'm').unwrap();
+        let bounds = state.fonts.typographic_bounds(font_id, glyph_id).unwrap();
+        self.scale_metric(bounds.width(), font_id, font_size)
+    }
+
+    pub fn line_height(&self, font_id: FontId, font_size: f32) -> f32 {
+        let bounding_box = self.metric(font_id, |m| m.bounding_box);
+        self.scale_metric(bounding_box.height(), font_id, font_size)
+    }
+
+    pub fn cap_height(&self, font_id: FontId, font_size: f32) -> f32 {
+        self.scale_metric(self.metric(font_id, |m| m.cap_height), font_id, font_size)
+    }
+
+    pub fn ascent(&self, font_id: FontId, font_size: f32) -> f32 {
+        self.scale_metric(self.metric(font_id, |m| m.ascent), font_id, font_size)
+    }
+
+    pub fn descent(&self, font_id: FontId, font_size: f32) -> f32 {
+        self.scale_metric(self.metric(font_id, |m| m.descent), font_id, font_size)
+    }
+
+    pub fn scale_metric(&self, metric: f32, font_id: FontId, font_size: f32) -> f32 {
+        metric * font_size / self.metric(font_id, |m| m.units_per_em as f32)
+    }
+}

gpui/src/fonts.rs 🔗

@@ -1,160 +1,7 @@
-use crate::{
-    geometry::vector::{vec2f, Vector2F},
-    platform,
-};
-use anyhow::{anyhow, Result};
-use font_kit::metrics::Metrics;
+pub use font_kit::metrics::Metrics;
 pub use font_kit::properties::{Properties, Weight};
-use parking_lot::{RwLock, RwLockUpgradableReadGuard};
-use std::{collections::HashMap, sync::Arc};
-
-pub type GlyphId = u32;
-
-#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)]
-pub struct FamilyId(usize);
 
 #[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)]
 pub struct FontId(pub usize);
 
-pub struct FontCache(RwLock<FontCacheState>);
-
-pub struct FontCacheState {
-    fonts: Arc<dyn platform::FontSystem>,
-    families: Vec<Family>,
-    font_selections: HashMap<FamilyId, HashMap<Properties, FontId>>,
-    metrics: HashMap<FontId, Metrics>,
-}
-
-unsafe impl Send for FontCache {}
-
-struct Family {
-    name: String,
-    font_ids: Vec<FontId>,
-}
-
-impl FontCache {
-    pub fn new(fonts: Arc<dyn platform::FontSystem>) -> Self {
-        Self(RwLock::new(FontCacheState {
-            fonts,
-            families: Vec::new(),
-            font_selections: HashMap::new(),
-            metrics: HashMap::new(),
-        }))
-    }
-
-    pub fn load_family(&self, names: &[&str]) -> Result<FamilyId> {
-        for name in names {
-            let state = self.0.upgradable_read();
-
-            if let Some(ix) = state.families.iter().position(|f| f.name == *name) {
-                return Ok(FamilyId(ix));
-            }
-
-            let mut state = RwLockUpgradableReadGuard::upgrade(state);
-
-            if let Ok(font_ids) = state.fonts.load_family(name) {
-                if font_ids.is_empty() {
-                    continue;
-                }
-
-                let family_id = FamilyId(state.families.len());
-                for font_id in &font_ids {
-                    if state.fonts.glyph_for_char(*font_id, 'm').is_none() {
-                        return Err(anyhow!("font must contain a glyph for the 'm' character"));
-                    }
-                }
-
-                state.families.push(Family {
-                    name: String::from(*name),
-                    font_ids,
-                });
-                return Ok(family_id);
-            }
-        }
-
-        Err(anyhow!(
-            "could not find a non-empty font family matching one of the given names"
-        ))
-    }
-
-    pub fn default_font(&self, family_id: FamilyId) -> FontId {
-        self.select_font(family_id, &Properties::default()).unwrap()
-    }
-
-    pub fn select_font(&self, family_id: FamilyId, properties: &Properties) -> Result<FontId> {
-        let inner = self.0.upgradable_read();
-        if let Some(font_id) = inner
-            .font_selections
-            .get(&family_id)
-            .and_then(|f| f.get(properties))
-        {
-            Ok(*font_id)
-        } else {
-            let mut inner = RwLockUpgradableReadGuard::upgrade(inner);
-            let family = &inner.families[family_id.0];
-            let font_id = inner
-                .fonts
-                .select_font(&family.font_ids, properties)
-                .unwrap_or(family.font_ids[0]);
-
-            inner
-                .font_selections
-                .entry(family_id)
-                .or_default()
-                .insert(properties.clone(), font_id);
-            Ok(font_id)
-        }
-    }
-
-    pub fn metric<F, T>(&self, font_id: FontId, f: F) -> T
-    where
-        F: FnOnce(&Metrics) -> T,
-        T: 'static,
-    {
-        let state = self.0.upgradable_read();
-        if let Some(metrics) = state.metrics.get(&font_id) {
-            f(metrics)
-        } else {
-            let metrics = state.fonts.font_metrics(font_id);
-            let metric = f(&metrics);
-            let mut state = RwLockUpgradableReadGuard::upgrade(state);
-            state.metrics.insert(font_id, metrics);
-            metric
-        }
-    }
-
-    pub fn bounding_box(&self, font_id: FontId, font_size: f32) -> Vector2F {
-        let bounding_box = self.metric(font_id, |m| m.bounding_box);
-        let width = self.scale_metric(bounding_box.width(), font_id, font_size);
-        let height = self.scale_metric(bounding_box.height(), font_id, font_size);
-        vec2f(width, height)
-    }
-
-    pub fn em_width(&self, font_id: FontId, font_size: f32) -> f32 {
-        let state = self.0.read();
-        let glyph_id = state.fonts.glyph_for_char(font_id, 'm').unwrap();
-        let bounds = state.fonts.typographic_bounds(font_id, glyph_id).unwrap();
-        self.scale_metric(bounds.width(), font_id, font_size)
-    }
-
-    pub fn line_height(&self, font_id: FontId, font_size: f32) -> f32 {
-        let bounding_box = self.metric(font_id, |m| m.bounding_box);
-        self.scale_metric(bounding_box.height(), font_id, font_size)
-    }
-
-    pub fn cap_height(&self, font_id: FontId, font_size: f32) -> f32 {
-        self.scale_metric(self.metric(font_id, |m| m.cap_height), font_id, font_size)
-    }
-
-    pub fn ascent(&self, font_id: FontId, font_size: f32) -> f32 {
-        self.scale_metric(self.metric(font_id, |m| m.ascent), font_id, font_size)
-    }
-
-    pub fn descent(&self, font_id: FontId, font_size: f32) -> f32 {
-        self.scale_metric(self.metric(font_id, |m| m.descent), font_id, font_size)
-    }
-
-    pub fn scale_metric(&self, metric: f32, font_id: FontId, font_size: f32) -> f32 {
-        metric * font_size / self.metric(font_id, |m| m.units_per_em as f32)
-    }
-}
+pub type GlyphId = u32;

gpui/src/lib.rs 🔗

@@ -3,8 +3,9 @@ pub use app::*;
 mod assets;
 pub use assets::*;
 pub mod elements;
+pub mod font_cache;
+pub use font_cache::FontCache;
 pub mod fonts;
-pub use fonts::FontCache;
 mod presenter;
 mod scene;
 pub use scene::{Border, Scene};

gpui/src/platform/mac/fonts.rs 🔗

@@ -1,5 +1,5 @@
 use crate::{
-    fonts::{FontId, GlyphId},
+    fonts::{FontId, GlyphId, Metrics, Properties},
     geometry::{
         rect::{RectF, RectI},
         transform2d::Transform2F,
@@ -19,10 +19,7 @@ use core_graphics::{
     base::CGGlyph, color_space::CGColorSpace, context::CGContext, geometry::CGAffineTransform,
 };
 use core_text::{line::CTLine, string_attributes::kCTFontAttributeName};
-use font_kit::{
-    canvas::RasterizationOptions, hinting::HintingOptions, metrics::Metrics,
-    properties::Properties, source::SystemSource,
-};
+use font_kit::{canvas::RasterizationOptions, hinting::HintingOptions, source::SystemSource};
 use parking_lot::RwLock;
 use std::{char, convert::TryFrom};
 

gpui/src/platform/mod.rs 🔗

@@ -8,7 +8,7 @@ pub mod current {
 
 use crate::{
     executor,
-    fonts::{FontId, GlyphId},
+    fonts::{FontId, GlyphId, Metrics as FontMetrics, Properties as FontProperties},
     geometry::{
         rect::{RectF, RectI},
         vector::Vector2F,
@@ -19,7 +19,6 @@ use crate::{
 use anyhow::Result;
 use async_task::Runnable;
 pub use event::Event;
-use font_kit::{metrics::Metrics as FontMetrics, properties::Properties as FontProperties};
 use std::{ops::Range, path::PathBuf, rc::Rc, sync::Arc};
 
 pub trait Runner {

gpui/src/presenter.rs 🔗

@@ -1,7 +1,7 @@
 use crate::{
     app::{AppContext, MutableAppContext, WindowInvalidation},
     elements::Element,
-    fonts::FontCache,
+    font_cache::FontCache,
     platform::{self, Event},
     text_layout::TextLayoutCache,
     AssetCache, ElementBox, Scene,

zed/src/editor/buffer_view.rs 🔗

@@ -6,10 +6,8 @@ use crate::{settings::Settings, watch, workspace};
 use anyhow::Result;
 use easy_parallel::Parallel;
 use gpui::{
-    fonts::{FontCache, Properties as FontProperties},
-    keymap::Binding,
-    text_layout, App, AppContext, Element, ElementBox, Entity, ModelHandle, View, ViewContext,
-    WeakViewHandle,
+    fonts::Properties as FontProperties, keymap::Binding, text_layout, App, AppContext, Element,
+    ElementBox, Entity, FontCache, ModelHandle, View, ViewContext, WeakViewHandle,
 };
 use gpui::{geometry::vector::Vector2F, TextLayoutCache};
 use parking_lot::Mutex;

zed/src/settings.rs 🔗

@@ -1,6 +1,6 @@
 use crate::watch;
 use anyhow::Result;
-use gpui::fonts::{FamilyId, FontCache};
+use gpui::font_cache::{FamilyId, FontCache};
 
 #[derive(Clone)]
 pub struct Settings {