Skip to content

Commit

Permalink
Fix TrueType SVG fonts handling
Browse files Browse the repository at this point in the history
  • Loading branch information
LaurenzV authored Jun 10, 2024
1 parent 063e403 commit ba1be45
Showing 1 changed file with 25 additions and 7 deletions.
32 changes: 25 additions & 7 deletions crates/usvg/src/text/flatten.rs
Original file line number Diff line number Diff line change
Expand Up @@ -85,16 +85,16 @@ pub(crate) fn flatten(text: &mut Text, fontdb: &fontdb::Database) -> Option<(Gro

new_children.push(Node::Group(Box::new(group)));
}
// An SVG glyph. Will return the usvg tree containing the glyph descriptions.
else if let Some(tree) = fontdb.svg(glyph.font, glyph.id) {
// An SVG glyph. Will return the usvg node containing the glyph descriptions.
else if let Some(node) = fontdb.svg(glyph.font, glyph.id) {
push_outline_paths(span, &mut span_builder, &mut new_children, rendering_mode);

let mut group = Group {
transform: glyph.svg_transform(),
..Group::empty()
};
// TODO: Probably need to update abs_transform of children?
group.children.push(Node::Group(Box::new(tree.root)));
group.children.push(node);
group.calculate_bounding_boxes();

new_children.push(Node::Group(Box::new(group)));
Expand Down Expand Up @@ -189,7 +189,7 @@ impl ttf_parser::OutlineBuilder for PathBuilder {
pub(crate) trait DatabaseExt {
fn outline(&self, id: ID, glyph_id: GlyphId) -> Option<tiny_skia_path::Path>;
fn raster(&self, id: ID, glyph_id: GlyphId) -> Option<BitmapImage>;
fn svg(&self, id: ID, glyph_id: GlyphId) -> Option<Tree>;
fn svg(&self, id: ID, glyph_id: GlyphId) -> Option<Node>;
fn colr(&self, id: ID, glyph_id: GlyphId) -> Option<Tree>;
}

Expand Down Expand Up @@ -253,14 +253,32 @@ impl DatabaseExt for Database {
})?
}

fn svg(&self, id: ID, glyph_id: GlyphId) -> Option<Tree> {
fn svg(&self, id: ID, glyph_id: GlyphId) -> Option<Node> {
// TODO: Technically not 100% accurate because the SVG format in a OTF font
// is actually a subset/superset of a normal SVG, but it seems to work fine
// for Twitter Color Emoji, so might as well use what we already have.
self.with_face_data(id, |data, face_index| -> Option<Tree> {

// TODO: Glyph records can contain the data for multiple glyphs. We should
// add a cache so we don't need to reparse the data every time.
self.with_face_data(id, |data, face_index| -> Option<Node> {
let font = ttf_parser::Face::parse(data, face_index).ok()?;
let image = font.glyph_svg_image(glyph_id)?;
Tree::from_data(image.data, &Options::default()).ok()
let tree = Tree::from_data(image.data, &Options::default()).ok()?;

// Twitter Color Emoji seems to always have one SVG record per glyph,
// while Noto Color Emoji sometimes contains multiple ones. It's kind of hacky,
// but the best we have for now.
let node = if image.start_glyph_id == image.end_glyph_id {
Node::Group(Box::new(tree.root))
} else {
tree.node_by_id(&format!("glyph{}", glyph_id.0))
.log_none(|| {
log::warn!("Failed to find SVG glyph node for glyph {}", glyph_id.0)
})
.cloned()?
};

Some(node)
})?
}

Expand Down

0 comments on commit ba1be45

Please sign in to comment.