mirror of
https://github.com/storytold/designcraft.git
synced 2026-10-26 11:16:50 -06:00
Integration: #787 refuses bitmap-only fonts for embedding, and styles name the face's numeric weight
This commit is contained in:
@@ -156,7 +156,7 @@ fn embedded_fonts(d: &designcraft_doc::Document, warnings: &mut Vec<String>) ->
|
||||
let face = db.face(&family, &style);
|
||||
if !face.family.eq_ignore_ascii_case(&family) {
|
||||
warnings.push(format!("font `{family} {style}` is not available; not embedded"));
|
||||
} else if face.restricted_licence() {
|
||||
} else if face.restricted_licence() || face.bitmap_only() {
|
||||
warnings.push(format!("font `{family} {style}`: its licence doesn't allow embedding; not embedded"));
|
||||
} else if face.data().starts_with(b"ttcf") {
|
||||
warnings.push(format!("font `{family} {style}` is part of a font collection; not embedded"));
|
||||
@@ -811,6 +811,36 @@ mod text_tests {
|
||||
assert!(html.contains("\"Source Sans 3\", sans-serif;"));
|
||||
}
|
||||
|
||||
/// A font whose licence allows embedding bitmaps only (fsType bit 9) is not packaged whole,
|
||||
/// and a Semibold style asks for the Semibold face's weight, not Bold's.
|
||||
#[test]
|
||||
fn epub_embedding_follows_bitmap_only_licences_and_weights() {
|
||||
use designcraft_fonts::testing::{font_with, with_fs_type};
|
||||
const BITMAP: &str = "DocFont Epub Bitmap Only";
|
||||
for fs_type in [0x0200, 0x0208] {
|
||||
designcraft_fonts::FontDb::global()
|
||||
.add_font(with_fs_type(font_with(&format!("{BITMAP} {fs_type:04x}"), &['W']).unwrap(), fs_type).unwrap());
|
||||
}
|
||||
let mut s = Session::new();
|
||||
s.execute("file.new", &json!({"pages": 1})).unwrap();
|
||||
for fs_type in [0x0200, 0x0208] {
|
||||
let family = format!("{BITMAP} {fs_type:04x}");
|
||||
s.execute("style.paragraph.create", &json!({"name": family, "chars": {"fontFamily": family, "fontStyle": "Regular"}})).unwrap();
|
||||
}
|
||||
s.execute("style.paragraph.create", &json!({"name": "Semi", "chars": {"fontFamily": "Source Sans 3", "fontStyle": "Semibold"}})).unwrap();
|
||||
s.execute("frame.create", &json!({"rect": [72, 72, 400, 200], "content": "text", "text": "Words", "caret": false})).unwrap();
|
||||
let r = s.execute("file.exportEpub", &json!({"embedFonts": true})).unwrap();
|
||||
let mut z = unzip(r["base64"].as_str().unwrap());
|
||||
let css = read(&mut z, "OEBPS/style.css");
|
||||
assert!(!css.contains(&format!("@font-face {{ font-family: \"{BITMAP}")), "{css}");
|
||||
let warnings = r["warnings"].to_string();
|
||||
for fs_type in [0x0200, 0x0208] {
|
||||
assert!(warnings.contains(&format!("{BITMAP} {fs_type:04x} Regular`: its licence doesn't allow embedding")), "{warnings}");
|
||||
}
|
||||
let semi = css.lines().find(|l| l.contains(".semi {")).unwrap_or_default();
|
||||
assert!(semi.contains("font-weight: 600;"), "{css}");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn flattener_rasterises_spreads_with_transparency() {
|
||||
let mut s = Session::new();
|
||||
|
||||
@@ -349,15 +349,9 @@ fn hex(doc: &Document, swatch: &str, tint: f32) -> Option<String> {
|
||||
|
||||
fn char_css(doc: &Document, c: &CharProps, base_size: f64, generics: &BTreeMap<String, String>, out: &mut String) {
|
||||
let _ = write!(out, "font-family: \"{}\", {}; ", css_string(&c.font_family), generic_family(&c.font_family, generics));
|
||||
let st = c.font_style.to_lowercase();
|
||||
if st.contains("bold") {
|
||||
out.push_str("font-weight: bold; ");
|
||||
} else if st.contains("semibold") {
|
||||
out.push_str("font-weight: 600; ");
|
||||
}
|
||||
if st.contains("italic") {
|
||||
out.push_str("font-style: italic; ");
|
||||
}
|
||||
// The face's own weight, so an embedded Semibold or Light face is the one chosen.
|
||||
let (weight, style) = css_weight_style(&c.font_style);
|
||||
let _ = write!(out, "font-weight: {weight}; font-style: {style}; ");
|
||||
let _ = write!(out, "font-size: {:.3}em; ", c.size / base_size);
|
||||
if c.tracking != 0.0 {
|
||||
let _ = write!(out, "letter-spacing: {:.3}em; ", c.tracking / 1000.0);
|
||||
|
||||
@@ -358,6 +358,13 @@ impl FontFace {
|
||||
let fs_type = self.skrifa().and_then(|f| f.os2().ok()).map_or(0, |t| t.fs_type());
|
||||
fs_type & 0x0002 != 0 && fs_type & 0x000C == 0
|
||||
}
|
||||
|
||||
/// Does the font's licence allow embedding bitmaps only? OS/2 `fsType` bit 9: the outlines
|
||||
/// may not be passed on, so the font file can't be packaged whole.
|
||||
pub fn bitmap_only(&self) -> bool {
|
||||
use skrifa::raw::TableProvider;
|
||||
self.skrifa().and_then(|f| f.os2().ok()).is_some_and(|t| t.fs_type() & 0x0200 != 0)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
|
||||
Reference in New Issue
Block a user