mirror of
https://github.com/slint-ui/slint.git
synced 2025-08-04 18:58:36 +00:00
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:
parent
e64e15e277
commit
02694f4992
1 changed files with 118 additions and 41 deletions
|
@ -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(
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue