Skip to content

Commit aa6c3b1

Browse files
committed
Small style fixes2
1 parent 935da38 commit aa6c3b1

1 file changed

Lines changed: 26 additions & 7 deletions

File tree

pubstash/server.ts

Lines changed: 26 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -120,13 +120,6 @@ async function convertHtmlToPdf(html: string): Promise<Buffer> {
120120
// Load the HTML
121121
await page.setContent(html, { waitUntil: 'load', timeout: PAGE_TIMEOUT_MS });
122122

123-
// Chromium 146 renders characters like ↩ (U+21A9) as color emoji by
124-
// default. Force text presentation so they stay as simple glyphs —
125-
// important for academic reference back-links.
126-
await page.addStyleTag({
127-
content: `*, *::before, *::after { font-variant-emoji: text; }`,
128-
});
129-
130123
// Wait for all web fonts before paged.js measures text.
131124
// (Key fix from the pubpub/pagedjs-cli fork.)
132125
await page.evaluate(() => document.fonts.ready);
@@ -206,6 +199,32 @@ async function convertHtmlToPdf(html: string): Promise<Buffer> {
206199
() => new Promise((r) => requestAnimationFrame(() => requestAnimationFrame(r))),
207200
);
208201

202+
// Chromium 146+ renders certain Unicode characters (e.g. ↩ U+21A9 in
203+
// footnote back-links) as color emoji instead of simple text glyphs.
204+
// Fix at the Unicode level by appending U+FE0E (Variation Selector 15 =
205+
// "text presentation") to every affected character in text nodes.
206+
// This is more reliable than CSS font-variant-emoji because page.pdf()
207+
// uses Chromium's internal print path which may ignore that property.
208+
await page.evaluate(() => {
209+
const VS15 = '\uFE0E';
210+
// Characters with dual text/emoji presentation that commonly appear
211+
// in academic documents and should remain as simple text glyphs.
212+
const EMOJI_CAPABLE =
213+
/[\u2139\u21A9\u21AA\u2194-\u2199\u23CF\u23ED-\u23EF\u23F1\u23F2\u25AA\u25AB\u25B6\u25C0\u25FB-\u25FE\u2600-\u27BF\u2934\u2935\u2B05-\u2B07\u2B1B\u2B1C\u2B50\u2B55\u3030\u303D]/;
214+
const walker = document.createTreeWalker(document.body, NodeFilter.SHOW_TEXT);
215+
let node: Text | null;
216+
while ((node = walker.nextNode() as Text | null)) {
217+
const text = node.nodeValue;
218+
if (text && EMOJI_CAPABLE.test(text)) {
219+
// Append VS15 after each matching char (skip if already followed by VS15)
220+
node.nodeValue = text.replace(
221+
/([\u2139\u21A9\u21AA\u2194-\u2199\u23CF\u23ED-\u23EF\u23F1\u23F2\u25AA\u25AB\u25B6\u25C0\u25FB-\u25FE\u2600-\u27BF\u2934\u2935\u2B05-\u2B07\u2B1B\u2B1C\u2B50\u2B55\u3030\u303D])(?!\uFE0E)/g,
222+
`$1${VS15}`,
223+
);
224+
}
225+
}
226+
});
227+
209228
// Extract <meta> tags for PDF metadata
210229
const meta: PdfMeta = await page.evaluate(() => {
211230
const m: Record<string, string> = {};

0 commit comments

Comments
 (0)