Make rendering of svg that has text work out of the box (#2560)
* fix: load system fonts to usvg font_db, this will make rendering of text in svg that has it * feat: add an example that renders svg that has text on it * Initialize `fontdb` only once for `vector` images * Remove `svg_text` example * Set `fontdb` for `usvg::Options` in `tiny_skia::vector` --------- Co-authored-by: Héctor Ramón Jiménez <hector@hecrj.dev>
This commit is contained in:
parent
e0da42efed
commit
0c502801e3
2 changed files with 42 additions and 19 deletions
|
|
@ -8,6 +8,7 @@ use tiny_skia::Transform;
|
||||||
use std::cell::RefCell;
|
use std::cell::RefCell;
|
||||||
use std::collections::hash_map;
|
use std::collections::hash_map;
|
||||||
use std::fs;
|
use std::fs;
|
||||||
|
use std::sync::Arc;
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct Pipeline {
|
pub struct Pipeline {
|
||||||
|
|
@ -68,6 +69,7 @@ struct Cache {
|
||||||
tree_hits: FxHashSet<u64>,
|
tree_hits: FxHashSet<u64>,
|
||||||
rasters: FxHashMap<RasterKey, tiny_skia::Pixmap>,
|
rasters: FxHashMap<RasterKey, tiny_skia::Pixmap>,
|
||||||
raster_hits: FxHashSet<RasterKey>,
|
raster_hits: FxHashSet<RasterKey>,
|
||||||
|
fontdb: Option<Arc<usvg::fontdb::Database>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
|
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
|
||||||
|
|
@ -81,23 +83,32 @@ impl Cache {
|
||||||
fn load(&mut self, handle: &Handle) -> Option<&usvg::Tree> {
|
fn load(&mut self, handle: &Handle) -> Option<&usvg::Tree> {
|
||||||
let id = handle.id();
|
let id = handle.id();
|
||||||
|
|
||||||
|
// TODO: Reuse `cosmic-text` font database
|
||||||
|
if self.fontdb.is_none() {
|
||||||
|
let mut fontdb = usvg::fontdb::Database::new();
|
||||||
|
fontdb.load_system_fonts();
|
||||||
|
|
||||||
|
self.fontdb = Some(Arc::new(fontdb));
|
||||||
|
}
|
||||||
|
|
||||||
|
let options = usvg::Options {
|
||||||
|
fontdb: self
|
||||||
|
.fontdb
|
||||||
|
.as_ref()
|
||||||
|
.expect("fontdb must be initialized")
|
||||||
|
.clone(),
|
||||||
|
..usvg::Options::default()
|
||||||
|
};
|
||||||
|
|
||||||
if let hash_map::Entry::Vacant(entry) = self.trees.entry(id) {
|
if let hash_map::Entry::Vacant(entry) = self.trees.entry(id) {
|
||||||
let svg = match handle.data() {
|
let svg = match handle.data() {
|
||||||
Data::Path(path) => {
|
Data::Path(path) => {
|
||||||
fs::read_to_string(path).ok().and_then(|contents| {
|
fs::read_to_string(path).ok().and_then(|contents| {
|
||||||
usvg::Tree::from_str(
|
usvg::Tree::from_str(&contents, &options).ok()
|
||||||
&contents,
|
|
||||||
&usvg::Options::default(), // TODO: Set usvg::Options::fontdb
|
|
||||||
)
|
|
||||||
.ok()
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
Data::Bytes(bytes) => {
|
Data::Bytes(bytes) => {
|
||||||
usvg::Tree::from_data(
|
usvg::Tree::from_data(bytes, &options).ok()
|
||||||
bytes,
|
|
||||||
&usvg::Options::default(), // TODO: Set usvg::Options::fontdb
|
|
||||||
)
|
|
||||||
.ok()
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -6,6 +6,7 @@ use resvg::tiny_skia;
|
||||||
use resvg::usvg;
|
use resvg::usvg;
|
||||||
use rustc_hash::{FxHashMap, FxHashSet};
|
use rustc_hash::{FxHashMap, FxHashSet};
|
||||||
use std::fs;
|
use std::fs;
|
||||||
|
use std::sync::Arc;
|
||||||
|
|
||||||
/// Entry in cache corresponding to an svg handle
|
/// Entry in cache corresponding to an svg handle
|
||||||
pub enum Svg {
|
pub enum Svg {
|
||||||
|
|
@ -37,6 +38,7 @@ pub struct Cache {
|
||||||
svg_hits: FxHashSet<u64>,
|
svg_hits: FxHashSet<u64>,
|
||||||
rasterized_hits: FxHashSet<(u64, u32, u32, ColorFilter)>,
|
rasterized_hits: FxHashSet<(u64, u32, u32, ColorFilter)>,
|
||||||
should_trim: bool,
|
should_trim: bool,
|
||||||
|
fontdb: Option<Arc<usvg::fontdb::Database>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
type ColorFilter = Option<[u8; 4]>;
|
type ColorFilter = Option<[u8; 4]>;
|
||||||
|
|
@ -48,23 +50,33 @@ impl Cache {
|
||||||
return self.svgs.get(&handle.id()).unwrap();
|
return self.svgs.get(&handle.id()).unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO: Reuse `cosmic-text` font database
|
||||||
|
if self.fontdb.is_none() {
|
||||||
|
let mut fontdb = usvg::fontdb::Database::new();
|
||||||
|
fontdb.load_system_fonts();
|
||||||
|
|
||||||
|
self.fontdb = Some(Arc::new(fontdb));
|
||||||
|
}
|
||||||
|
|
||||||
|
let options = usvg::Options {
|
||||||
|
fontdb: self
|
||||||
|
.fontdb
|
||||||
|
.as_ref()
|
||||||
|
.expect("fontdb must be initialized")
|
||||||
|
.clone(),
|
||||||
|
..usvg::Options::default()
|
||||||
|
};
|
||||||
|
|
||||||
let svg = match handle.data() {
|
let svg = match handle.data() {
|
||||||
svg::Data::Path(path) => fs::read_to_string(path)
|
svg::Data::Path(path) => fs::read_to_string(path)
|
||||||
.ok()
|
.ok()
|
||||||
.and_then(|contents| {
|
.and_then(|contents| {
|
||||||
usvg::Tree::from_str(
|
usvg::Tree::from_str(&contents, &options).ok()
|
||||||
&contents,
|
|
||||||
&usvg::Options::default(), // TODO: Set usvg::Options::fontdb
|
|
||||||
)
|
|
||||||
.ok()
|
|
||||||
})
|
})
|
||||||
.map(Svg::Loaded)
|
.map(Svg::Loaded)
|
||||||
.unwrap_or(Svg::NotFound),
|
.unwrap_or(Svg::NotFound),
|
||||||
svg::Data::Bytes(bytes) => {
|
svg::Data::Bytes(bytes) => {
|
||||||
match usvg::Tree::from_data(
|
match usvg::Tree::from_data(bytes, &options) {
|
||||||
bytes,
|
|
||||||
&usvg::Options::default(), // TODO: Set usvg::Options::fontdb
|
|
||||||
) {
|
|
||||||
Ok(tree) => Svg::Loaded(tree),
|
Ok(tree) => Svg::Loaded(tree),
|
||||||
Err(_) => Svg::NotFound,
|
Err(_) => Svg::NotFound,
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue