diff options
author | Federico Mena Quintero <federico@gnome.org> | 2023-02-14 19:09:34 -0600 |
---|---|---|
committer | Federico Mena Quintero <federico@gnome.org> | 2023-02-14 19:09:34 -0600 |
commit | be70ba1e182b425f711b308bf30e6ecccde7163d (patch) | |
tree | 1310abfa8a704e5abe5c5b26a321086ea1cdfac5 | |
parent | a1a4be2a38cd3178274a76d452a67dd15e269a38 (diff) | |
download | librsvg-be70ba1e182b425f711b308bf30e6ecccde7163d.tar.gz |
MeasuredSpan::from_span(): Check that the font-size and letter-spacing are convertible to Pango units
Otherwise, ignore the span - return None and have the caller ignore
it.
Now, this is a good place to actually impose a limit on font sizes.
What should those be...?
Part-of: <https://gitlab.gnome.org/GNOME/librsvg/-/merge_requests/796>
-rw-r--r-- | src/text.rs | 94 |
1 files changed, 62 insertions, 32 deletions
diff --git a/src/text.rs b/src/text.rs index 3ca8ec9f..24fa12d1 100644 --- a/src/text.rs +++ b/src/text.rs @@ -144,7 +144,7 @@ impl MeasuredChunk { let mut measured_spans: Vec<MeasuredSpan> = chunk .spans .iter() - .map(|span| MeasuredSpan::from_span(layout_context, span)) + .filter_map(|span| MeasuredSpan::from_span(layout_context, span)) .collect(); // The first span contains the (dx, dy) that will be applied to the whole chunk. @@ -356,7 +356,7 @@ impl PangoUnits { } impl MeasuredSpan { - fn from_span(layout_context: &LayoutContext, span: &Span) -> MeasuredSpan { + fn from_span(layout_context: &LayoutContext, span: &Span) -> Option<MeasuredSpan> { let values = span.values.clone(); let params = NormalizeParams::new(&values, &layout_context.view_params); @@ -369,30 +369,35 @@ impl MeasuredSpan { ); let with_control_chars = wrap_with_direction_control_chars(&span.text, &bidi_control); - let layout = create_pango_layout(layout_context, &properties, &with_control_chars); - let (w, h) = layout.size(); - let w = f64::from(w) / f64::from(pango::SCALE); - let h = f64::from(h) / f64::from(pango::SCALE); + if let Some(layout) = create_pango_layout(layout_context, &properties, &with_control_chars) + { + let (w, h) = layout.size(); - // This is the logical size of the layout, regardless of text direction, so it's always positive. - assert!(w >= 0.0); - assert!(h >= 0.0); + let w = f64::from(w) / f64::from(pango::SCALE); + let h = f64::from(h) / f64::from(pango::SCALE); - let advance = if layout_context.writing_mode.is_horizontal() { - (w, 0.0) - } else { - (0.0, w) - }; + // This is the logical size of the layout, regardless of text direction, so it's always positive. + assert!(w >= 0.0); + assert!(h >= 0.0); - MeasuredSpan { - values, - layout, - layout_size: (w, h), - advance, - dx: span.dx, - dy: span.dy, - link_target: span.link_target.clone(), + let advance = if layout_context.writing_mode.is_horizontal() { + (w, 0.0) + } else { + (0.0, w) + }; + + Some(MeasuredSpan { + values, + layout, + layout_size: (w, h), + advance, + dx: span.dx, + dy: span.dy, + link_target: span.link_target.clone(), + }) + } else { + None } } } @@ -1206,11 +1211,12 @@ fn wrap_with_direction_control_chars(s: &str, bidi_control: &BidiControl) -> Str res } +/// Returns `None` if the layout would be invalid due to, for example, out-of-bounds font sizes. fn create_pango_layout( layout_context: &LayoutContext, props: &FontProperties, text: &str, -) -> pango::Layout { +) -> Option<pango::Layout> { let pango_context = create_pango_context(&layout_context.font_options, &layout_context.transform); @@ -1236,14 +1242,37 @@ fn create_pango_layout( let layout = pango::Layout::new(&pango_context); - let attr_list = pango::AttrList::new(); - add_pango_attributes(&attr_list, props, 0, text.len()); + let font_size = PangoUnits::from_pixels(props.font_size); + let letter_spacing = PangoUnits::from_pixels(props.letter_spacing); - layout.set_attributes(Some(&attr_list)); - layout.set_text(text); - layout.set_auto_dir(false); + if font_size.is_none() { + rsvg_log!( + &layout_context.session, + "font-size {} is out of bounds; ignoring span", + props.font_size + ); + } + + if letter_spacing.is_none() { + rsvg_log!( + &layout_context.session, + "letter-spacing {} is out of bounds; ignoring span", + props.letter_spacing + ); + } + + if let (Some(font_size), Some(letter_spacing)) = (font_size, letter_spacing) { + let attr_list = pango::AttrList::new(); + add_pango_attributes(&attr_list, props, 0, text.len(), font_size, letter_spacing); + + layout.set_attributes(Some(&attr_list)); + layout.set_text(text); + layout.set_auto_dir(false); - layout + Some(layout) + } else { + None + } } /// Adds Pango attributes, suitable for a span of text, to an `AttrList`. @@ -1252,6 +1281,8 @@ fn add_pango_attributes( props: &FontProperties, start_index: usize, end_index: usize, + font_size: PangoUnits, + letter_spacing: PangoUnits, ) { let start_index = u32::try_from(start_index).expect("Pango attribute index must fit in u32"); let end_index = u32::try_from(end_index).expect("Pango attribute index must fit in u32"); @@ -1270,12 +1301,11 @@ fn add_pango_attributes( font_desc.set_weight(pango::Weight::from(props.font_weight)); font_desc.set_stretch(pango::Stretch::from(props.font_stretch)); - font_desc.set_size(to_pango_units(props.font_size)); + font_desc.set_size(font_size.0); attributes.push(pango::AttrFontDesc::new(&font_desc).upcast()); - attributes - .push(pango::AttrInt::new_letter_spacing(to_pango_units(props.letter_spacing)).upcast()); + attributes.push(pango::AttrInt::new_letter_spacing(letter_spacing.0).upcast()); if props.text_decoration.overline { attributes.push(pango::AttrInt::new_overline(pango::Overline::Single).upcast()); |