This commit is contained in:
Jeremy Soller 2024-01-17 13:26:39 -07:00
parent 329941c4a6
commit a11f68f13d
6 changed files with 66 additions and 26 deletions

View file

@ -534,7 +534,11 @@ impl Buffer {
} }
/// Set monospace width monospace glyphs should be resized to match. `None` means don't resize /// Set monospace width monospace glyphs should be resized to match. `None` means don't resize
pub fn set_monospace_width(&mut self, font_system: &mut FontSystem, monospace_width: Option<f32>) { pub fn set_monospace_width(
&mut self,
font_system: &mut FontSystem,
monospace_width: Option<f32>,
) {
if monospace_width != self.monospace_width { if monospace_width != self.monospace_width {
self.monospace_width = monospace_width; self.monospace_width = monospace_width;
self.relayout(font_system); self.relayout(font_system);

View file

@ -210,7 +210,15 @@ impl BufferLine {
let align = self.align; let align = self.align;
let shape = self.shape_in_buffer(scratch, font_system); let shape = self.shape_in_buffer(scratch, font_system);
let mut layout = Vec::with_capacity(1); let mut layout = Vec::with_capacity(1);
shape.layout_to_buffer(scratch, font_size, width, wrap, align, &mut layout, match_mono_width); shape.layout_to_buffer(
scratch,
font_size,
width,
wrap,
align,
&mut layout,
match_mono_width,
);
self.layout_opt = Some(layout); self.layout_opt = Some(layout);
} }
self.layout_opt.as_ref().expect("layout not found") self.layout_opt.as_ref().expect("layout not found")

View file

@ -1,13 +1,13 @@
// SPDX-License-Identifier: MIT OR Apache-2.0 // SPDX-License-Identifier: MIT OR Apache-2.0
use alloc::collections::BTreeSet;
use alloc::sync::Arc; use alloc::sync::Arc;
#[cfg(not(feature = "std"))] #[cfg(not(feature = "std"))]
use alloc::vec::Vec; use alloc::vec::Vec;
use alloc::collections::BTreeSet;
use fontdb::Family; use fontdb::Family;
use unicode_script::Script; use unicode_script::Script;
use crate::{Font, FontSystem, ShapePlanCache, FontMatchKey}; use crate::{Font, FontMatchKey, FontSystem, ShapePlanCache};
use self::platform::*; use self::platform::*;
@ -138,9 +138,11 @@ impl<'a> Iterator for FontFallbackIter<'a> {
} }
} }
let font_match_keys_iter = |is_mono| self.font_match_keys let font_match_keys_iter = |is_mono| {
self.font_match_keys
.iter() .iter()
.filter(move |m_key| m_key.weight_offset == 0 || is_mono); .filter(move |m_key| m_key.weight_offset == 0 || is_mono)
};
while self.default_i < self.default_families.len() { while self.default_i < self.default_families.len() {
self.default_i += 1; self.default_i += 1;
@ -160,7 +162,7 @@ impl<'a> Iterator for FontFallbackIter<'a> {
let fallback_info = MonospaceFallbackInfo { let fallback_info = MonospaceFallbackInfo {
weight_offset: None, weight_offset: None,
script_non_matches: None, script_non_matches: None,
id: m_key.id id: m_key.id,
}; };
assert_eq!(self.monospace_fallbacks.insert(fallback_info), true); assert_eq!(self.monospace_fallbacks.insert(fallback_info), true);
} }
@ -168,25 +170,33 @@ impl<'a> Iterator for FontFallbackIter<'a> {
} }
// Set a monospace fallback if Monospace family is not found // Set a monospace fallback if Monospace family is not found
if is_mono { if is_mono {
let script_tags = self.scripts.iter() let script_tags = self
.scripts
.iter()
.filter_map(|script| { .filter_map(|script| {
let script_as_lower = script.short_name().to_lowercase(); let script_as_lower = script.short_name().to_lowercase();
<[u8; 4]>::try_from(script_as_lower.as_bytes()).ok() <[u8; 4]>::try_from(script_as_lower.as_bytes()).ok()
}).collect::<Vec<_>>(); })
.collect::<Vec<_>>();
if let Some(face_info) = self.font_system.db().face(m_key.id) { if let Some(face_info) = self.font_system.db().face(m_key.id) {
// Don't use emoji fonts as Monospace // Don't use emoji fonts as Monospace
if face_info.monospaced && !face_info.post_script_name.contains("Emoji") { if face_info.monospaced && !face_info.post_script_name.contains("Emoji") {
if let Some(font) = self.font_system.get_font(m_key.id) { if let Some(font) = self.font_system.get_font(m_key.id) {
let script_non_matches = self.scripts.len() - script_tags.iter() let script_non_matches = self.scripts.len()
.filter(|&&script_tag| { - script_tags
font.scripts().iter().any(|&tag_bytes| tag_bytes == script_tag) .iter()
}).count(); .filter(|&&script_tag| {
font.scripts()
.iter()
.any(|&tag_bytes| tag_bytes == script_tag)
})
.count();
let fallback_info = MonospaceFallbackInfo { let fallback_info = MonospaceFallbackInfo {
weight_offset: Some(m_key.weight_offset), weight_offset: Some(m_key.weight_offset),
script_non_matches: Some(script_non_matches), script_non_matches: Some(script_non_matches),
id: m_key.id id: m_key.id,
}; };
assert_eq!(self.monospace_fallbacks.insert(fallback_info), true); assert_eq!(self.monospace_fallbacks.insert(fallback_info), true);
} }

View file

@ -78,17 +78,23 @@ impl Font {
let (monospace_em_width, scripts) = { let (monospace_em_width, scripts) = {
db.with_face_data(id, |font_data, face_index| { db.with_face_data(id, |font_data, face_index| {
let face = ttf_parser::Face::parse(font_data, face_index).ok()?; let face = ttf_parser::Face::parse(font_data, face_index).ok()?;
let monospace_em_width = info.monospaced.then(|| { let monospace_em_width = info
let hor_advance = face.glyph_hor_advance(face.glyph_index(' ')?)? as f32; .monospaced
let upem = face.units_per_em() as f32; .then(|| {
Some(hor_advance/upem) let hor_advance = face.glyph_hor_advance(face.glyph_index(' ')?)? as f32;
}).flatten(); let upem = face.units_per_em() as f32;
Some(hor_advance / upem)
})
.flatten();
if info.monospaced && monospace_em_width.is_none() { if info.monospaced && monospace_em_width.is_none() {
None?; None?;
} }
let scripts = face.tables().gpos.into_iter() let scripts = face
.tables()
.gpos
.into_iter()
.chain(face.tables().gsub) .chain(face.tables().gsub)
.map(|table| table.scripts) .map(|table| table.scripts)
.flatten() .flatten()

View file

@ -120,7 +120,10 @@ impl FontSystem {
match Font::new(&self.db, id) { match Font::new(&self.db, id) {
Some(font) => Some(Arc::new(font)), Some(font) => Some(Arc::new(font)),
None => { None => {
log::warn!("failed to load font '{}'", self.db.face(id)?.post_script_name); log::warn!(
"failed to load font '{}'",
self.db.face(id)?.post_script_name
);
None None
} }
} }
@ -140,7 +143,10 @@ impl FontSystem {
.db .db
.faces() .faces()
.filter(|face| attrs.matches(face)) .filter(|face| attrs.matches(face))
.map(|face| FontMatchKey{ weight_offset: attrs.weight.0 - face.weight.0, id: face.id }) .map(|face| FontMatchKey {
weight_offset: attrs.weight.0 - face.weight.0,
id: face.id,
})
.collect::<Vec<_>>(); .collect::<Vec<_>>();
// Sort so we get the keys with weight_offset=0 first // Sort so we get the keys with weight_offset=0 first

View file

@ -1247,12 +1247,18 @@ impl ShapeLine {
let match_mono_em_width = match_mono_width.map(|w| w / font_size); let match_mono_em_width = match_mono_width.map(|w| w / font_size);
for glyph in included_glyphs { for glyph in included_glyphs {
let glyph_font_size = match(match_mono_em_width, glyph.font_monospace_em_width) { let glyph_font_size = match (
(Some(match_em_width), Some(glyph_em_width)) if glyph_em_width != match_em_width => { match_mono_em_width,
let glyph_font_size = font_size * (match_em_width / glyph_em_width); glyph.font_monospace_em_width,
) {
(Some(match_em_width), Some(glyph_em_width))
if glyph_em_width != match_em_width =>
{
let glyph_font_size =
font_size * (match_em_width / glyph_em_width);
log::trace!("Adjusted glyph font size ({font_size} => {glyph_font_size})"); log::trace!("Adjusted glyph font size ({font_size} => {glyph_font_size})");
glyph_font_size glyph_font_size
}, }
_ => font_size, _ => font_size,
}; };