mirror of
https://github.com/storytold/designcraft.git
synced 2026-11-14 14:22:39 +00:00
PPTX export: bound the retained glyph-to-character maps
* PPTX export: keep only the last four faces' glyph-to-character maps
This commit is contained in:
1 parent
6fff5328eb
commit
f87c24a1cd
1 file changed
+31
@@ -15,6 +15,9 @@ pub struct RunFont {
|
||||
pub italic: bool,
|
||||
}
|
||||
|
||||
/// Faces whose glyph-to-character map is kept at once.
|
||||
const MAX_REVERSE_MAPS: usize = 4;
|
||||
|
||||
#[derive(Default)]
|
||||
pub struct Fonts {
|
||||
names: HashMap<u32, RunFont>,
|
||||
@@ -116,6 +119,11 @@ impl Fonts {
|
||||
|
||||
/// The character a glyph shows (the lowest code point mapping to it).
|
||||
pub fn char_of(&mut self, face: &FontFace, gid: u32) -> Option<char> {
|
||||
// A face's reverse map can hold over a million entries; keeping one per face a bundle uses
|
||||
// is unbounded, so only the last few stay (a rebuilt map answers the same).
|
||||
if !self.reverse.contains_key(&face.id()) && self.reverse.len() >= MAX_REVERSE_MAPS {
|
||||
self.reverse.clear();
|
||||
}
|
||||
let map = self.reverse.entry(face.id()).or_insert_with(|| {
|
||||
let mut m = HashMap::new();
|
||||
for (c, g) in face.chars() {
|
||||
@@ -216,3 +224,26 @@ pub fn eot(face: &FontFace) -> Result<Vec<u8>, NoEmbed> {
|
||||
h.extend_from_slice(data);
|
||||
Ok(h)
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn only_a_few_reverse_maps_are_kept_and_answers_do_not_change() {
|
||||
let db = designcraft_fonts::FontDb::global();
|
||||
let mut fonts = Fonts::default();
|
||||
let mut last = None;
|
||||
for style in ["Regular", "Bold", "Italic", "Bold Italic", "Semibold", "Light", "Black", "ExtraLight", "Medium", "SemiBold Italic"] {
|
||||
let face = db.face("Source Serif 4", style);
|
||||
let gid = face.glyph_for('A');
|
||||
assert_eq!(fonts.char_of(&face, gid), Some('A'), "{style}");
|
||||
assert!(fonts.reverse.len() <= MAX_REVERSE_MAPS);
|
||||
last = Some((face, gid));
|
||||
}
|
||||
// The map evicted earlier is rebuilt on demand with the same answer.
|
||||
if let Some((face, gid)) = last {
|
||||
assert_eq!(fonts.char_of(&face, gid), Some('A'));
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user