mirror of
https://github.com/typst/typst
synced 2025-05-22 04:55:29 +08:00
parent
66a5958917
commit
073effc740
@ -168,7 +168,7 @@ impl Layout for ImageElem {
|
|||||||
data.into(),
|
data.into(),
|
||||||
format,
|
format,
|
||||||
vt.world,
|
vt.world,
|
||||||
families(styles).next().as_ref().map(|f| f.as_str()),
|
families(styles).next().map(|s| s.as_str().into()),
|
||||||
self.alt(styles),
|
self.alt(styles),
|
||||||
)
|
)
|
||||||
.at(self.span())?;
|
.at(self.span())?;
|
||||||
|
@ -76,7 +76,7 @@ impl Image {
|
|||||||
data: Bytes,
|
data: Bytes,
|
||||||
format: ImageFormat,
|
format: ImageFormat,
|
||||||
world: Tracked<dyn World + '_>,
|
world: Tracked<dyn World + '_>,
|
||||||
fallback_family: Option<&str>,
|
fallback_family: Option<EcoString>,
|
||||||
alt: Option<EcoString>,
|
alt: Option<EcoString>,
|
||||||
) -> StrResult<Self> {
|
) -> StrResult<Self> {
|
||||||
let loader = WorldLoader::new(world, fallback_family);
|
let loader = WorldLoader::new(world, fallback_family);
|
||||||
@ -313,31 +313,39 @@ fn load_svg_fonts(
|
|||||||
tree: &usvg::Tree,
|
tree: &usvg::Tree,
|
||||||
loader: Tracked<dyn SvgFontLoader + '_>,
|
loader: Tracked<dyn SvgFontLoader + '_>,
|
||||||
) -> fontdb::Database {
|
) -> fontdb::Database {
|
||||||
let mut referenced = BTreeMap::<EcoString, bool>::new();
|
|
||||||
let mut fontdb = fontdb::Database::new();
|
let mut fontdb = fontdb::Database::new();
|
||||||
let mut load = |family_cased: &str| {
|
let mut referenced = BTreeMap::<EcoString, Option<EcoString>>::new();
|
||||||
let family = EcoString::from(family_cased.trim()).to_lowercase();
|
|
||||||
if let Some(&success) = referenced.get(&family) {
|
// Loads a font family by its Typst name and returns its usvg-compatible
|
||||||
return success;
|
// 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
|
// We load all variants for the family, since we don't know which will
|
||||||
// be used.
|
// be used.
|
||||||
let mut success = false;
|
let mut name = None;
|
||||||
for font in loader.load(&family) {
|
for font in loader.load(&family) {
|
||||||
let source = Arc::new(font.data().clone());
|
let source = Arc::new(font.data().clone());
|
||||||
fontdb.load_font_source(fontdb::Source::Binary(source));
|
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);
|
referenced.insert(family, name.clone());
|
||||||
success
|
name
|
||||||
};
|
};
|
||||||
|
|
||||||
// Load fallback family.
|
// Load fallback family.
|
||||||
let fallback_cased = loader.fallback();
|
let mut fallback_usvg_compatible = None;
|
||||||
if let Some(family_cased) = fallback_cased {
|
if let Some(family) = loader.fallback_family() {
|
||||||
load(family_cased);
|
fallback_usvg_compatible = load(family);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Find out which font families are referenced by the SVG.
|
// 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 };
|
let usvg::NodeKind::Text(text) = &mut *node.borrow_mut() else { return };
|
||||||
for chunk in &mut text.chunks {
|
for chunk in &mut text.chunks {
|
||||||
for span in &mut chunk.spans {
|
for span in &mut chunk.spans {
|
||||||
for family_cased in &mut span.font.families {
|
for family in &mut span.font.families {
|
||||||
if family_cased.is_empty() || !load(family_cased) {
|
if family.is_empty() || load(family).is_none() {
|
||||||
let Some(fallback) = fallback_cased else { continue };
|
if let Some(fallback) = &fallback_usvg_compatible {
|
||||||
*family_cased = fallback.into();
|
*family = fallback.into();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -384,40 +393,31 @@ where
|
|||||||
#[comemo::track]
|
#[comemo::track]
|
||||||
trait SvgFontLoader {
|
trait SvgFontLoader {
|
||||||
/// Load all fonts for the given lowercased font family.
|
/// 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.
|
/// The fallback family.
|
||||||
fn fallback(&self) -> Option<&str>;
|
fn fallback_family(&self) -> Option<&str>;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Loads fonts for an SVG from a world
|
/// Loads fonts for an SVG from a world
|
||||||
struct WorldLoader<'a> {
|
struct WorldLoader<'a> {
|
||||||
world: Tracked<'a, dyn World + 'a>,
|
world: Tracked<'a, dyn World + 'a>,
|
||||||
seen: RefCell<BTreeMap<EcoString, EcoVec<Font>>>,
|
seen: RefCell<BTreeMap<EcoString, EcoVec<Font>>>,
|
||||||
fallback_family_cased: Option<String>,
|
fallback_family: Option<EcoString>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> WorldLoader<'a> {
|
impl<'a> WorldLoader<'a> {
|
||||||
fn new(world: Tracked<'a, dyn World + 'a>, fallback_family: Option<&str>) -> Self {
|
fn new(
|
||||||
// Recover the non-lowercased version of the family because
|
world: Tracked<'a, dyn World + 'a>,
|
||||||
// usvg is case sensitive.
|
fallback_family: Option<EcoString>,
|
||||||
let book = world.book();
|
) -> Self {
|
||||||
let fallback_family_cased = fallback_family
|
Self { world, fallback_family, seen: Default::default() }
|
||||||
.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 into_prepared(self) -> PreparedLoader {
|
fn into_prepared(self) -> PreparedLoader {
|
||||||
PreparedLoader {
|
PreparedLoader {
|
||||||
families: self.seen.into_inner(),
|
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()
|
.clone()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn fallback(&self) -> Option<&str> {
|
fn fallback_family(&self) -> Option<&str> {
|
||||||
self.fallback_family_cased.as_deref()
|
self.fallback_family.as_deref()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -446,7 +446,7 @@ impl SvgFontLoader for WorldLoader<'_> {
|
|||||||
#[derive(Default, Hash)]
|
#[derive(Default, Hash)]
|
||||||
struct PreparedLoader {
|
struct PreparedLoader {
|
||||||
families: BTreeMap<EcoString, EcoVec<Font>>,
|
families: BTreeMap<EcoString, EcoVec<Font>>,
|
||||||
fallback_family_cased: Option<String>,
|
fallback_family: Option<EcoString>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl SvgFontLoader for PreparedLoader {
|
impl SvgFontLoader for PreparedLoader {
|
||||||
@ -454,8 +454,8 @@ impl SvgFontLoader for PreparedLoader {
|
|||||||
self.families.get(family).cloned().unwrap_or_default()
|
self.families.get(family).cloned().unwrap_or_default()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn fallback(&self) -> Option<&str> {
|
fn fallback_family(&self) -> Option<&str> {
|
||||||
self.fallback_family_cased.as_deref()
|
self.fallback_family.as_deref()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
BIN
tests/ref/bugs/new-cm-svg.png
Normal file
BIN
tests/ref/bugs/new-cm-svg.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 2.8 KiB |
2
tests/typ/bugs/new-cm-svg.typ
Normal file
2
tests/typ/bugs/new-cm-svg.typ
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
#set text(font: "New Computer Modern")
|
||||||
|
#image("/files/diagram.svg")
|
Loading…
x
Reference in New Issue
Block a user