Replace unwraps in compiler glyph embedding with diagnostics

As discussed with Olivier, fatal diagnostics are better than a panicing
compiler.
This commit is contained in:
Simon Hausmann 2023-02-07 16:09:39 +01:00 committed by Simon Hausmann
parent e64e15e277
commit 02694f4992

View file

@ -34,6 +34,9 @@ pub fn embed_glyphs<'a>(
) {
use crate::diagnostics::Spanned;
let generic_diag_location =
component.root_element.borrow().node.as_ref().map(|e| e.to_source_location());
characters_seen.extend(
('a'..='z')
.chain('A'..='Z')
@ -43,9 +46,23 @@ pub fn embed_glyphs<'a>(
);
if let Ok(sizes_str) = std::env::var("SLINT_FONT_SIZES") {
for custom_size in sizes_str.split(',').map(|size_str| {
(size_str.parse::<f64>().expect("invalid font size") * scale_factor) as i16
}) {
for custom_size_str in sizes_str.split(',') {
let custom_size = if let Ok(custom_size) = custom_size_str
.parse::<f64>()
.map(|size_as_float| (size_as_float * scale_factor) as i16)
{
custom_size
} else {
diag.push_error(
format!(
"Invalid font size '{}' specified in `SLINT_FONT_SIZES`",
custom_size_str
),
&generic_diag_location,
);
return;
};
if let Err(pos) = pixel_sizes.binary_search(&custom_size) {
pixel_sizes.insert(pos, custom_size)
}
@ -65,7 +82,11 @@ pub fn embed_glyphs<'a>(
let default_sans_serif_family = {
let mut fontconfig_fallback_families = fontconfig::find_families("sans-serif");
if fontconfig_fallback_families.len() == 0 {
panic!("internal error: unable to resolve 'sans-serif' with fontconfig");
diag.push_error(
"internal error: unable to resolve 'sans-serif' with fontconfig".to_string(),
&generic_diag_location,
);
return;
}
fontconfig_fallback_families.remove(0)
};
@ -74,9 +95,6 @@ pub fn embed_glyphs<'a>(
let maybe_override_default_font_id =
std::env::var_os("SLINT_DEFAULT_FONT").and_then(|maybe_font_path| {
let generic_warning_location = component.root_element.borrow().node.as_ref().map(|e| e.to_source_location());
let path = std::path::Path::new(&maybe_font_path);
if path.extension().is_some() {
let face_count = fontdb.len();
@ -87,7 +105,7 @@ pub fn embed_glyphs<'a>(
Err(err) => {
diag.push_warning(
format!("Could not load the font set via `SLINT_DEFAULT_FONT`: {}: {}", path.display(), err),
&generic_warning_location,
&generic_diag_location,
);
None
},
@ -95,7 +113,7 @@ pub fn embed_glyphs<'a>(
} else {
diag.push_warning(
"The environment variable `SLINT_DEFAULT_FONT` is set, but its value is not referring to a file".into(),
&generic_warning_location,
&generic_diag_location,
);
None
}
@ -117,7 +135,7 @@ pub fn embed_glyphs<'a>(
}
}
let (default_font_face_id, default_font_path) = maybe_override_default_font_id.map_or_else(||{
let (default_font_face_id, default_font_path) = if let Some(result) = maybe_override_default_font_id.map_or_else(||{
// TODO: improve heuristics in choice of which fonts to embed. use default-font-family, etc.
let (family, source_location) = component
.root_element
@ -145,16 +163,23 @@ pub fn embed_glyphs<'a>(
fallback_font
});
let face_info = fontdb
.face(face_id)
.expect("internal error: fontdb query returned a font that does not exist");
(
let face_info = if let Some(face_info) = fontdb
.face(face_id) {
face_info
} else {
diag.push_error("internal error: fontdb query returned a font that does not exist".to_string(), &generic_diag_location);
return None;
};
Some((
face_id,
match &face_info.source {
fontdb::Source::File(path) => path.to_string_lossy().to_string(),
_ => panic!("internal errormemory fonts are not supported in the compiler"),
_ => {
diag.push_error("internal error: memory fonts are not supported in the compiler".to_string(), &generic_diag_location);
return None;
}
},
)
))
}, |override_default_font_id| {
let path = match &fontdb.face(override_default_font_id).unwrap().source {
fontdb::Source::Binary(_) => unreachable!(),
@ -162,50 +187,102 @@ pub fn embed_glyphs<'a>(
fontdb::Source::SharedFile(path_buf, _) => path_buf.clone(),
};
(override_default_font_id, path.to_string_lossy().into())
});
Some((override_default_font_id, path.to_string_lossy().into()))
}) {
result
} else {
return;
};
// Map from path to family name
let mut fonts = std::collections::BTreeMap::<String, fontdb::ID>::new();
fonts.insert(default_font_path.clone(), default_font_face_id);
// add custom fonts
let mut custom_face_error = false;
fonts.extend(custom_fonts.iter().filter_map(|face_id| {
fontdb.face(*face_id).map(|face_info| {
(
fontdb.face(*face_id).and_then(|face_info| {
Some((
match &face_info.source {
fontdb::Source::File(path) => path.to_string_lossy().to_string(),
_ => panic!("internal errormemory fonts are not supported in the compiler"),
_ => {
diag.push_error(
"internal error: memory fonts are not supported in the compiler"
.to_string(),
&generic_diag_location,
);
custom_face_error = true;
return None;
}
},
*face_id,
)
))
})
}));
let embed_font_by_path_and_face_id = |path, face_id| {
let font = fontdb
.with_face_data(face_id, |font_data, face_index| {
let font = fontdue::Font::from_bytes(
font_data,
fontdue::FontSettings { collection_index: face_index, scale: 40. },
)
.expect("internal error: fontdb returned a font that ttf-parser/fontdue could not parse");
if custom_face_error {
return;
}
let mut embed_font_by_path_and_face_id = |path, face_id| {
let maybe_font = if let Some(maybe_font) =
fontdb.with_face_data(face_id, |font_data, face_index| {
let fontdue_font = match fontdue::Font::from_bytes(
font_data,
fontdue::FontSettings { collection_index: face_index, scale: 40. },
) {
Ok(fontdue_font) => fontdue_font,
Err(fontdue_msg) => {
diag.push_error(
format!(
"internal error: fontdue can't parse font {path}: {fontdue_msg}"
),
&generic_diag_location,
);
return None;
}
};
let family_name = if let Some(family_name) = fontdb
.face(face_id)
.expect("must succeed as we are within face_data with same face_id")
.families
.first()
.map(|(name, _)| name.clone())
{
family_name
} else {
diag.push_error(
format!("internal error: TrueType font without english family name encountered: {path}"),
&generic_diag_location,
);
return None;
};
embed_font(
fontdb
.face(face_id)
.unwrap()
.families
.first()
.expect("TrueType font without english family name encountered")
.0
.clone(),
font,
family_name,
fontdue_font,
&pixel_sizes,
characters_seen.iter().cloned(),
&fallback_fonts,
)
})
.unwrap();
.into()
}) {
maybe_font
} else {
diag.push_error(
format!("internal error: face_id of selected font {path} is unknown to fontdb"),
&generic_diag_location,
);
return;
};
let font = if let Some(font) = maybe_font {
font
} else {
// Diagnostic was created inside callback for `width_face_data`.
return;
};
let resource_id = component.embedded_file_resources.borrow().len();
component.embedded_file_resources.borrow_mut().insert(