summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLaurenz <laurmaedje@gmail.com>2023-09-09 22:31:37 +0200
committerLaurenz <laurmaedje@gmail.com>2023-09-09 22:33:17 +0200
commit073effc7407bd314beea09ac8f83e809bdb10497 (patch)
tree920849b41992bd61531f59281ab1b9457836f245
parent66a595891793a0e6b0b90bbc0bed3e597610f857 (diff)
Fix font family mismatch between Typst and usvg
Fixes #2051
-rw-r--r--crates/typst-library/src/visualize/image.rs2
-rw-r--r--crates/typst/src/image.rs82
-rw-r--r--tests/ref/bugs/new-cm-svg.pngbin0 -> 2911 bytes
-rw-r--r--tests/typ/bugs/new-cm-svg.typ2
4 files changed, 44 insertions, 42 deletions
diff --git a/crates/typst-library/src/visualize/image.rs b/crates/typst-library/src/visualize/image.rs
index a5c8eae4..a06509dd 100644
--- a/crates/typst-library/src/visualize/image.rs
+++ b/crates/typst-library/src/visualize/image.rs
@@ -168,7 +168,7 @@ impl Layout for ImageElem {
data.into(),
format,
vt.world,
- families(styles).next().as_ref().map(|f| f.as_str()),
+ families(styles).next().map(|s| s.as_str().into()),
self.alt(styles),
)
.at(self.span())?;
diff --git a/crates/typst/src/image.rs b/crates/typst/src/image.rs
index 40dad615..83d8f3a7 100644
--- a/crates/typst/src/image.rs
+++ b/crates/typst/src/image.rs
@@ -76,7 +76,7 @@ impl Image {
data: Bytes,
format: ImageFormat,
world: Tracked<dyn World + '_>,
- fallback_family: Option<&str>,
+ fallback_family: Option<EcoString>,
alt: Option<EcoString>,
) -> StrResult<Self> {
let loader = WorldLoader::new(world, fallback_family);
@@ -313,31 +313,39 @@ fn load_svg_fonts(
tree: &usvg::Tree,
loader: Tracked<dyn SvgFontLoader + '_>,
) -> fontdb::Database {
- let mut referenced = BTreeMap::<EcoString, bool>::new();
let mut fontdb = fontdb::Database::new();
- let mut load = |family_cased: &str| {
- let family = EcoString::from(family_cased.trim()).to_lowercase();
- if let Some(&success) = referenced.get(&family) {
- return success;
+ let mut referenced = BTreeMap::<EcoString, Option<EcoString>>::new();
+
+ // Loads a font family by its Typst name and returns its usvg-compatible
+ // name.
+ let mut load = |family: &str| -> Option<EcoString> {
+ let family = EcoString::from(family.trim()).to_lowercase();
+ if let Some(success) = referenced.get(&family) {
+ return success.clone();
}
// We load all variants for the family, since we don't know which will
// be used.
- let mut success = false;
+ let mut name = None;
for font in loader.load(&family) {
let source = Arc::new(font.data().clone());
fontdb.load_font_source(fontdb::Source::Binary(source));
- success = true;
+ if name.is_none() {
+ name = font
+ .find_name(ttf_parser::name_id::TYPOGRAPHIC_FAMILY)
+ .or_else(|| font.find_name(ttf_parser::name_id::FAMILY))
+ .map(Into::into);
+ }
}
- referenced.insert(family, success);
- success
+ referenced.insert(family, name.clone());
+ name
};
// Load fallback family.
- let fallback_cased = loader.fallback();
- if let Some(family_cased) = fallback_cased {
- load(family_cased);
+ let mut fallback_usvg_compatible = None;
+ if let Some(family) = loader.fallback_family() {
+ fallback_usvg_compatible = load(family);
}
// Find out which font families are referenced by the SVG.
@@ -345,10 +353,11 @@ fn load_svg_fonts(
let usvg::NodeKind::Text(text) = &mut *node.borrow_mut() else { return };
for chunk in &mut text.chunks {
for span in &mut chunk.spans {
- for family_cased in &mut span.font.families {
- if family_cased.is_empty() || !load(family_cased) {
- let Some(fallback) = fallback_cased else { continue };
- *family_cased = fallback.into();
+ for family in &mut span.font.families {
+ if family.is_empty() || load(family).is_none() {
+ if let Some(fallback) = &fallback_usvg_compatible {
+ *family = fallback.into();
+ }
}
}
}
@@ -384,40 +393,31 @@ where
#[comemo::track]
trait SvgFontLoader {
/// Load all fonts for the given lowercased font family.
- fn load(&self, lower_family: &str) -> EcoVec<Font>;
+ fn load(&self, family: &str) -> EcoVec<Font>;
- /// The case-sensitive name of the fallback family.
- fn fallback(&self) -> Option<&str>;
+ /// The fallback family.
+ fn fallback_family(&self) -> Option<&str>;
}
/// Loads fonts for an SVG from a world
struct WorldLoader<'a> {
world: Tracked<'a, dyn World + 'a>,
seen: RefCell<BTreeMap<EcoString, EcoVec<Font>>>,
- fallback_family_cased: Option<String>,
+ fallback_family: Option<EcoString>,
}
impl<'a> WorldLoader<'a> {
- fn new(world: Tracked<'a, dyn World + 'a>, fallback_family: Option<&str>) -> Self {
- // Recover the non-lowercased version of the family because
- // usvg is case sensitive.
- let book = world.book();
- let fallback_family_cased = fallback_family
- .and_then(|lowercase| book.select_family(lowercase).next())
- .and_then(|index| book.info(index))
- .map(|info| info.family.clone());
-
- Self {
- world,
- fallback_family_cased,
- seen: Default::default(),
- }
+ fn new(
+ world: Tracked<'a, dyn World + 'a>,
+ fallback_family: Option<EcoString>,
+ ) -> Self {
+ Self { world, fallback_family, seen: Default::default() }
}
fn into_prepared(self) -> PreparedLoader {
PreparedLoader {
families: self.seen.into_inner(),
- fallback_family_cased: self.fallback_family_cased,
+ fallback_family: self.fallback_family,
}
}
}
@@ -437,8 +437,8 @@ impl SvgFontLoader for WorldLoader<'_> {
.clone()
}
- fn fallback(&self) -> Option<&str> {
- self.fallback_family_cased.as_deref()
+ fn fallback_family(&self) -> Option<&str> {
+ self.fallback_family.as_deref()
}
}
@@ -446,7 +446,7 @@ impl SvgFontLoader for WorldLoader<'_> {
#[derive(Default, Hash)]
struct PreparedLoader {
families: BTreeMap<EcoString, EcoVec<Font>>,
- fallback_family_cased: Option<String>,
+ fallback_family: Option<EcoString>,
}
impl SvgFontLoader for PreparedLoader {
@@ -454,8 +454,8 @@ impl SvgFontLoader for PreparedLoader {
self.families.get(family).cloned().unwrap_or_default()
}
- fn fallback(&self) -> Option<&str> {
- self.fallback_family_cased.as_deref()
+ fn fallback_family(&self) -> Option<&str> {
+ self.fallback_family.as_deref()
}
}
diff --git a/tests/ref/bugs/new-cm-svg.png b/tests/ref/bugs/new-cm-svg.png
new file mode 100644
index 00000000..c011bbfc
--- /dev/null
+++ b/tests/ref/bugs/new-cm-svg.png
Binary files differ
diff --git a/tests/typ/bugs/new-cm-svg.typ b/tests/typ/bugs/new-cm-svg.typ
new file mode 100644
index 00000000..06cd4532
--- /dev/null
+++ b/tests/typ/bugs/new-cm-svg.typ
@@ -0,0 +1,2 @@
+#set text(font: "New Computer Modern")
+#image("/files/diagram.svg")