Fix overlapping text and improve Arabic rendering in PDFs
Update PDF rendering logic to use fontkit for Arabic shaping and RTL reordering, eliminating pre-shaping and resolving text overlap issues. Replit-Commit-Author: Agent Replit-Commit-Session-Id: 77cfe984-2c65-4152-bb7a-0df28274fe66 Replit-Commit-Checkpoint-Type: full_checkpoint Replit-Commit-Event-Id: 32b8a89e-ae1f-4a09-ae50-3a53ae3f3477 Replit-Commit-Screenshot-Url: https://storage.googleapis.com/screenshot-production-us-central1/c3c252e4-c83d-40ca-9fff-99a3ea60701e/77cfe984-2c65-4152-bb7a-0df28274fe66/Ow4s0aa Replit-Helium-Checkpoint-Created: true
This commit is contained in:
@@ -1024,15 +1024,19 @@ test("PDF content: title label, rowColor tint, dropped isHighlighted, fontColor"
|
||||
void ascii;
|
||||
});
|
||||
|
||||
test("PDF Arabic shaping: title renders in connected presentation forms (not isolated)", async () => {
|
||||
test("PDF Arabic shaping: title renders in connected, correctly-ordered Arabic", async () => {
|
||||
// Regression for the bug where Arabic in the printed PDF appeared as
|
||||
// disconnected, visually-reversed letters (e.g. "الاجتماعات" →
|
||||
// "تاعامتجالا"). PDFKit has no built-in HarfBuzz, so we now run a
|
||||
// pre-shaping pass that converts base Arabic letters (U+0600..U+06FF)
|
||||
// to their contextual presentation forms (FE80..FEFF, plus FEFB
|
||||
// lam-alef ligature) BEFORE handing text to bidi + PDFKit. We assert
|
||||
// the rendered PDF contains presentation-form codepoints in its
|
||||
// embedded ToUnicode CMap (proves shaped glyphs were drawn).
|
||||
// disconnected, visually-reversed letters (e.g. "قائمة حضور" →
|
||||
// "ةمئاقروضح"). The renderer now hands RAW Unicode (logical order,
|
||||
// U+0600..06FF base letters) to PDFKit, which forwards it to fontkit
|
||||
// along with `features: ['rtla', 'rclt', 'calt', 'liga', ...]`.
|
||||
// Fontkit performs shaping AND visual right-to-left reorder at the
|
||||
// glyph layer, so the PDF content stream contains glyph IDs, not
|
||||
// characters. Per PDF 1.7 §9.10, every embedded TrueType font carries
|
||||
// a ToUnicode CMap that maps each emitted glyph back to its LOGICAL
|
||||
// base codepoint — that is what we assert here. (Pre-shaped output
|
||||
// would put U+FExx presentation-form codepoints in the CMap; the
|
||||
// current pipeline must NOT do that.)
|
||||
|
||||
// End-to-end: render a real PDF and assert the inflated streams
|
||||
// (which include the embedded ToUnicode CMap) reference at least one
|
||||
@@ -1081,13 +1085,25 @@ test("PDF Arabic shaping: title renders in connected presentation forms (not iso
|
||||
cursor = end + "\nendstream".length;
|
||||
}
|
||||
const allDecoded = decoded.join("\n");
|
||||
// Match any FE80..FEFF or FB50..FDFF hex literal — these are the
|
||||
// Arabic Presentation Forms ranges. Without shaping none would appear.
|
||||
const presFormsRegex = /<(?:FE[89A-F][0-9A-F]|FEF[0-9A-F]|FE[7][0-9A-F]|FB[5-9A-F][0-9A-F]|FC[0-9A-F]{2}|FD[0-9A-F]{2})>/i;
|
||||
// Assert (a) the embedded ToUnicode CMap references at least one base
|
||||
// Arabic codepoint (U+0600..06FF) — proves Arabic content was drawn
|
||||
// and survived round-tripping — and (b) the CMap does NOT reference
|
||||
// any Arabic Presentation Forms (FE70..FEFF / FB50..FDFF). The
|
||||
// presence of presentation-form codepoints in the CMap would mean
|
||||
// someone re-introduced the pre-shaping pass and the PDF would
|
||||
// render visually mirrored again.
|
||||
const baseArabicRegex = /<(?:06[0-9A-F]{2})>/i;
|
||||
assert.match(
|
||||
allDecoded,
|
||||
presFormsRegex,
|
||||
"rendered PDF must reference Arabic Presentation Forms codepoints (proves shaping ran before PDFKit)",
|
||||
baseArabicRegex,
|
||||
"rendered PDF must reference base Arabic codepoints in its ToUnicode CMap",
|
||||
);
|
||||
const presFormsRegex = /<(?:FE[789A-F][0-9A-F]|FB[5-9A-F][0-9A-F]|FC[0-9A-F]{2}|FD[0-9A-F]{2})>/i;
|
||||
const presMatch = allDecoded.match(presFormsRegex);
|
||||
assert.equal(
|
||||
presMatch,
|
||||
null,
|
||||
`rendered PDF must NOT reference Arabic Presentation Forms in its ToUnicode CMap — found ${presMatch?.[0]} (regression: pre-shaping has been re-introduced and the PDF will render visually mirrored)`,
|
||||
);
|
||||
});
|
||||
|
||||
|
||||
Reference in New Issue
Block a user