Use supported codepoints instead of scripts in Monospace fallback
This should/could improve fallback order. This could also probably be utilized for non-Monospace fallback too. But I didn't want to touch that code to avoid accidentally breaking anything. Signed-off-by: Mohammad AlSaleh <CE.Mohammad.AlSaleh@gmail.com>
This commit is contained in:
parent
845a66ceff
commit
db1530c4ec
3 changed files with 45 additions and 37 deletions
|
|
@ -38,7 +38,7 @@ use log::warn as missing_warn;
|
||||||
#[derive(Debug, PartialEq, Eq, PartialOrd, Ord)]
|
#[derive(Debug, PartialEq, Eq, PartialOrd, Ord)]
|
||||||
struct MonospaceFallbackInfo {
|
struct MonospaceFallbackInfo {
|
||||||
weight_offset: Option<u16>,
|
weight_offset: Option<u16>,
|
||||||
script_non_matches: Option<usize>,
|
codepoint_non_matches: Option<usize>,
|
||||||
id: fontdb::ID,
|
id: fontdb::ID,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -49,6 +49,7 @@ pub struct FontFallbackIter<'a> {
|
||||||
monospace_fallbacks: BTreeSet<MonospaceFallbackInfo>,
|
monospace_fallbacks: BTreeSet<MonospaceFallbackInfo>,
|
||||||
default_i: usize,
|
default_i: usize,
|
||||||
scripts: &'a [Script],
|
scripts: &'a [Script],
|
||||||
|
word: &'a str,
|
||||||
script_i: (usize, usize),
|
script_i: (usize, usize),
|
||||||
common_i: usize,
|
common_i: usize,
|
||||||
other_i: usize,
|
other_i: usize,
|
||||||
|
|
@ -61,6 +62,7 @@ impl<'a> FontFallbackIter<'a> {
|
||||||
font_match_keys: &'a [FontMatchKey],
|
font_match_keys: &'a [FontMatchKey],
|
||||||
default_families: &'a [&'a Family<'a>],
|
default_families: &'a [&'a Family<'a>],
|
||||||
scripts: &'a [Script],
|
scripts: &'a [Script],
|
||||||
|
word: &'a str,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
Self {
|
Self {
|
||||||
font_system,
|
font_system,
|
||||||
|
|
@ -69,6 +71,7 @@ impl<'a> FontFallbackIter<'a> {
|
||||||
monospace_fallbacks: BTreeSet::new(),
|
monospace_fallbacks: BTreeSet::new(),
|
||||||
default_i: 0,
|
default_i: 0,
|
||||||
scripts,
|
scripts,
|
||||||
|
word,
|
||||||
script_i: (0, 0),
|
script_i: (0, 0),
|
||||||
common_i: 0,
|
common_i: 0,
|
||||||
other_i: 0,
|
other_i: 0,
|
||||||
|
|
@ -161,44 +164,34 @@ impl<'a> Iterator for FontFallbackIter<'a> {
|
||||||
// Default font
|
// Default font
|
||||||
let fallback_info = MonospaceFallbackInfo {
|
let fallback_info = MonospaceFallbackInfo {
|
||||||
weight_offset: None,
|
weight_offset: None,
|
||||||
script_non_matches: None,
|
codepoint_non_matches: None,
|
||||||
id: m_key.id,
|
id: m_key.id,
|
||||||
};
|
};
|
||||||
assert_eq!(self.monospace_fallbacks.insert(fallback_info), true);
|
assert!(self.monospace_fallbacks.insert(fallback_info));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// 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()
|
|
||||||
.filter_map(|script| {
|
|
||||||
let script_as_lower = script.short_name().to_lowercase();
|
|
||||||
<[u8; 4]>::try_from(script_as_lower.as_bytes()).ok()
|
|
||||||
})
|
|
||||||
.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()
|
let codepoint_non_matches = self.word.chars().count()
|
||||||
- script_tags
|
- self
|
||||||
.iter()
|
.word
|
||||||
.filter(|&&script_tag| {
|
.chars()
|
||||||
font.scripts()
|
.filter(|ch| {
|
||||||
.iter()
|
font.unicode_codepoints().contains(&u32::from(*ch))
|
||||||
.any(|&tag_bytes| tag_bytes == script_tag)
|
|
||||||
})
|
})
|
||||||
.count();
|
.count();
|
||||||
|
|
||||||
let fallback_info = MonospaceFallbackInfo {
|
let fallback_info = MonospaceFallbackInfo {
|
||||||
weight_offset: m_key.weight_offset,
|
weight_offset: m_key.weight_offset,
|
||||||
script_non_matches: Some(script_non_matches),
|
codepoint_non_matches: Some(codepoint_non_matches),
|
||||||
id: m_key.id,
|
id: m_key.id,
|
||||||
};
|
};
|
||||||
assert_eq!(self.monospace_fallbacks.insert(fallback_info), true);
|
assert!(self.monospace_fallbacks.insert(fallback_info));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -30,7 +30,7 @@ pub struct Font {
|
||||||
data: Arc<dyn AsRef<[u8]> + Send + Sync>,
|
data: Arc<dyn AsRef<[u8]> + Send + Sync>,
|
||||||
id: fontdb::ID,
|
id: fontdb::ID,
|
||||||
monospace_em_width: Option<f32>,
|
monospace_em_width: Option<f32>,
|
||||||
scripts: Vec<[u8; 4]>,
|
unicode_codepoints: Vec<u32>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl fmt::Debug for Font {
|
impl fmt::Debug for Font {
|
||||||
|
|
@ -50,8 +50,8 @@ impl Font {
|
||||||
self.monospace_em_width
|
self.monospace_em_width
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn scripts(&self) -> &[[u8; 4]] {
|
pub fn unicode_codepoints(&self) -> &[u32] {
|
||||||
&self.scripts
|
&self.unicode_codepoints
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn data(&self) -> &[u8] {
|
pub fn data(&self) -> &[u8] {
|
||||||
|
|
@ -77,7 +77,7 @@ impl Font {
|
||||||
pub fn new(db: &fontdb::Database, id: fontdb::ID) -> Option<Self> {
|
pub fn new(db: &fontdb::Database, id: fontdb::ID) -> Option<Self> {
|
||||||
let info = db.face(id)?;
|
let info = db.face(id)?;
|
||||||
|
|
||||||
let (monospace_em_width, scripts) = {
|
let (monospace_em_width, unicode_codepoints) = {
|
||||||
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
|
let monospace_em_width = info
|
||||||
|
|
@ -93,16 +93,25 @@ impl Font {
|
||||||
None?;
|
None?;
|
||||||
}
|
}
|
||||||
|
|
||||||
let scripts = face
|
let mut unicode_codepoints = Vec::new();
|
||||||
.tables()
|
|
||||||
.gpos
|
face.tables()
|
||||||
|
.cmap?
|
||||||
|
.subtables
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.chain(face.tables().gsub)
|
.filter(|subtable| subtable.is_unicode())
|
||||||
.map(|table| table.scripts)
|
.for_each(|subtable| {
|
||||||
.flatten()
|
unicode_codepoints.reserve(1024);
|
||||||
.map(|script| script.tag.to_bytes())
|
subtable.codepoints(|code_point| {
|
||||||
.collect();
|
if subtable.glyph_index(code_point).is_some() {
|
||||||
Some((monospace_em_width, scripts))
|
unicode_codepoints.push(code_point);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
unicode_codepoints.shrink_to_fit();
|
||||||
|
|
||||||
|
Some((monospace_em_width, unicode_codepoints))
|
||||||
})?
|
})?
|
||||||
}?;
|
}?;
|
||||||
|
|
||||||
|
|
@ -120,7 +129,7 @@ impl Font {
|
||||||
Some(Self {
|
Some(Self {
|
||||||
id: info.id,
|
id: info.id,
|
||||||
monospace_em_width,
|
monospace_em_width,
|
||||||
scripts,
|
unicode_codepoints,
|
||||||
#[cfg(feature = "swash")]
|
#[cfg(feature = "swash")]
|
||||||
swash: {
|
swash: {
|
||||||
let swash = swash::FontRef::from_index((*data).as_ref(), info.index as usize)?;
|
let swash = swash::FontRef::from_index((*data).as_ref(), info.index as usize)?;
|
||||||
|
|
|
||||||
10
src/shape.rs
10
src/shape.rs
|
|
@ -219,7 +219,13 @@ fn shape_run(
|
||||||
let fonts = font_system.get_font_matches(attrs);
|
let fonts = font_system.get_font_matches(attrs);
|
||||||
|
|
||||||
let default_families = [&attrs.family];
|
let default_families = [&attrs.family];
|
||||||
let mut font_iter = FontFallbackIter::new(font_system, &fonts, &default_families, &scripts);
|
let mut font_iter = FontFallbackIter::new(
|
||||||
|
font_system,
|
||||||
|
&fonts,
|
||||||
|
&default_families,
|
||||||
|
&scripts,
|
||||||
|
&line[start_run..end_run],
|
||||||
|
);
|
||||||
|
|
||||||
let font = font_iter.next().expect("no default font found");
|
let font = font_iter.next().expect("no default font found");
|
||||||
|
|
||||||
|
|
@ -341,7 +347,7 @@ fn shape_skip(
|
||||||
let fonts = font_system.get_font_matches(attrs);
|
let fonts = font_system.get_font_matches(attrs);
|
||||||
|
|
||||||
let default_families = [&attrs.family];
|
let default_families = [&attrs.family];
|
||||||
let mut font_iter = FontFallbackIter::new(font_system, &fonts, &default_families, &[]);
|
let mut font_iter = FontFallbackIter::new(font_system, &fonts, &default_families, &[], "");
|
||||||
|
|
||||||
let font = font_iter.next().expect("no default font found");
|
let font = font_iter.next().expect("no default font found");
|
||||||
let font_id = font.id();
|
let font_id = font.id();
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue