diff options
author | Martin Robinson <mrobinson@igalia.com> | 2024-08-23 04:17:44 -0700 |
---|---|---|
committer | GitHub <noreply@github.com> | 2024-08-23 11:17:44 +0000 |
commit | 78e2691d3f396c9811bd27d69877cade365e5d78 (patch) | |
tree | 014a0e57e804bd7d4a1f513aff276c8a23ccfea4 /components/fonts/shaper.rs | |
parent | ebdae6094ecc105be10fb2e59b13cf63773a4c10 (diff) | |
download | servo-78e2691d3f396c9811bd27d69877cade365e5d78.tar.gz servo-78e2691d3f396c9811bd27d69877cade365e5d78.zip |
shaping: Don't assume there's a space glyph when rendering tabs (#32979)
Previously if a font didn't have a space advance and it was needed to
make advances for tabs, Servo would try to read the advance from the
font. If the font didn't have a space glyph, Servo would panic. This
fixes that issue by making the space advance part of the `FontMetrics`
of a font (like Gecko) and falling back properly if that glyph doesn't
exist. The rendered glyph is still the "space" glyph, but we make
sure to select a font that supports that glyph explicitly.
This prevents a crash, but tabs still aren't handled properly. In
reality, tab stops should be calculated in layout and the size of
the space character of the current font shouldn't come into play.
The addition of the space advance metric will make this easier.
Fixes #32970.
Signed-off-by: Martin Robinson <mrobinson@igalia.com>
Diffstat (limited to 'components/fonts/shaper.rs')
-rw-r--r-- | components/fonts/shaper.rs | 43 |
1 files changed, 20 insertions, 23 deletions
diff --git a/components/fonts/shaper.rs b/components/fonts/shaper.rs index eb8f92b789d..6b61a16183a 100644 --- a/components/fonts/shaper.rs +++ b/components/fonts/shaper.rs @@ -545,20 +545,27 @@ impl Shaper { let character = text[byte_range.clone()].chars().next().unwrap(); if is_bidi_control(character) { // Don't add any glyphs for bidi control chars - } else if character == '\t' { - // Treat tabs in pre-formatted text as a fixed number of spaces. - // - // TODO: Proper tab stops. - const TAB_COLS: i32 = 8; - let (space_glyph_id, space_advance) = glyph_space_advance(self.font); - let advance = Au::from_f64_px(space_advance) * TAB_COLS; - let data = - GlyphData::new(space_glyph_id, advance, Default::default(), true, true); - glyphs.add_glyph_for_byte_index(byte_idx, character, &data); } else { - let shape = glyph_data.entry_for_glyph(glyph_span.start, &mut y_pos); - let advance = self.advance_for_shaped_glyph(shape.advance, character, options); - let data = GlyphData::new(shape.codepoint, advance, shape.offset, true, true); + let (glyph_id, advance, offset) = if character == '\t' { + // Treat tabs in pre-formatted text as a fixed number of spaces. The glyph id does + // not matter here as Servo doesn't render any glyphs for whitespace. + // + // TODO: Proper tab stops. This should happen in layout and be based on the + // size of the space character of the inline formatting context. + let font = unsafe { &(*self.font) }; + ( + font.glyph_index(' ').unwrap_or(0) as hb_codepoint_t, + font.metrics.space_advance * 8, + Default::default(), + ) + } else { + let shape = glyph_data.entry_for_glyph(glyph_span.start, &mut y_pos); + let advance = + self.advance_for_shaped_glyph(shape.advance, character, options); + (shape.codepoint, advance, shape.offset) + }; + + let data = GlyphData::new(glyph_id, advance, offset, true, true); glyphs.add_glyph_for_byte_index(byte_idx, character, &data); } } else { @@ -708,16 +715,6 @@ extern "C" fn glyph_h_advance_func( } } -fn glyph_space_advance(font: *const Font) -> (hb_codepoint_t, f64) { - let space_unicode = ' '; - let space_glyph: hb_codepoint_t = match unsafe { (*font).glyph_index(space_unicode) } { - Some(g) => g as hb_codepoint_t, - None => panic!("No space info"), - }; - let space_advance = unsafe { (*font).glyph_h_advance(space_glyph as GlyphId) }; - (space_glyph, space_advance) -} - // Callback to get a font table out of a font. extern "C" fn font_table_func( _: *mut hb_face_t, |