Detailed changes
@@ -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,
@@ -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,
@@ -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)
+ }
+}
@@ -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;
@@ -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};
@@ -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};
@@ -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 {
@@ -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,
@@ -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;
@@ -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 {