From ef1fd68eb97bfb1b1827f972ee42e3f066595a4e Mon Sep 17 00:00:00 2001 From: "@permadeath.com" Date: Sun, 25 Oct 2026 11:33:31 -0400 Subject: [PATCH] fix(query): set Cyrillic, Greek and CJK on share cards Cards carry Inter's Cyrillic and Greek subsets and load Noto Sans CJK from the image, so those names and lines are no longer drawn as missing glyphs. Co-Authored-By: Claude Opus 5.5 Change-Id: I77d6a019874e7b52cbf1bd270df6a2a8a06e7e95 --- crates/vibescrobble-query/src/card.rs | 282 ++++++++++++++++++++++++-- docs/running-locally.md | 9 +- infra/files/vibescrobble.Dockerfile | 13 +- web/fonts/README.md | 8 +- web/fonts/inter-cyrillic-400.woff2 | Bin 0 -> 7712 bytes web/fonts/inter-cyrillic-700.woff2 | Bin 0 -> 7904 bytes web/fonts/inter-greek-400.woff2 | Bin 0 -> 7776 bytes web/fonts/inter-greek-700.woff2 | Bin 0 -> 7920 bytes 8 files changed, 287 insertions(+), 25 deletions(-) create mode 100644 web/fonts/inter-cyrillic-400.woff2 create mode 100644 web/fonts/inter-cyrillic-700.woff2 create mode 100644 web/fonts/inter-greek-400.woff2 create mode 100644 web/fonts/inter-greek-700.woff2 diff --git a/crates/vibescrobble-query/src/card.rs b/crates/vibescrobble-query/src/card.rs index 4199da03..1e3255ea 100644 --- a/crates/vibescrobble-query/src/card.rs +++ b/crates/vibescrobble-query/src/card.rs @@ -6,7 +6,10 @@ //! milliseconds rather than a Chrome. The faces are the page's own //! (`web/fonts/`), compiled in, so a card is set in what the board is set //! in. Emoji are drawn from the colour font `--emoji-font` names, Noto Color -//! Emoji in the image; without one, a card is drawn without its emoji. +//! Emoji in the image; without one, a card is drawn without its emoji. A +//! name or a line in Cyrillic or Greek is set in Inter's own, compiled in +//! too, and one in Chinese, Japanese or Korean in Noto Sans CJK from +//! [`CJK_FONTS`] where the machine has it. //! //! The look is the zine's (`web/plate.css`, `web/zine.css`): lavender riso //! stock under a dot screen, a paper bar with the wordmark over a ska @@ -43,6 +46,13 @@ pub const HEIGHT: u32 = 630; /// copies to the same place. pub const DEFAULT_EMOJI_FONT: &str = "/usr/share/fonts/truetype/noto/NotoColorEmoji.ttf"; +/// Where Debian's `fonts-noto-cjk` puts Noto Sans CJK, regular and bold, +/// which the image copies to the same place. +pub const CJK_FONTS: [&str; 2] = [ + "/usr/share/fonts/opentype/noto/NotoSansCJK-Regular.ttc", + "/usr/share/fonts/opentype/noto/NotoSansCJK-Bold.ttc", +]; + /// How many drawn cards are kept. A card is a few hundred kilobytes, so this /// is a few tens of megabytes at most. pub const CACHED: usize = 64; @@ -53,6 +63,14 @@ pub const DRAWING: usize = 2; const INTER: &[u8] = include_bytes!("../../../web/fonts/inter-latin-400.woff2"); const INTER_BOLD: &[u8] = include_bytes!("../../../web/fonts/inter-latin-700.woff2"); +/// Inter's Cyrillic and Greek, regular and bold, which set what the Latin +/// faces have no glyph for. +const INTER_MORE: [&[u8]; 4] = [ + include_bytes!("../../../web/fonts/inter-cyrillic-400.woff2"), + include_bytes!("../../../web/fonts/inter-cyrillic-700.woff2"), + include_bytes!("../../../web/fonts/inter-greek-400.woff2"), + include_bytes!("../../../web/fonts/inter-greek-700.woff2"), +]; const BAGEL: &[u8] = include_bytes!("../../../web/fonts/bagel-fat-one-latin-400.woff2"); const RIGHTEOUS: &[u8] = include_bytes!("../../../web/fonts/righteous-latin-400.woff2"); // The zine's other hands, for the swarm cards: the poster's display face, @@ -400,6 +418,10 @@ impl Faces { ] { db.load_font_data(face.clone()); } + // After the Latin faces, so a query for Inter finds those first. + for face in inter_more() { + db.load_font_data(face.clone()); + } db.set_sans_serif_family("Inter"); let emoji = match emoji_font { Some(path) => match db.load_font_file(path) { @@ -414,7 +436,19 @@ impl Faces { false } }; - info!(faces = db.len(), emoji, "loaded the faces cards are set in"); + // Mapped rather than read, so a face costs memory only for the + // glyphs a card draws from it. + let mut cjk = true; + for path in CJK_FONTS { + if let Err(err) = db.load_font_file(path) { + warn!(path, %err, "no CJK face; cards set Chinese, Japanese and Korean as missing glyphs"); + cjk = false; + } + } + info!( + faces = db.len(), + emoji, cjk, "loaded the faces cards are set in" + ); Self { db: Arc::new(db), inter, @@ -442,12 +476,8 @@ pub(crate) fn render_at( width: u32, height: u32, ) -> Result, String> { - let options = usvg::Options { - fontdb: faces.db.clone(), - font_family: "Inter".to_owned(), - ..usvg::Options::default() - }; - let tree = usvg::Tree::from_str(svg, &options).map_err(|err| format!("card SVG: {err}"))?; + let tree = + usvg::Tree::from_str(svg, &options(faces)).map_err(|err| format!("card SVG: {err}"))?; let mut pixmap = resvg::tiny_skia::Pixmap::new(width, height).ok_or("no canvas for a card")?; resvg::render( &tree, @@ -459,31 +489,120 @@ pub(crate) fn render_at( .map_err(|err| format!("card PNG: {err}")) } +/// How a card's SVG is read: in its faces, Inter where none is named. +fn options(faces: &Faces) -> usvg::Options<'static> { + usvg::Options { + fontdb: faces.db.clone(), + font_family: "Inter".to_owned(), + font_resolver: usvg::FontResolver { + select_fallback: Box::new(fallback), + ..usvg::FontResolver::default() + }, + ..usvg::Options::default() + } +} + +/// The face to set `ch` in when the face asked for has no glyph for it: the +/// first family that has one, in the weight asked for where that family +/// has it, so a bold name in Cyrillic is set in Inter's bold Cyrillic and +/// a bold one in Chinese in Noto Sans CJK's bold. +fn fallback(ch: char, used: &[fontdb::ID], db: &mut Arc) -> Option { + let weight = used + .first() + .and_then(|id| db.face(*id)) + .map(|face| face.weight); + let has = |face: &&fontdb::FaceInfo| { + !used.contains(&face.id) + && db.with_face_data(face.id, |data, index| { + skrifa::FontRef::from_index(data, index) + .is_ok_and(|font| font.charmap().map(ch).is_some()) + }) == Some(true) + }; + let first = db.faces().find(has)?; + let family = &first.families.first()?.0; + let weighted = db.faces().filter(has).find(|face| { + Some(face.weight) == weight && face.families.first().is_some_and(|f| &f.0 == family) + }); + Some(weighted.unwrap_or(first).id) +} + /// How wide `text` is set in `font` at `px`, near enough to wrap by. /// /// Advances only: no kerning and no shaping. A grapheme the face has no -/// glyph for — an emoji, a script outside its subset — is counted as a -/// square and a bit, which errs wide, so a line wrapped by this fits. +/// glyph for is measured in the face a card sets it in: Inter's Cyrillic +/// or Greek of the same weight, or Noto Sans CJK, which sets Han and kana +/// on one em and Hangul on a little less. Anything else, an emoji most +/// likely, is counted as a square and a bit. Both err wide, so a line +/// wrapped by this fits. pub(crate) fn width(font: &[u8], text: &str, px: f32) -> f32 { let Ok(face) = skrifa::FontRef::new(font) else { return text.graphemes(true).count() as f32 * px * 0.6; }; - let charmap = face.charmap(); - let metrics = face.glyph_metrics(Size::new(px), LocationRef::default()); + let bold = face.attributes().weight.value() >= 600.0; + let faces = std::iter::once(face).chain( + inter_more() + .iter() + .skip(usize::from(bold)) + .step_by(2) + .filter_map(|more| skrifa::FontRef::new(more).ok()), + ); + let measures: Vec<_> = faces + .map(|face| { + ( + face.charmap(), + face.glyph_metrics(Size::new(px), LocationRef::default()), + ) + }) + .collect(); text.graphemes(true) .map(|grapheme| { let mut chars = grapheme.chars(); match (chars.next(), chars.next()) { - (Some(ch), None) => charmap - .map(ch) - .and_then(|glyph| metrics.advance_width(glyph)) - .unwrap_or(px * 1.2), + (Some(ch), None) => measures + .iter() + .find_map(|(charmap, metrics)| { + charmap + .map(ch) + .and_then(|glyph| metrics.advance_width(glyph)) + }) + .unwrap_or(if wide(ch) { px } else { px * 1.2 }), _ => px * 1.2, } }) .sum() } +/// Whether `ch` is Han, kana, Hangul or a full-width form: what Noto Sans +/// CJK sets on one em at most. +fn wide(ch: char) -> bool { + matches!( + u32::from(ch), + 0x1100..=0x115F + | 0x2E80..=0x303E + | 0x3041..=0x33FF + | 0x3400..=0x4DBF + | 0x4E00..=0x9FFF + | 0xA960..=0xA97F + | 0xAC00..=0xD7A3 + | 0xF900..=0xFAFF + | 0xFE30..=0xFE4F + | 0xFF01..=0xFF60 + | 0xFFE0..=0xFFE6 + | 0x20000..=0x3FFFD + ) +} + +/// Inter's Cyrillic and Greek, regular then bold of each, decoded once. +fn inter_more() -> &'static [Vec] { + static MORE: OnceLock>> = OnceLock::new(); + MORE.get_or_init(|| { + INTER_MORE + .iter() + .map(|woff2| wuff::decompress_woff2(woff2).unwrap_or_default()) + .collect() + }) +} + /// Inter, regular and bold, decoded once without the rest of a card's /// faces. fn inter_faces() -> &'static (Vec, Vec) { @@ -969,6 +1088,137 @@ mod tests { ); } + /// Every glyph `svg` sets, with the family and weight of the face it + /// was set in. + fn set_in(svg: &str, faces: &Faces) -> Vec<(String, u16, String, String)> { + fn walk( + group: &usvg::Group, + db: &fontdb::Database, + out: &mut Vec<(String, u16, String, String)>, + ) { + for node in group.children() { + match node { + usvg::Node::Group(group) => walk(group, db, out), + usvg::Node::Text(text) => { + for glyph in text + .layouted() + .iter() + .flat_map(|span| &span.positioned_glyphs) + { + let face = db.face(glyph.font).expect("a face"); + let missing = if glyph.id.0 == 0 { "missing" } else { "" }; + out.push(( + face.families[0].0.clone(), + face.weight.0, + glyph.text.clone(), + missing.to_owned(), + )); + } + } + _ => {} + } + } + } + let tree = usvg::Tree::from_str(svg, &options(faces)).expect("it parses"); + let mut out = Vec::new(); + walk(tree.root(), tree.fontdb(), &mut out); + out + } + + /// A name in Cyrillic and Greek is set in Inter's own, bold as the + /// name is, and so is a line; a line with Chinese in it is set in Noto + /// Sans CJK where the machine has it, whole, since resvg sets a run in + /// one fallback face where that face has all of it. No glyph is the + /// missing one. + #[test] + fn a_card_sets_cyrillic_greek_and_chinese() { + let faces = Faces::load(None); + let card = Card { + did: "did:plc:zhizn6mbfqhzpldiwtoeyrxs".to_owned(), + name: "Жизнь Ωμέγα".to_owned(), + handle: Some("zhizn.example".to_owned()), + picture: None, + said: Some(Said { + emoji: "🪴".to_owned(), + text: "и всё ещё".to_owned(), + at: "2026-10-17T10:03:00Z".to_owned(), + by: None, + }), + }; + let drawn = svg(&card, None, &faces); + if let Some(dir) = std::env::var_os("CARD_OUT") { + let png = render(&drawn, &faces).expect("it draws"); + std::fs::write(PathBuf::from(dir).join("scripts.png"), &png).expect("written"); + } + let set = set_in(&drawn, &faces); + for letter in ["Ж", "з", "Ω", "έ"] { + let glyph = set + .iter() + .find(|(.., text, _)| text == letter) + .expect(letter); + assert_eq!( + (glyph.0.as_str(), glyph.1, glyph.3.as_str()), + ("Inter", 700, ""), + "{letter}" + ); + } + let glyph = set.iter().find(|(.., text, _)| text == "в").expect("в"); + assert_eq!( + (glyph.0.as_str(), glyph.1, glyph.3.as_str()), + ("Inter", 400, "") + ); + let chinese = Card { + said: Some(Said { + text: "测试中文 и всё: 正在检查卡片上的中文字体".to_owned(), + ..card.said.clone().expect("said") + }), + ..card + }; + let drawn = svg(&chinese, None, &faces); + if let Some(dir) = std::env::var_os("CARD_OUT") { + let png = render(&drawn, &faces).expect("it draws"); + std::fs::write(PathBuf::from(dir).join("scripts-cjk.png"), &png).expect("written"); + } + let set = set_in(&drawn, &faces); + if CJK_FONTS + .iter() + .all(|path| std::path::Path::new(path).is_file()) + { + for letter in ["测", "文"] { + let glyph = set + .iter() + .find(|(.., text, _)| text == letter) + .expect(letter); + assert!(glyph.0.starts_with("Noto Sans CJK"), "{glyph:?}"); + assert_eq!((glyph.1, glyph.3.as_str()), (400, ""), "{letter}"); + } + } + // Measured in the face that sets it, so a wrapped line fits. + let more = inter_more(); + assert_eq!( + width(&faces.inter_bold, "Жизнь", 54.0), + width(&more[1], "Жизнь", 54.0) + ); + assert_eq!( + width(&faces.inter, "Ωμέγα", 38.0), + width(&more[2], "Ωμέγα", 38.0) + ); + // Noto Sans CJK sets a Han or kana grapheme on one em, and Hangul + // on a little less, so counting it as one errs wide. + assert_eq!(width(&faces.inter, "测试한ア", 38.0), 4.0 * 38.0); + if let Ok(cjk) = std::fs::read(CJK_FONTS[0]) { + for (letter, em) in [('测', 1.0), ('ア', 1.0), ('、', 1.0), ('한', 0.92)] { + let face = skrifa::FontRef::from_index(&cjk, 0).expect("a face"); + let glyph = face.charmap().map(letter).expect("a glyph"); + let advance = face + .glyph_metrics(Size::new(38.0), LocationRef::default()) + .advance_width(glyph) + .expect("an advance"); + assert!((advance - 38.0 * em).abs() < 0.01, "{letter}: {advance}"); + } + } + } + #[test] fn a_long_line_wraps_and_is_cut_at_its_last() { let faces = Faces::load(None); diff --git a/docs/running-locally.md b/docs/running-locally.md index 5279779c..955d1d7d 100644 --- a/docs/running-locally.md +++ b/docs/running-locally.md @@ -404,9 +404,12 @@ cards are sent with `Cache-Control: public, max-age=300`, and a 404 with `no-cache`. Cards are SVG rasterised in-process by resvg, in the page's own faces from -`web/fonts/`, which the binary carries. Emoji come from the colour font -`--emoji-font` names (Debian's `fonts-noto-color-emoji` by default, which the -image installs); without one a card is drawn without its emoji. Two are drawn +`web/fonts/`, which the binary carries, Inter's Cyrillic and Greek among +them. Emoji come from the colour font `--emoji-font` names (Debian's +`fonts-noto-color-emoji` by default, which the image installs); without one a +card is drawn without its emoji. Chinese, Japanese and Korean are set in Noto +Sans CJK from Debian's `fonts-noto-cjk` paths, which the image carries the +sans faces of; without them those glyphs are drawn missing. Two are drawn at a time and the last 64 are held. `--public-url` sets the origin the tags' absolute URLs are written against; without it, the request's `Host` is used. The pages' styles are `web/share.css`, which Caddy serves beside the canvas. diff --git a/infra/files/vibescrobble.Dockerfile b/infra/files/vibescrobble.Dockerfile index ea6b0bfd..4c906e5f 100644 --- a/infra/files/vibescrobble.Dockerfile +++ b/infra/files/vibescrobble.Dockerfile @@ -89,12 +89,12 @@ RUN base="https://huggingface.co/${MODEL_REPO}/resolve/${MODEL_REVISION}" && \ done # What the runtime stage needs from a package manager and a shell: the CA -# bundle, an account for the user the services run as, and the colour emoji -# font a share card's emoji are drawn from. None holds anything -# per-architecture, so they are made natively, from the same base, and -# copied across. +# bundle, an account for the user the services run as, the colour emoji +# font a share card's emoji are drawn from, and the CJK faces its Chinese, +# Japanese and Korean are set in. None holds anything per-architecture, so +# they are made natively, from the same base, and copied across. FROM --platform=$BUILDPLATFORM debian:bookworm-slim@sha256:3783cc01769c7b2b1b83a5c5ad96c815348e28ed7da68e2e3687004faa906251 AS system -RUN apt-get update && apt-get install -y --no-install-recommends ca-certificates fonts-noto-color-emoji && \ +RUN apt-get update && apt-get install -y --no-install-recommends ca-certificates fonts-noto-color-emoji fonts-noto-cjk && \ rm -rf /var/lib/apt/lists/* && \ useradd --system --uid 65532 vibescrobble && mkdir -p /data @@ -106,6 +106,9 @@ COPY --from=system /etc/ssl/certs /etc/ssl/certs COPY --from=system /usr/share/ca-certificates /usr/share/ca-certificates # Where vibescrobble-query's `--emoji-font` looks unless told otherwise. COPY --from=system /usr/share/fonts/truetype/noto/NotoColorEmoji.ttf /usr/share/fonts/truetype/noto/NotoColorEmoji.ttf +# Where it looks for Noto Sans CJK, regular and bold: the sans only, since +# the package's serif faces are half its weight and nothing sets them. +COPY --from=system /usr/share/fonts/opentype/noto/NotoSansCJK-Regular.ttc /usr/share/fonts/opentype/noto/NotoSansCJK-Bold.ttc /usr/share/fonts/opentype/noto/ COPY --from=build /out/vibescrobble-index /out/vibescrobble-query /usr/local/bin/ # `--model` takes a directory as readily as a Hugging Face id, and a directory # is what this is: no network, no cache layout, no revision to resolve. diff --git a/web/fonts/README.md b/web/fonts/README.md index 6ef89627..36cfdaa2 100644 --- a/web/fonts/README.md +++ b/web/fonts/README.md @@ -11,6 +11,10 @@ same faces. | `inter-latin-400.woff2` | Inter | 400 | SIL OFL 1.1, `OFL-Inter.txt` | Fontsource `@fontsource/inter`, latin subset | | `inter-latin-600.woff2` | Inter | 600 | SIL OFL 1.1, `OFL-Inter.txt` | Fontsource `@fontsource/inter`, latin subset | | `inter-latin-700.woff2` | Inter | 700 | SIL OFL 1.1, `OFL-Inter.txt` | Fontsource `@fontsource/inter`, latin subset | +| `inter-cyrillic-400.woff2` | Inter | 400 | SIL OFL 1.1, `OFL-Inter.txt` | Fontsource `@fontsource/inter` 5.3.0, cyrillic subset | +| `inter-cyrillic-700.woff2` | Inter | 700 | SIL OFL 1.1, `OFL-Inter.txt` | Fontsource `@fontsource/inter` 5.3.0, cyrillic subset | +| `inter-greek-400.woff2` | Inter | 400 | SIL OFL 1.1, `OFL-Inter.txt` | Fontsource `@fontsource/inter` 5.3.0, greek subset | +| `inter-greek-700.woff2` | Inter | 700 | SIL OFL 1.1, `OFL-Inter.txt` | Fontsource `@fontsource/inter` 5.3.0, greek subset | | `bagel-fat-one-latin-400.woff2` | Bagel Fat One | 400 | SIL OFL 1.1, `OFL-BagelFatOne.txt` | Fontsource `@fontsource/bagel-fat-one`, latin subset | | `righteous-latin-400.woff2` | Righteous | 400 | SIL OFL 1.1, `OFL-Righteous.txt` | Fontsource `@fontsource/righteous`, latin subset | | `caveat-brush-latin-400.woff2` | Caveat Brush | 400 | SIL OFL 1.1, `OFL-CaveatBrush.txt` | Fontsource `@fontsource/caveat-brush`, latin subset | @@ -18,7 +22,9 @@ same faces. | `bowlby-one-sc-latin-400.woff2` | Bowlby One SC | 400 | SIL OFL 1.1, `OFL-BowlbyOneSC.txt` | Fontsource `@fontsource/bowlby-one-sc`, latin subset | | `reenie-beanie-latin-400.woff2` | Reenie Beanie | 400 | SIL OFL 1.1, `OFL-ReenieBeanie.txt` | Fontsource `@fontsource/reenie-beanie`, latin subset | -Inter is for anything that is read. Bagel Fat One is for headings, and +Inter is for anything that is read. Its Cyrillic and Greek subsets are for +the share cards only, which have no system faces to fall back to; no page +declares them. Bagel Fat One is for headings, and `web/wordmark.svg` is drawn from it by `web/dev/wordmark.mjs`. Righteous sets the caption boxes and the readings' names; Caveat Brush the scrawled marker; and with Courier Prime and Bowlby One SC they are the scraps `web/zine.js` diff --git a/web/fonts/inter-cyrillic-400.woff2 b/web/fonts/inter-cyrillic-400.woff2 new file mode 100644 index 0000000000000000000000000000000000000000..e7583fca2f891e8f3ad0b714b2225be51ff1abf4 GIT binary patch literal 7712 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 literal 0 HcmV?d00001 diff --git a/web/fonts/inter-greek-400.woff2 b/web/fonts/inter-greek-400.woff2 new file mode 100644 index 0000000000000000000000000000000000000000..e7103fb5d82ee7b79263e028974a0fbb5c1f1e4c GIT binary patch literal 7776 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 M`~Cewv-ubp04?^+K>z>% literal 0 HcmV?d00001 diff --git a/web/fonts/inter-greek-700.woff2 b/web/fonts/inter-greek-700.woff2 new file mode 100644 index 0000000000000000000000000000000000000000..3a9fc0b9ba4ec20c1599ce319c590fd8408e76b5 GIT binary patch literal 7920 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 PUh{MR{nABY3=9kaNPj2a literal 0 HcmV?d00001 -- knotmirror 0.0.1