mirror of
https://github.com/storytold/vectorcraft.git
synced 2026-11-11 00:12:24 +00:00
Merge pull request #6326 from JonRC/fix/eps-missing-fonts-warning
Fix #6320: EPS import warns about fonts that aren't available
This commit is contained in:
@@ -98,6 +98,10 @@ const LETTER: [f64; 4] = [0.0, 0.0, 612.0, 792.0];
|
||||
/// Largest page side read (points).
|
||||
const MAX_SIDE: f64 = 1e5;
|
||||
|
||||
/// The start of the warning that type was set in fonts that aren't available, before ": " and
|
||||
/// their families: PDF import's words, as type in those fonts comes in the same way.
|
||||
pub(crate) const MISSING_FONTS_NOTE: &str = "fonts that aren't available show in the fallback font until they are";
|
||||
|
||||
/// A read file.
|
||||
#[derive(Debug)]
|
||||
pub struct Imported {
|
||||
@@ -364,6 +368,9 @@ fn finish_with(out: Out, layers: Vec<Arc<Node>>) -> Imported {
|
||||
}
|
||||
doc.layers = layers;
|
||||
let mut warnings = out.warnings;
|
||||
if !out.missing_fonts.is_empty() {
|
||||
warnings.push(format!("{MISSING_FONTS_NOTE}: {}", out.missing_fonts.join(", ")));
|
||||
}
|
||||
doc.limit_depth_noting(&mut warnings);
|
||||
Imported { document: doc, warnings, preview: false }
|
||||
}
|
||||
|
||||
@@ -115,6 +115,9 @@ impl Default for GState {
|
||||
}
|
||||
}
|
||||
|
||||
/// Most families listed in the warning about fonts that aren't available.
|
||||
const MAX_MISSING_FONTS: usize = 64;
|
||||
|
||||
/// What the program draws.
|
||||
pub(crate) struct Out {
|
||||
/// The document being made: ids, images and swatches.
|
||||
@@ -152,6 +155,9 @@ pub(crate) struct Out {
|
||||
pub(super) tilings: HashMap<u64, Vec<Tiling>>,
|
||||
/// How deep art drawn apart (a pattern's cell, a Type 3 glyph) is nested.
|
||||
pub apart: u32,
|
||||
/// The families type was set in that aren't available (it shows in the fallback font), each
|
||||
/// once in the order first set, for the import's warning.
|
||||
pub missing_fonts: Vec<String>,
|
||||
}
|
||||
|
||||
fn sane(r: Rect) -> bool {
|
||||
@@ -201,6 +207,14 @@ impl Out {
|
||||
shadings: HashSet::new(),
|
||||
tilings: HashMap::new(),
|
||||
apart: 0,
|
||||
missing_fonts: vec![],
|
||||
}
|
||||
}
|
||||
|
||||
/// Note that type was set in `family`, which isn't available (at most [`MAX_MISSING_FONTS`]).
|
||||
pub fn missing_font(&mut self, family: &str) {
|
||||
if !family.is_empty() && self.missing_fonts.len() < MAX_MISSING_FONTS && !self.missing_fonts.iter().any(|f| f == family) {
|
||||
self.missing_fonts.push(family.to_string());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -737,7 +737,7 @@ fn embedded_font_programs_are_skipped() {
|
||||
let r = read(&program);
|
||||
let NodeKind::Text(t) = &objects(&r.document)[0].kind else { panic!("{program}: {:?}", r.warnings) };
|
||||
assert_eq!(t.runs[0].style.font_family, "My Font");
|
||||
assert!(r.warnings.is_empty(), "{program}: {:?}", r.warnings);
|
||||
assert!(program_warnings(&r.warnings).is_empty(), "{program}: {:?}", r.warnings);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -833,12 +833,18 @@ fn device_settings_are_accepted_and_change_nothing() {
|
||||
}
|
||||
|
||||
/// Check that `body` draws one square, blue: it sets blue when what it checks holds, else red.
|
||||
/// `warnings` without the note naming fonts that aren't available: which those are depends on the
|
||||
/// fonts installed where the tests run, not on the program.
|
||||
pub(super) fn program_warnings(warnings: &[String]) -> Vec<&String> {
|
||||
warnings.iter().filter(|w| !w.starts_with(super::MISSING_FONTS_NOTE)).collect()
|
||||
}
|
||||
|
||||
fn blue(body: &str) {
|
||||
let r = read(&format!("{body} 10 10 80 80 rectfill"));
|
||||
let o = objects(&r.document);
|
||||
assert_eq!(o.len(), 1, "{body}: {:?}", r.warnings);
|
||||
assert_eq!(fill(&o[0]), Some(&Paint::solid(Color::rgb(0.0, 0.0, 1.0))), "{body}");
|
||||
assert!(r.warnings.is_empty(), "{body}: {:?}", r.warnings);
|
||||
assert!(program_warnings(&r.warnings).is_empty(), "{body}: {:?}", r.warnings);
|
||||
}
|
||||
|
||||
/// Check that PostScript `cond` leaves `true`.
|
||||
|
||||
@@ -392,7 +392,7 @@ fn named_cidfonts_over_unicode_cmaps_set_their_characters_as_type() {
|
||||
.collect()
|
||||
};
|
||||
let r = super::tests::read("/Ryumin-Light-UniJIS-UCS2-H findfont 20 scalefont setfont 10 20 moveto <4e2d0041> show");
|
||||
assert!(r.warnings.is_empty(), "{:?}", r.warnings);
|
||||
assert!(super::tests::program_warnings(&r.warnings).is_empty(), "{:?}", r.warnings);
|
||||
let t = texts(&r);
|
||||
assert_eq!(t.len(), 1, "{:?}", all(&r.document));
|
||||
assert_eq!(t[0].plain_text(), "\u{4e2d}A");
|
||||
|
||||
@@ -215,7 +215,7 @@ fn text_and_its_strokes_come_from_the_page_into_the_layer_of_its_text_object() {
|
||||
assert_eq!(kinds(&r.document.layers[0]), ["path"]);
|
||||
// The text and the path of its stroke, where the text object is (no group of their own).
|
||||
assert_eq!(kinds(&r.document.layers[1]), ["text", "path"], "{:?}", r.warnings);
|
||||
assert!(r.warnings.is_empty(), "{:?}", r.warnings);
|
||||
assert!(super::tests::program_warnings(&r.warnings).is_empty(), "{:?}", r.warnings);
|
||||
}
|
||||
|
||||
/// A point type object in the legacy format (`To` … `TO`), as an EPS saved for Illustrator 10
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
|
||||
use vectorcraft_doc::{NodeKind, TextObject};
|
||||
|
||||
use super::tests::{all, bounds, check, read};
|
||||
use super::tests::{all, bounds, check, program_warnings, read};
|
||||
use crate::import::import;
|
||||
|
||||
/// A Type 1 charstring number (§6.2).
|
||||
@@ -115,7 +115,7 @@ fn program(encoding: &str, hex: bool, body: &str) -> crate::Imported {
|
||||
fn embedded_type1_type_keeps_the_fonts_widths() {
|
||||
for hex in [true, false] {
|
||||
let r = program(OWN, hex, "/TestOne findfont 50 scalefont setfont 10 20 moveto (AB) show");
|
||||
assert!(r.warnings.is_empty(), "{:?}", r.warnings);
|
||||
assert!(program_warnings(&r.warnings).is_empty(), "{:?}", r.warnings);
|
||||
let t = texts(&r);
|
||||
assert_eq!(t.len(), 1, "{:?}", all(&r.document));
|
||||
assert_eq!(t[0].plain_text(), "AB");
|
||||
@@ -126,6 +126,22 @@ fn embedded_type1_type_keeps_the_fonts_widths() {
|
||||
}
|
||||
}
|
||||
|
||||
/// Type in an embedded font whose family isn't available keeps the font's name and shows in the
|
||||
/// fallback font, and the import says so as PDF import does: each such family once, in the order
|
||||
/// its type comes. A family that is available isn't named.
|
||||
#[test]
|
||||
fn type_in_fonts_that_arent_available_is_named_in_a_warning() {
|
||||
let r = program(
|
||||
OWN,
|
||||
false,
|
||||
"/TestOne findfont 50 scalefont setfont 10 20 moveto (AB) show 10 60 moveto (BA) show \
|
||||
/Nowhere-Bold 12 selectfont 10 80 moveto (x) show /Inter-Regular 12 selectfont 10 90 moveto (y) show",
|
||||
);
|
||||
assert_eq!(texts(&r).iter().map(|t| t.runs[0].style.font_family.as_str()).collect::<Vec<_>>(), ["Test One", "Test One", "Nowhere", "Inter"]);
|
||||
// PDF import's words.
|
||||
assert_eq!(r.warnings, ["fonts that aren't available show in the fallback font until they are: Test One, Nowhere"]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn embedded_type1_fonts_measure_and_outline_their_glyphs() {
|
||||
let fonts = String::from_utf8(font(OWN, true)).unwrap();
|
||||
|
||||
@@ -489,7 +489,14 @@ impl Interp<'_> {
|
||||
}
|
||||
let (family, font_style) = family_style(&name);
|
||||
// The available family's own spelling: `MicrosoftYaHei` is Microsoft YaHei, not "Microsoft Ya Hei".
|
||||
let font_family = vectorcraft_text::FontDb::global().find_family(&family).unwrap_or(family);
|
||||
// A family that isn't available keeps its name and shows in the fallback font.
|
||||
let font_family = match vectorcraft_text::FontDb::global().find_family(&family) {
|
||||
Some(f) => f,
|
||||
None => {
|
||||
self.out.missing_font(&family);
|
||||
family
|
||||
}
|
||||
};
|
||||
let fill = if self.g.paint.is_none() { Paint::solid(vectorcraft_color::Color::BLACK) } else { self.g.paint.clone() };
|
||||
let style = CharStyle { font_family, font_style, size, fill, stroke: Paint::None, ..CharStyle::default() };
|
||||
let mut t = TextObject::point(Point::ZERO, text, style);
|
||||
|
||||
Reference in New Issue
Block a user